Skip to content

Commit 18a9fe1

Browse files
authored
Add infrastructure for testing order of processing nodes in new analyser (#7160)
See #6341 This PR doesn't add actual tests, just the infra. I simply expose the existing machinery we use in the fine grained mode also to the normal tests. Using this opportunity I also refactor `assert_module_equivalence()` and `assert_target_equivalence()` by moving `is None` checks to callers.
1 parent 1d1f2fe commit 18a9fe1

File tree

6 files changed

+77
-43
lines changed

6 files changed

+77
-43
lines changed

mypy/build.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,10 @@ def __init__(self, data_dir: str,
572572
self.plugins_snapshot = plugins_snapshot
573573
self.old_plugins_snapshot = read_plugins_snapshot(self)
574574
self.quickstart_state = read_quickstart_file(options, self.stdout)
575+
# Fine grained targets (module top levels and top level functions) processed by
576+
# the semantic analyzer, used only for testing. Currently used only by the new
577+
# semantic analyzer.
578+
self.processed_targets = [] # type: List[str]
575579

576580
def dump_stats(self) -> None:
577581
self.log("Stats:")

mypy/newsemanal/semanal_main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ def semantic_analyze_target(target: str,
297297
- was some definition incomplete
298298
- were any new names were defined (or placeholders replaced)
299299
"""
300+
state.manager.processed_targets.append(target)
300301
tree = state.tree
301302
assert tree is not None
302303
analyzer = state.manager.new_semantic_analyzer

mypy/test/helpers.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,32 +115,30 @@ def assert_string_arrays_equal(expected: List[str], actual: List[str],
115115

116116

117117
def assert_module_equivalence(name: str,
118-
expected: Optional[Iterable[str]], actual: Iterable[str]) -> None:
119-
if expected is not None:
120-
expected_normalized = sorted(expected)
121-
actual_normalized = sorted(set(actual).difference({"__main__"}))
122-
assert_string_arrays_equal(
123-
expected_normalized,
124-
actual_normalized,
125-
('Actual modules ({}) do not match expected modules ({}) '
126-
'for "[{} ...]"').format(
127-
', '.join(actual_normalized),
128-
', '.join(expected_normalized),
129-
name))
118+
expected: Iterable[str], actual: Iterable[str]) -> None:
119+
expected_normalized = sorted(expected)
120+
actual_normalized = sorted(set(actual).difference({"__main__"}))
121+
assert_string_arrays_equal(
122+
expected_normalized,
123+
actual_normalized,
124+
('Actual modules ({}) do not match expected modules ({}) '
125+
'for "[{} ...]"').format(
126+
', '.join(actual_normalized),
127+
', '.join(expected_normalized),
128+
name))
130129

131130

132131
def assert_target_equivalence(name: str,
133-
expected: Optional[List[str]], actual: List[str]) -> None:
132+
expected: List[str], actual: List[str]) -> None:
134133
"""Compare actual and expected targets (order sensitive)."""
135-
if expected is not None:
136-
assert_string_arrays_equal(
137-
expected,
138-
actual,
139-
('Actual targets ({}) do not match expected targets ({}) '
140-
'for "[{} ...]"').format(
141-
', '.join(actual),
142-
', '.join(expected),
143-
name))
134+
assert_string_arrays_equal(
135+
expected,
136+
actual,
137+
('Actual targets ({}) do not match expected targets ({}) '
138+
'for "[{} ...]"').format(
139+
', '.join(actual),
140+
', '.join(expected),
141+
name))
144142

145143

146144
def update_testcase_output(testcase: DataDrivenTestCase, output: List[str]) -> None:

mypy/test/testcheck.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
from mypy.test.helpers import (
1717
assert_string_arrays_equal, normalize_error_messages, assert_module_equivalence,
1818
retry_on_error, update_testcase_output, parse_options,
19-
copy_and_fudge_mtime
19+
copy_and_fudge_mtime, assert_target_equivalence
2020
)
2121
from mypy.errors import CompileError
22+
from mypy.newsemanal.semanal_main import core_modules
2223

2324

2425
# List of files that contain test case descriptions.
@@ -222,16 +223,28 @@ def run_case_once(self, testcase: DataDrivenTestCase,
222223
if options.cache_dir != os.devnull:
223224
self.verify_cache(module_data, res.errors, res.manager, res.graph)
224225

226+
if options.new_semantic_analyzer:
227+
name = 'targets'
228+
if incremental_step:
229+
name += str(incremental_step + 1)
230+
expected = testcase.expected_fine_grained_targets.get(incremental_step + 1)
231+
actual = res.manager.processed_targets
232+
# Skip the initial builtin cycle.
233+
actual = [t for t in actual if not any(t.startswith(mod) for mod in core_modules)]
234+
if expected is not None:
235+
assert_target_equivalence(name, expected, actual)
225236
if incremental_step > 1:
226237
suffix = '' if incremental_step == 2 else str(incremental_step - 1)
227-
assert_module_equivalence(
228-
'rechecked' + suffix,
229-
testcase.expected_rechecked_modules.get(incremental_step - 1),
230-
res.manager.rechecked_modules)
231-
assert_module_equivalence(
232-
'stale' + suffix,
233-
testcase.expected_stale_modules.get(incremental_step - 1),
234-
res.manager.stale_modules)
238+
expected_rechecked = testcase.expected_rechecked_modules.get(incremental_step - 1)
239+
if expected_rechecked is not None:
240+
assert_module_equivalence(
241+
'rechecked' + suffix,
242+
expected_rechecked, res.manager.rechecked_modules)
243+
expected_stale = testcase.expected_stale_modules.get(incremental_step - 1)
244+
if expected_stale is not None:
245+
assert_module_equivalence(
246+
'stale' + suffix,
247+
expected_stale, res.manager.stale_modules)
235248

236249
def verify_cache(self, module_data: List[Tuple[str, str, str]], a: List[str],
237250
manager: build.BuildManager, graph: Graph) -> None:

mypy/test/testfinegrained.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -133,18 +133,23 @@ def run_case(self, testcase: DataDrivenTestCase) -> None:
133133
changed = [mod for mod, file in server.fine_grained_manager.changed_modules]
134134
targets = server.fine_grained_manager.processed_targets
135135

136-
assert_module_equivalence(
137-
'stale' + str(step - 1),
138-
testcase.expected_stale_modules.get(step - 1),
139-
changed)
140-
assert_module_equivalence(
141-
'rechecked' + str(step - 1),
142-
testcase.expected_rechecked_modules.get(step - 1),
143-
updated)
144-
assert_target_equivalence(
145-
'targets' + str(step),
146-
testcase.expected_fine_grained_targets.get(step),
147-
targets)
136+
expected_stale = testcase.expected_stale_modules.get(step - 1)
137+
if expected_stale is not None:
138+
assert_module_equivalence(
139+
'stale' + str(step - 1),
140+
expected_stale, changed)
141+
142+
expected_rechecked = testcase.expected_rechecked_modules.get(step - 1)
143+
if expected_rechecked is not None:
144+
assert_module_equivalence(
145+
'rechecked' + str(step - 1),
146+
expected_rechecked, updated)
147+
148+
expected = testcase.expected_fine_grained_targets.get(step)
149+
if expected:
150+
assert_target_equivalence(
151+
'targets' + str(step),
152+
expected, targets)
148153

149154
new_messages = normalize_messages(new_messages)
150155

test-data/unit/check-newsemanal.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3069,3 +3069,16 @@ class C:
30693069
def f(self) -> None: pass
30703070

30713071
Method() # E: Cannot instantiate abstract class 'Method' with abstract attribute 'f'
3072+
3073+
[case testModulesAndFuncsTargetsInCycle]
3074+
import a
3075+
[file a.py]
3076+
import b
3077+
defer: Yes
3078+
def func() -> int: ...
3079+
class Yes: ...
3080+
[file b.py]
3081+
import a
3082+
3083+
def func() -> int: ...
3084+
[targets a, b, a, b.func, a.func, __main__]

0 commit comments

Comments
 (0)