Import a Python module and raise a user-friendly error if it is not available. This utility helps provide actionable error messages when optional dependencies are missing. It attempts to import the given module and, on failure, suggests a `pip install` command based on either the module
(module: str, mitigation: Optional[str] = None)
| 18 | |
| 19 | |
| 20 | def require_module(module: str, mitigation: Optional[str] = None) -> Any: |
| 21 | """Import a Python module and raise a user-friendly error if it is not available. |
| 22 | |
| 23 | This utility helps provide actionable error messages when optional dependencies |
| 24 | are missing. It attempts to import the given module and, on failure, suggests |
| 25 | a `pip install` command based on either the module name or an optional |
| 26 | mitigation package name. |
| 27 | |
| 28 | Args: |
| 29 | module (str): The full module name to import (e.g., ``"numpy"``, ``"pandas.io.parquet"``). |
| 30 | mitigation (Optional[str], optional): The package name to suggest for installation |
| 31 | if the import fails. If not provided, the top-level package of `module` |
| 32 | will be used (e.g., ``"pandas"`` for ``"pandas.io.parquet"``). |
| 33 | |
| 34 | Returns: |
| 35 | Any: The imported module object. |
| 36 | |
| 37 | Raises: |
| 38 | ImportError: If the module cannot be imported, with a clear installation hint. |
| 39 | |
| 40 | Examples: |
| 41 | >>> import zvec |
| 42 | >>> np = zvec.require_module("numpy") |
| 43 | >>> pq = zvec.require_module("pyarrow.parquet", mitigation="pyarrow") |
| 44 | |
| 45 | Note: |
| 46 | This function is intended for lazy-loading optional dependencies |
| 47 | with helpful error messages, not for core dependencies. |
| 48 | """ |
| 49 | try: |
| 50 | return importlib.import_module(module) |
| 51 | except ImportError as e: |
| 52 | package = mitigation or module |
| 53 | msg = f"Required package '{package}' is not installed. " |
| 54 | if "." in module: |
| 55 | top_level = module.split(".", maxsplit=1)[0] |
| 56 | msg += f"Module '{module}' is part of '{top_level}', " |
| 57 | if mitigation: |
| 58 | msg += f"please pip install '{mitigation}'." |
| 59 | else: |
| 60 | msg += f"please pip install '{top_level}'." |
| 61 | else: |
| 62 | msg += f"Please pip install '{package}'." |
| 63 | raise ImportError(msg) from e |
no outgoing calls