Skip to content

Commit 6d24777

Browse files
committed
Support loading from cache in fine-grained incremental mdoe
1 parent e05fe58 commit 6d24777

File tree

5 files changed

+36
-8
lines changed

5 files changed

+36
-8
lines changed

mypy/build.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,6 +2371,13 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
23712371
manager.log("Processing SCC of size %d (%s) as %s" % (size, scc_str, fresh_msg))
23722372
process_stale_scc(graph, scc, manager)
23732373

2374+
# If we are running in fine-grained incremental mode with caching,
2375+
# we need to always process fresh SCCs.
2376+
if manager.options.use_fine_grained_cache:
2377+
for prev_scc in fresh_scc_queue:
2378+
process_fresh_scc(graph, prev_scc, manager)
2379+
fresh_scc_queue = []
2380+
23742381
sccs_left = len(fresh_scc_queue)
23752382
nodes_left = sum(len(scc) for scc in fresh_scc_queue)
23762383
manager.add_stats(sccs_left=sccs_left, nodes_left=nodes_left)

mypy/dmypy_server.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,16 @@ def __init__(self, flags: List[str]) -> None:
9999
sys.exit("dmypy: start/restart should not disable incremental mode")
100100
if options.quick_and_dirty:
101101
sys.exit("dmypy: start/restart should not specify quick_and_dirty mode")
102+
if options.use_fine_grained_cache and not options.fine_grained_incremental:
103+
sys.exit("dmypy: fine-grained cache can only be used in experimental mode")
102104
self.options = options
103105
if os.path.isfile(STATUS_FILE):
104106
os.unlink(STATUS_FILE)
105107
if self.fine_grained:
106108
options.incremental = True
107109
options.show_traceback = True
108-
options.cache_dir = os.devnull
110+
if not options.use_fine_grained_cache:
111+
options.cache_dir = os.devnull
109112

110113
def serve(self) -> None:
111114
"""Serve requests, synchronously (no thread or fork)."""

mypy/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ def add_invertible_flag(flag: str,
395395
if server_options:
396396
parser.add_argument('--experimental', action='store_true', dest='fine_grained_incremental',
397397
help="enable fine-grained incremental mode")
398+
parser.add_argument('--use-fine-grained-cache', action='store_true',
399+
help="use the cache in fine-grained incremental mode")
398400

399401
report_group = parser.add_argument_group(
400402
title='report generation',

mypy/options.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ def __init__(self) -> None:
144144
self.skip_version_check = False
145145
self.fine_grained_incremental = False
146146
self.cache_fine_grained = False
147+
self.use_fine_grained_cache = False
147148

148149
# Paths of user plugins
149150
self.plugins = [] # type: List[str]

mypy/server/update.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,10 @@ def update_single(self, module: str, path: str) -> Tuple[List[str],
281281
print('triggered:', sorted(filtered))
282282
self.triggered.extend(triggered | self.previous_targets_with_errors)
283283
collect_dependencies({module: tree}, self.deps, graph)
284-
propagate_changes_using_dependencies(manager, graph, self.deps, triggered,
285-
{module},
286-
self.previous_targets_with_errors)
284+
remaining += propagate_changes_using_dependencies(
285+
manager, graph, self.deps, triggered,
286+
{module},
287+
self.previous_targets_with_errors)
287288

288289
# Preserve state needed for the next update.
289290
self.previous_targets_with_errors = manager.errors.targets()
@@ -318,6 +319,9 @@ def mark_all_meta_as_memory_only(graph: Dict[str, State],
318319
def get_all_dependencies(manager: BuildManager, graph: Dict[str, State],
319320
options: Options) -> Dict[str, Set[str]]:
320321
"""Return the fine-grained dependency map for an entire build."""
322+
if not options.use_fine_grained_cache:
323+
for state in graph.values():
324+
state.compute_fine_grained_deps()
321325
deps = {} # type: Dict[str, Set[str]]
322326
collect_dependencies(manager.modules, deps, graph)
323327
return deps
@@ -441,6 +445,7 @@ def update_single_isolated(module: str,
441445
# Perform type checking.
442446
state.type_check_first_pass()
443447
state.type_check_second_pass()
448+
state.compute_fine_grained_deps()
444449
state.finish_passes()
445450
# TODO: state.write_cache()?
446451
# TODO: state.mark_as_rechecked()?
@@ -650,7 +655,6 @@ def collect_dependencies(new_modules: Mapping[str, Optional[MypyFile]],
650655
for id, node in new_modules.items():
651656
if node is None:
652657
continue
653-
graph[id].compute_fine_grained_deps()
654658
for trigger, targets in graph[id].fine_grained_deps.items():
655659
deps.setdefault(trigger, set()).update(targets)
656660

@@ -707,9 +711,10 @@ def propagate_changes_using_dependencies(
707711
deps: Dict[str, Set[str]],
708712
triggered: Set[str],
709713
up_to_date_modules: Set[str],
710-
targets_with_errors: Set[str]) -> None:
714+
targets_with_errors: Set[str]) -> List[Tuple[str, str]]:
711715
# TODO: Multiple type checking passes
712716
num_iter = 0
717+
remaining_modules = []
713718

714719
# Propagate changes until nothing visible has changed during the last
715720
# iteration.
@@ -733,7 +738,13 @@ def propagate_changes_using_dependencies(
733738
# TODO: Preserve order (set is not optimal)
734739
for id, nodes in sorted(todo.items(), key=lambda x: x[0]):
735740
assert id not in up_to_date_modules
736-
triggered |= reprocess_nodes(manager, graph, id, nodes, deps)
741+
# TODO: Is there a better way to detect that the file isn't loaded?
742+
if not manager.modules[id].defs:
743+
# We haven't actually loaded this file! Add it to the
744+
# queue of files that need to be processed fully.
745+
remaining_modules.append((id, manager.modules[id].path))
746+
else:
747+
triggered |= reprocess_nodes(manager, graph, id, nodes, deps)
737748
# Changes elsewhere may require us to reprocess modules that were
738749
# previously considered up to date. For example, there may be a
739750
# dependency loop that loops back to an originally processed module.
@@ -742,6 +753,8 @@ def propagate_changes_using_dependencies(
742753
if DEBUG:
743754
print('triggered:', list(triggered))
744755

756+
return remaining_modules
757+
745758

746759
def find_targets_recursive(
747760
triggers: Set[str],
@@ -989,4 +1002,6 @@ def lookup_target(modules: Dict[str, MypyFile], target: str) -> List[DeferredNod
9891002

9901003

9911004
def extract_type_maps(graph: Graph) -> Dict[str, Dict[Expression, Type]]:
992-
return {id: state.type_map() for id, state in graph.items()}
1005+
# This is used to export information used only by the testmerge harness.
1006+
return {id: state.type_map() for id, state in graph.items()
1007+
if state.tree}

0 commit comments

Comments
 (0)