Module finder with integrated cache. Module locations and some intermediate results are cached internally and can be cleared with the clear() method. All file system accesses are performed through a FileSystemCache, which is not ever cleared by this class. If necessary it must be
| 170 | |
| 171 | |
| 172 | class FindModuleCache: |
| 173 | """Module finder with integrated cache. |
| 174 | |
| 175 | Module locations and some intermediate results are cached internally |
| 176 | and can be cleared with the clear() method. |
| 177 | |
| 178 | All file system accesses are performed through a FileSystemCache, |
| 179 | which is not ever cleared by this class. If necessary it must be |
| 180 | cleared by client code. |
| 181 | """ |
| 182 | |
| 183 | def __init__( |
| 184 | self, |
| 185 | search_paths: SearchPaths, |
| 186 | fscache: FileSystemCache | None, |
| 187 | options: Options | None, |
| 188 | stdlib_py_versions: StdlibVersions | None = None, |
| 189 | source_set: BuildSourceSet | None = None, |
| 190 | ) -> None: |
| 191 | self.search_paths = search_paths |
| 192 | self.source_set = source_set |
| 193 | self.fscache = fscache or FileSystemCache() |
| 194 | # Cache for get_toplevel_possibilities: |
| 195 | # search_paths -> (toplevel_id -> list(package_dirs)) |
| 196 | self.initial_components: dict[tuple[str, ...], dict[str, list[str]]] = {} |
| 197 | # Cache find_module: id -> result |
| 198 | self.results: dict[str, ModuleSearchResult] = {} |
| 199 | self.ns_ancestors: dict[str, str] = {} |
| 200 | self.options = options |
| 201 | custom_typeshed_dir = None |
| 202 | if options: |
| 203 | custom_typeshed_dir = options.custom_typeshed_dir |
| 204 | self.stdlib_py_versions = stdlib_py_versions or load_stdlib_py_versions( |
| 205 | custom_typeshed_dir |
| 206 | ) |
| 207 | |
| 208 | def clear(self) -> None: |
| 209 | self.results.clear() |
| 210 | self.initial_components.clear() |
| 211 | self.ns_ancestors.clear() |
| 212 | |
| 213 | def find_module_via_source_set(self, id: str) -> ModuleSearchResult | None: |
| 214 | """Fast path to find modules by looking through the input sources |
| 215 | |
| 216 | This is only used when --fast-module-lookup is passed on the command line.""" |
| 217 | if not self.source_set: |
| 218 | return None |
| 219 | |
| 220 | p = self.source_set.source_modules.get(id, None) |
| 221 | if p and self.fscache.isfile(p): |
| 222 | # We need to make sure we still have __init__.py all the way up |
| 223 | # otherwise we might have false positives compared to slow path |
| 224 | # in case of deletion of init files, which is covered by some tests. |
| 225 | # TODO: are there some combination of flags in which this check should be skipped? |
| 226 | d = os.path.dirname(p) |
| 227 | for _ in range(id.count(".")): |
| 228 | if not any( |
| 229 | self.fscache.isfile(os_path_join(d, "__init__" + x)) for x in PYTHON_EXTENSIONS |
no outgoing calls
searching dependent graphs…