| 40 | |
| 41 | @mypyc_attr(allow_interpreted_subclasses=True) # for tests |
| 42 | class FileSystemCache: |
| 43 | def __init__(self) -> None: |
| 44 | # The package root is not flushed with the caches. |
| 45 | # It is set by set_package_root() below. |
| 46 | self.package_root: list[str] = [] |
| 47 | self.flush() |
| 48 | |
| 49 | def set_package_root(self, package_root: list[str]) -> None: |
| 50 | self.package_root = package_root |
| 51 | |
| 52 | def flush(self) -> None: |
| 53 | """Start another transaction and empty all caches.""" |
| 54 | self.stat_or_none_cache: dict[str, os.stat_result | None] = {} |
| 55 | |
| 56 | self.listdir_cache: dict[str, list[str]] = {} |
| 57 | self.listdir_error_cache: dict[str, OSError] = {} |
| 58 | self.isfile_case_cache: dict[str, bool] = {} |
| 59 | self.exists_case_cache: dict[str, bool] = {} |
| 60 | self.read_cache: dict[str, bytes] = {} |
| 61 | self.read_error_cache: dict[str, Exception] = {} |
| 62 | self.hash_cache: dict[str, str] = {} |
| 63 | self.fake_package_cache: set[str] = set() |
| 64 | |
| 65 | def stat_or_none(self, path: str) -> os.stat_result | None: |
| 66 | if path in self.stat_or_none_cache: |
| 67 | return self.stat_or_none_cache[path] |
| 68 | |
| 69 | st = None |
| 70 | try: |
| 71 | st = os.stat(path) |
| 72 | except OSError: |
| 73 | if self.init_under_package_root(path): |
| 74 | try: |
| 75 | st = self._fake_init(path) |
| 76 | except OSError: |
| 77 | pass |
| 78 | |
| 79 | self.stat_or_none_cache[path] = st |
| 80 | return st |
| 81 | |
| 82 | def init_under_package_root(self, path: str) -> bool: |
| 83 | """Is this path an __init__.py under a package root? |
| 84 | |
| 85 | This is used to detect packages that don't contain __init__.py |
| 86 | files, which is needed to support Bazel. The function should |
| 87 | only be called for non-existing files. |
| 88 | |
| 89 | It will return True if it refers to a __init__.py file that |
| 90 | Bazel would create, so that at runtime Python would think the |
| 91 | directory containing it is a package. For this to work you |
| 92 | must pass one or more package roots using the --package-root |
| 93 | flag. |
| 94 | |
| 95 | As an exceptional case, any directory that is a package root |
| 96 | itself will not be considered to contain a __init__.py file. |
| 97 | This is different from the rules Bazel itself applies, but is |
| 98 | necessary for mypy to properly distinguish packages from other |
| 99 | directories. |
no outgoing calls
searching dependent graphs…