|
| 1 | +from importlib import import_module, metadata |
| 2 | +from packaging.requirements import Requirement |
| 3 | +from types import ModuleType |
| 4 | + |
| 5 | + |
| 6 | +def import_optional_dependency( |
| 7 | + module_name: str, |
| 8 | + feature: str |
| 9 | +) -> ModuleType: |
| 10 | + """Import an optional dependency. |
| 11 | +
|
| 12 | + This function is designed to support interaction with other common |
| 13 | + libraries that are not required for `highdicom` by default. |
| 14 | +
|
| 15 | + Parameters |
| 16 | + ---------- |
| 17 | + module_name: str |
| 18 | + Name of the module to be imported. |
| 19 | + feature: str |
| 20 | + Name or description of the feature that requires this dependency. |
| 21 | + This is used for improving the clarity of error messages. |
| 22 | +
|
| 23 | + Returns |
| 24 | + ------- |
| 25 | + ModuleType: |
| 26 | + Imported module. |
| 27 | +
|
| 28 | + Raises |
| 29 | + ------ |
| 30 | + ImportError: |
| 31 | + When the specified module cannot be imported. |
| 32 | +
|
| 33 | + """ |
| 34 | + for req_str in metadata.requires('highdicom'): |
| 35 | + req = Requirement(req_str) |
| 36 | + if req.name == module_name: |
| 37 | + break |
| 38 | + |
| 39 | + else: |
| 40 | + raise ValueError( |
| 41 | + f'`{module_name}` is not a requirement of highdicom ' |
| 42 | + f'but is required for {feature}.' |
| 43 | + ) |
| 44 | + |
| 45 | + try: |
| 46 | + module = import_module(name=module_name) |
| 47 | + |
| 48 | + except ImportError as error: |
| 49 | + raise ImportError( |
| 50 | + f'Optional dependency `{module_name}` could not be imported' |
| 51 | + f' but is required for {feature}.' |
| 52 | + f' highdicom requires {module_name}{req.specifier}.' |
| 53 | + ) from error |
| 54 | + |
| 55 | + installed_version = metadata.version(module_name) |
| 56 | + |
| 57 | + if installed_version not in req.specifier: |
| 58 | + raise ImportError( |
| 59 | + f'Optional dependency `{module_name}` has an unsuitable ' |
| 60 | + f'version. Found {module_name}=={installed_version}, but ' |
| 61 | + f'highdicom requires {module_name}{req.specifier}.' |
| 62 | + ) |
| 63 | + |
| 64 | + return module |
0 commit comments