-
Notifications
You must be signed in to change notification settings - Fork 166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Skip tests for optional dependencies if they are not installed #115
Comments
@szuckerman that's a really great catch! In general, I have been dependent on conda since grad school - only because conda helps with packaging of non-Python dependencies of Python and other language data science packages. Admittedly, I think what I'll do is go in and mark the tests with their appropriate submodule name, so we can do things like:
or
That way, they can be selectively run if necessary. |
Are the concerns raised here still outstanding @ericmjl, @szuckerman? I suppose this is related in a way to #551. I'm going through the oldest issues to see what can be done. |
I think we might need to update this issue - perhaps it should be renamed, "Mark tests with skipif for optional dependencies". Doing so would be pretty rad - we could skip all of the biology/chemistry/spark functions if they can't be imported successfully. One thing I would prefer to remain as is, though, is |
I agree. Having them as optional for users but required in CI is important. |
@ericmjl I'm revisiting this one again. try:
import pyspark
import janitor.spark # noqa: F401
except ImportError:
pyspark = None
@pytest.mark.spark_functions
@pytest.mark.skipif(pyspark is None, reason="pyspark tests only required for CI")
def test_clean_names_method_chain(spark_df):
... There are some other options I learned recently. We can instead skip the whole test file if an import is unsuccessful: import pytest
pyspark = pytest.importorskip("pyspark") I think it is very useful to:
|
@hectormz, this looks like a very good idea. I can definitely see how it’s useful for those who don’t want to install the entire suite of optional dependencies. If you could help me a bit here, I am not quite following the 3rd point:
If I understand correctly, on the CI system, if a package doesn’t get installed somehow, we want the tests to fail, rather than skip them. Is that part of the point you’re making with point 3? Or am I simply overthinking things here? 😸 |
@ericmjl Exactly! This is very related to a PR I'm working on for We're still figuring out the best way, either monkeypatching or writing our own |
@ericmjl With arviz-devs/arviz#1113 having been merged, do you want to try a similar approach to what was eventually executed in that PR? |
Yes! Let's do that. This would be good for the pyspark and domain-specific modules, right? I looked briefly at the code, and I think this is the block that would help, am I right about it? pytestmark = pytest.mark.skipif( # pylint: disable=invalid-name
(importlib.util.find_spec("numba") is None) & ~running_on_ci(),
reason="test requires numba which is not installed",
) |
Right. That decorator will skip the test if the module is not installed (but not running on CI) There's also from ..helper import importorskip
numba= importorskip("numba") # pylint: disable=invalid-name Which would skip the whole file of tests (Useful for tests that are grouped in same file like pyspark IIRC) This relies on a custom def running_on_ci() -> bool:
"""Return True if running on CI machine."""
return os.environ.get("ARVIZ_CI_MACHINE") is not None
def importorskip(
modname: str, minversion: Optional[str] = None, reason: Optional[str] = None
) -> Any:
"""Import and return the requested module ``modname``.
Doesn't allow skips on CI machine.
Borrowed and modified from ``pytest.importorskip``.
:param str modname: the name of the module to import
:param str minversion: if given, the imported module's ``__version__``
attribute must be at least this minimal version, otherwise the test is
still skipped.
:param str reason: if given, this reason is shown as the message when the
module cannot be imported.
:returns: The imported module. This should be assigned to its canonical
name.
Example::
docutils = pytest.importorskip("docutils")
"""
# ARVIZ_CI_MACHINE is True if tests run on CI, where ARVIZ_CI_MACHINE env variable exists
ARVIZ_CI_MACHINE = running_on_ci()
if ARVIZ_CI_MACHINE:
import warnings
compile(modname, "", "eval") # to catch syntaxerrors
with warnings.catch_warnings():
# make sure to ignore ImportWarnings that might happen because
# of existing directories with the same name we're trying to
# import but without a __init__.py file
warnings.simplefilter("ignore")
__import__(modname)
mod = sys.modules[modname]
if minversion is None:
return mod
verattr = getattr(mod, "__version__", None)
if minversion is not None:
if verattr is None or Version(verattr) < Version(minversion):
raise Skipped(
"module %r has __version__ %r, required is: %r"
% (modname, verattr, minversion),
allow_module_level=True,
)
return mod
else:
return pytest.importorskip(modname=modname, minversion=minversion, reason=reason) |
This second option makes sense if it is very clear that the test .py file is dedicated to |
I just tried to run the test suite and had some failures because I don't have some of the Chemistry packages installed. I realized that those packages are only available through conda.
I don't use conda and am finding out that it's not so easy to just "install" conda packages into a previously created virtual environment (I mean, I'll figure it out eventually, but this is just at first glance).
In any event, I think it raises an interesting question: Does this create issues for people who don't use conda? Meaning, if I try to use something from a submodule, but because I don't have a dependency installed, like
rdkit
, it'll tell me to remedy with aconda install
that's not going to work?I'm not really sure what the answer is, but I could see either putting functions that rely on conda dependencies in their own package for conda, or just keeping it how it is and let people deal with it (assuming that people using these modules most likely already have conda installed).
Just wanted to throw this out there before the submodules get bigger.
The text was updated successfully, but these errors were encountered: