Search sys.path for the given a dotted module name, and return its file system path if found.
(
module_name: str, *, consider_namespace_packages: bool = False
)
| 1038 | |
| 1039 | |
| 1040 | def search_pypath( |
| 1041 | module_name: str, *, consider_namespace_packages: bool = False |
| 1042 | ) -> str | None: |
| 1043 | """Search sys.path for the given a dotted module name, and return its file |
| 1044 | system path if found.""" |
| 1045 | try: |
| 1046 | spec = importlib.util.find_spec(module_name) |
| 1047 | # AttributeError: looks like package module, but actually filename |
| 1048 | # ImportError: module does not exist |
| 1049 | # ValueError: not a module name |
| 1050 | except (AttributeError, ImportError, ValueError): |
| 1051 | return None |
| 1052 | |
| 1053 | if spec is None: |
| 1054 | return None |
| 1055 | |
| 1056 | if ( |
| 1057 | spec.submodule_search_locations is None |
| 1058 | or len(spec.submodule_search_locations) == 0 |
| 1059 | ): |
| 1060 | # Must be a simple module. |
| 1061 | return spec.origin |
| 1062 | |
| 1063 | if consider_namespace_packages: |
| 1064 | # If submodule_search_locations is set, it's a package (regular or namespace). |
| 1065 | # Typically there is a single entry, but documentation claims it can be empty too |
| 1066 | # (e.g. if the package has no physical location). |
| 1067 | return spec.submodule_search_locations[0] |
| 1068 | |
| 1069 | if spec.origin is None: |
| 1070 | # This is only the case for namespace packages |
| 1071 | return None |
| 1072 | |
| 1073 | return os.path.dirname(spec.origin) |
| 1074 | |
| 1075 | |
| 1076 | @dataclasses.dataclass(frozen=True) |
no test coverage detected