Source code for simvx.core.testing.optional

"""Guards for tests that need an optional package.

:func:`importlib.util.find_spec` is the obvious way to write "skip unless X is
installed", and it is wrong for any dotted name: it imports the parent package
to read its ``__path__``, so a missing parent raises ``ModuleNotFoundError``
instead of returning ``None``. ``find_spec("simvx.physics.jolt")`` therefore
answers "not installed" on a machine that has ``simvx-physics-jolt`` minus the
submodule, and *raises at collection time* on one that has neither -- which is
every machine that installed only the engine.

:func:`module_installed` is the answer those guards actually want.
"""

import importlib.util

__all__ = ["module_installed"]


[docs] def module_installed(name: str) -> bool: """Return whether *name* can be imported, without importing it. Handles dotted names whose parent package is itself absent, and treats a parent that exists but fails to import as "not installed" rather than letting the import error escape into collection. Args: name: A module name, dotted or not (``"pymunk"``, ``"simvx.physics.jolt"``). Returns: ``True`` when the module can be located, ``False`` otherwise. """ try: return importlib.util.find_spec(name) is not None except (ImportError, ValueError): return False