Skip to content

Commit bbe68d3

Browse files
authored
Support --package-root with native parser (#21321)
When `--package-root` is used, `fscache` creates some fake `__init__.py` files on-the-fly (that don't actually exist). These obviously can't be handed by the native parser, but `fscache.exists()` returns `True` for them, causing a crash. One possible fix is to simply use `os.path.isfile()` everywhere. But I think `fscache` can give us a little perf boost, so I instead add a `real_only` flag to `fscache.exists()`.
1 parent 52a1c48 commit bbe68d3

5 files changed

Lines changed: 22 additions & 7 deletions

File tree

mypy/__main__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import sys
77
import traceback
88

9+
from mypy.fscache import FileSystemCache
910
from mypy.main import main, process_options
1011
from mypy.util import FancyFormatter
1112

@@ -22,7 +23,8 @@ def console_entry() -> None:
2223
os.dup2(devnull, sys.stdout.fileno())
2324
sys.exit(2)
2425
except KeyboardInterrupt:
25-
_, options = process_options(args=sys.argv[1:])
26+
# Setting fscache prevents bogus errors when --package-root is set.
27+
_, options = process_options(args=sys.argv[1:], fscache=FileSystemCache())
2628
if options.show_traceback:
2729
sys.stdout.write(traceback.format_exc())
2830
formatter = FancyFormatter(sys.stdout, sys.stderr, False)
@@ -36,7 +38,7 @@ def console_entry() -> None:
3638
try:
3739
import mypy.errors
3840

39-
_, options = process_options(args=sys.argv[1:])
41+
_, options = process_options(args=sys.argv[1:], fscache=FileSystemCache())
4042
mypy.errors.report_internal_error(e, None, 0, None, options)
4143
except Exception:
4244
pass

mypy/build.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ def parse_all(self, states: list[State], post_parse: bool = True) -> None:
10251025
if state.tree is not None:
10261026
# The file was already parsed.
10271027
continue
1028-
if not self.fscache.exists(state.xpath):
1028+
if not self.fscache.exists(state.xpath, real_only=True):
10291029
# New parser only supports parsing on-disk files.
10301030
sequential_states.append(state)
10311031
continue
@@ -1083,7 +1083,6 @@ def parse_parallel(self, sequential_states: list[State], parallel_states: list[S
10831083
elif state.source_hash is None:
10841084
# At least namespace packages may not have source.
10851085
state.get_source()
1086-
state.size_hint = os.path.getsize(state.xpath)
10871086
state.early_errors = list(self.errors.error_info_map.get(state.xpath, []))
10881087
state.semantic_analysis_pass1()
10891088
self.ast_cache[state.id] = (state.tree, state.early_errors, state.source_hash)
@@ -1271,7 +1270,7 @@ def parse_file(
12711270
12721271
Raise CompileError if there is a parse error.
12731272
"""
1274-
file_exists = self.fscache.exists(path)
1273+
file_exists = self.fscache.exists(path, real_only=True)
12751274
t0 = time.time()
12761275
if raw_data:
12771276
# If possible, deserialize from known binary data instead of parsing from scratch.

mypy/build_worker/worker.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ def main(argv: list[str]) -> None:
103103
raise
104104

105105
fscache = FileSystemCache()
106+
fscache.set_package_root(options.package_root)
106107
cached_read = fscache.read
107108
errors = Errors(options, read_source=lambda path: read_py_file(path, cached_read))
108109

mypy/fscache.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,14 @@ def isdir(self, path: str) -> bool:
253253
return False
254254
return stat.S_ISDIR(st.st_mode)
255255

256-
def exists(self, path: str) -> bool:
256+
def exists(self, path: str, real_only: bool = False) -> bool:
257257
st = self.stat_or_none(path)
258-
return st is not None
258+
if st is None:
259+
return False
260+
if real_only:
261+
dirname = os.path.dirname(path)
262+
return dirname not in self.fake_package_cache
263+
return True
259264

260265
def read(self, path: str) -> bytes:
261266
if path in self.read_cache:

test-data/unit/cmdline.test

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,14 @@ import d
591591
import b.c
592592
import d
593593

594+
[case testPackageRootMultipleParallel]
595+
# cmd: mypy --package-root=a/ --package-root=./ a/b/c.py d.py main.py --num-workers=2
596+
[file a/b/c.py]
597+
[file d.py]
598+
[file main.py]
599+
import b.c
600+
import d
601+
594602
[case testCacheMap]
595603
-- This just checks that a valid --cache-map triple is accepted.
596604
-- (Errors are too verbose to check.)

0 commit comments

Comments
 (0)