Skip to content

Commit b029c44

Browse files
committed
Refactor to allow a safer source=None
1 parent 8e53191 commit b029c44

2 files changed

Lines changed: 41 additions & 21 deletions

File tree

mypy/build.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
from mypy.modules_state import modules_state
164164
from mypy.nodes import Expression
165165
from mypy.options import Options
166-
from mypy.parse import load_from_raw, parse
166+
from mypy.parse import load_from_raw, parse, parse_native
167167
from mypy.plugin import ChainedPlugin, Plugin, ReportConfigContext
168168
from mypy.plugins.default import DefaultPlugin
169169
from mypy.renaming import LimitedVariableRenameVisitor, VariableRenameVisitor
@@ -1114,7 +1114,9 @@ def parse_files_threaded_raw(self, states: list[State]) -> tuple[list[State], se
11141114
ignore_errors = state.ignore_all or state.options.ignore_errors
11151115
if ignore_errors:
11161116
self.errors.ignored_files.add(state.xpath)
1117-
futures.append(executor.submit(state.parse_file_inner, state.source))
1117+
futures.append(
1118+
executor.submit(state.parse_file_inner, state.source, parallel=True)
1119+
)
11181120
parallel_parsed_states.append(state)
11191121
parallel_parsed_states_set.add(state)
11201122
else:
@@ -1264,9 +1266,10 @@ def parse_file(
12641266
self,
12651267
id: str,
12661268
path: str,
1267-
source: str,
1269+
source: str | None,
12681270
options: Options,
12691271
raw_data: FileRawData | None = None,
1272+
parallel: bool = False,
12701273
) -> MypyFile:
12711274
"""Parse the source of a file with the given name.
12721275
@@ -1277,7 +1280,11 @@ def parse_file(
12771280
# If possible, deserialize from known binary data instead of parsing from scratch.
12781281
tree = load_from_raw(path, id, raw_data, self.errors, options)
12791282
else:
1280-
tree = parse(source, path, id, self.errors, options=options)
1283+
if source is not None:
1284+
tree = parse(source, path, id, self.errors, options=options)
1285+
else:
1286+
assert parallel
1287+
tree = parse_native(source, path, id, self.errors, options=options)
12811288
tree._fullname = id
12821289
if self.stats_enabled:
12831290
with self.stats_lock:
@@ -3176,10 +3183,12 @@ def get_source(self) -> str:
31763183
self.time_spent_us += time_spent_us(t0)
31773184
return source
31783185

3179-
def parse_file_inner(self, source: str, raw_data: FileRawData | None = None) -> None:
3186+
def parse_file_inner(
3187+
self, source: str | None, raw_data: FileRawData | None = None, parallel: bool = False
3188+
) -> None:
31803189
t0 = time_ref()
31813190
self.tree = self.manager.parse_file(
3182-
self.id, self.xpath, source, options=self.options, raw_data=raw_data
3191+
self.id, self.xpath, source, self.options, raw_data, parallel
31833192
)
31843193
self.time_spent_us += time_spent_us(t0)
31853194

mypy/parse.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,7 @@ def parse(
2828
the parse errors, use eager=True.
2929
"""
3030
if options.native_parser:
31-
import mypy.nativeparse
32-
33-
ignore_errors = options.ignore_errors or fnam in errors.ignored_files
34-
# If errors are ignored, we can drop many function bodies to speed up type checking.
35-
strip_function_bodies = ignore_errors and not options.preserve_asts
36-
tree, _, _ = mypy.nativeparse.native_parse(
37-
fnam, options, source, skip_function_bodies=strip_function_bodies
38-
)
39-
# Set is_stub based on file extension
40-
tree.is_stub = fnam.endswith(".pyi")
41-
# Note: tree.imports is populated directly by load_from_raw() with deserialized
42-
# import metadata, so we don't need to collect imports via AST traversal
43-
if eager and tree.raw_data is not None:
44-
tree = load_from_raw(fnam, module, tree.raw_data, errors, options)
45-
return tree
31+
return parse_native(source, fnam, module, errors, options, eager)
4632

4733
if options.transform_source is not None:
4834
source = options.transform_source(source)
@@ -97,6 +83,31 @@ def load_from_raw(
9783
return tree
9884

9985

86+
def parse_native(
87+
source: str | bytes | None,
88+
fnam: str,
89+
module: str | None,
90+
errors: Errors,
91+
options: Options,
92+
eager: bool = False,
93+
) -> MypyFile:
94+
import mypy.nativeparse
95+
96+
ignore_errors = options.ignore_errors or fnam in errors.ignored_files
97+
# If errors are ignored, we can drop many function bodies to speed up type checking.
98+
strip_function_bodies = ignore_errors and not options.preserve_asts
99+
tree, _, _ = mypy.nativeparse.native_parse(
100+
fnam, options, source, skip_function_bodies=strip_function_bodies
101+
)
102+
# Set is_stub based on file extension
103+
tree.is_stub = fnam.endswith(".pyi")
104+
# Note: tree.imports is populated directly by load_from_raw() with deserialized
105+
# import metadata, so we don't need to collect imports via AST traversal
106+
if eager and tree.raw_data is not None:
107+
tree = load_from_raw(fnam, module, tree.raw_data, errors, options)
108+
return tree
109+
110+
100111
def report_parse_error(error: ParseError, errors: Errors) -> None:
101112
message = error["message"]
102113
# Standardize error message by capitalizing the first word

0 commit comments

Comments
 (0)