You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Refactor optional dependencies flags into utils module #4630
This idiom gets repeated in many other places for other optional dependencies. Might it make sense to refactor all these into a single module (perhaps opt_deps.py) in utils? Then application code would be:
That would also make is easier to find and change if the optional dependency changes, is removed (e.g. we decide in the future that scipy becomes a hard dependency).
@astrofrog - is this @requires_X mapped to pytest.mark.skipif so pytest is doing the right thing? It seems like @requires could take an argument of one or more optional deps, e.g. @test_requires('pathlib', 'scipy', 'beautifulsoup'). I think it makes sense to have test in the decorator name if it is specifically targeted at tests.
pathlib is now provided by the minversion of Python that we support, so that if ... else ... can be taken out altogether. For testing, pytest has importorskip, so can this issue be closed?
I started working on this and then realized that we cannot really lazy import until minversion of Python is 3.7. I think something like this might work based on PEP 562, otherwise we either over-engineer or incur a penalty of checking for everything at import time.
Lazy import is important because some of these HAS_* checks occur inside real modules, not just tests.
I called this file astropy/utils/compat/optional_deps.py but nothing is set in stone yet:
# Licensed under a 3-clause BSD style license - see LICENSE.rst"""Checks for optional dependencies using lazy import from`PEP 562 <https://www.python.org/dev/peps/pep-0562/>`_."""importimportlib__all__= [ # noqa'HAS_BS4', 'HAS_BLEACH', 'HAS_HTML5LIB', 'HAS_JPLEPHEM', 'HAS_LXML',
'HAS_PANDAS', 'HAS_PIL', 'HAS_SCIPY', 'HAS_SKYFIELD', 'HAS_YAML']
def__getattr__(name):
ifnamein__all__:
module_name=name.split('_')[1]
ifmodule_namenotin ('PIL', ):
module_name=module_name.lower()
try:
importlib.import_module(module_name)
except (ImportError, ModuleNotFoundError):
returnFalsereturnTrueraiseAttributeError(f"module {__name__!r} has no attribute {name!r}")
Using this, calling HAS_NOTSUCHPACKAGE raises ImportError or AttributeError depending on how the import is actually done.
Activity
hamogu commentedon Feb 23, 2016
That would also make is easier to find and change if the optional dependency changes, is removed (e.g. we decide in the future that scipy becomes a hard dependency).
astrofrog commentedon Feb 23, 2016
In Glue, I also made decorators that can be used directly on the test functions, e.g.
@requires_pathlib, so we could do that here too optionally?taldcroft commentedon Feb 23, 2016
@astrofrog - is this
@requires_Xmapped topytest.mark.skipifso pytest is doing the right thing? It seems like@requirescould take an argument of one or more optional deps, e.g.@test_requires('pathlib', 'scipy', 'beautifulsoup'). I think it makes sense to havetestin the decorator name if it is specifically targeted at tests.astrofrog commentedon Feb 23, 2016
@taldcroft - yes, you can see what I have here:
https://github.com/glue-viz/glue/blob/master/glue/tests/helpers.py
However, it's hard to do boolean logic with that, so it might be over-engineering, and the constants you are suggesting might be enough.
saimn commentedon Feb 23, 2016
Glue's decorator seems a good way to go.
https://github.com/glue-viz/glue/blob/master/glue/tests/helpers.py#L14
It provides both a decorator which wraps pytest's skipif, and a
...._INSTALLEDvariable to check if a module is available. (Should be renamed toHAS_...?)pllim commentedon May 11, 2020
pathlibis now provided by the minversion of Python that we support, so thatif ... else ...can be taken out altogether. For testing,pytesthasimportorskip, so can this issue be closed?astrofrog commentedon May 11, 2020
I think it might still be worth considering centralizing the
HAS_...variables for other optional dependencies?pllim commentedon May 12, 2020
I started working on this and then realized that we cannot really lazy import until minversion of Python is 3.7. I think something like this might work based on PEP 562, otherwise we either over-engineer or incur a penalty of checking for everything at import time.
Lazy import is important because some of these
HAS_*checks occur inside real modules, not just tests.I called this file
astropy/utils/compat/optional_deps.pybut nothing is set in stone yet:Using this, calling
HAS_NOTSUCHPACKAGEraisesImportErrororAttributeErrordepending on how the import is actually done.p.s. I welcome better ideas.
adrn commentedon Apr 6, 2021
Finding this after @nstarman re-raised the issue: I think this is doable now! Aren't we Python 3.7+?
pllim commentedon Apr 6, 2021
Theoretically, yes... but I have bigger fish to fry. Maybe someone else wanna give it a stab this time?
adrn commentedon Apr 6, 2021
You're just trying to trick me into contributing to
astropy.utils... :)But I have some time to try this out shortly!
pllim commentedon Apr 6, 2021