Do the hard work for readmodule[_ex]. If inpackage is given, it must be the dotted name of the package in which we are searching for a submodule, and then PATH must be the package search path; otherwise, we are searching for a top-level module, and path is combined with sys.path.
(module, path, inpackage=None)
| 120 | |
| 121 | |
| 122 | def _readmodule(module, path, inpackage=None): |
| 123 | """Do the hard work for readmodule[_ex]. |
| 124 | |
| 125 | If inpackage is given, it must be the dotted name of the package in |
| 126 | which we are searching for a submodule, and then PATH must be the |
| 127 | package search path; otherwise, we are searching for a top-level |
| 128 | module, and path is combined with sys.path. |
| 129 | """ |
| 130 | # Compute the full module name (prepending inpackage if set). |
| 131 | if inpackage is not None: |
| 132 | fullmodule = "%s.%s" % (inpackage, module) |
| 133 | else: |
| 134 | fullmodule = module |
| 135 | |
| 136 | # Check in the cache. |
| 137 | if fullmodule in _modules: |
| 138 | return _modules[fullmodule] |
| 139 | |
| 140 | # Initialize the dict for this module's contents. |
| 141 | tree = {} |
| 142 | |
| 143 | # Check if it is a built-in module; we don't do much for these. |
| 144 | if module in sys.builtin_module_names and inpackage is None: |
| 145 | _modules[module] = tree |
| 146 | return tree |
| 147 | |
| 148 | # Check for a dotted module name. |
| 149 | i = module.rfind('.') |
| 150 | if i >= 0: |
| 151 | package = module[:i] |
| 152 | submodule = module[i+1:] |
| 153 | parent = _readmodule(package, path, inpackage) |
| 154 | if inpackage is not None: |
| 155 | package = "%s.%s" % (inpackage, package) |
| 156 | if not '__path__' in parent: |
| 157 | raise ImportError('No package named {}'.format(package)) |
| 158 | return _readmodule(submodule, parent['__path__'], package) |
| 159 | |
| 160 | # Search the path for the module. |
| 161 | if inpackage is not None: |
| 162 | search_path = path |
| 163 | else: |
| 164 | search_path = path + sys.path |
| 165 | spec = importlib.util._find_spec_from_path(fullmodule, search_path) |
| 166 | if spec is None: |
| 167 | raise ModuleNotFoundError(f"no module named {fullmodule!r}", name=fullmodule) |
| 168 | _modules[fullmodule] = tree |
| 169 | # Is module a package? |
| 170 | if spec.submodule_search_locations is not None: |
| 171 | tree['__path__'] = spec.submodule_search_locations |
| 172 | try: |
| 173 | source = spec.loader.get_source(fullmodule) |
| 174 | except (AttributeError, ImportError): |
| 175 | # If module is not Python source, we cannot do anything. |
| 176 | return tree |
| 177 | else: |
| 178 | if source is None: |
| 179 | return tree |
no test coverage detected
searching dependent graphs…