Skip to content

Commit 22918dc

Browse files
committed
Support loading from cache in fine-grained incremental mdoe
1 parent 477f85a commit 22918dc

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
@@ -2383,6 +2383,13 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
23832383
manager.log("Processing SCC of size %d (%s) as %s" % (size, scc_str, fresh_msg))
23842384
process_stale_scc(graph, scc, manager)
23852385

2386+
# If we are running in fine-grained incremental mode with caching,
2387+
# we need to always process fresh SCCs.
2388+
if manager.options.use_fine_grained_cache:
2389+
for prev_scc in fresh_scc_queue:
2390+
process_fresh_scc(graph, prev_scc, manager)
2391+
fresh_scc_queue = []
2392+
23862393
sccs_left = len(fresh_scc_queue)
23872394
nodes_left = sum(len(scc) for scc in fresh_scc_queue)
23882395
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()?
@@ -654,7 +659,6 @@ def collect_dependencies(new_modules: Mapping[str, Optional[MypyFile]],
654659
for id, node in new_modules.items():
655660
if node is None:
656661
continue
657-
graph[id].compute_fine_grained_deps()
658662
for trigger, targets in graph[id].fine_grained_deps.items():
659663
deps.setdefault(trigger, set()).update(targets)
660664

@@ -711,9 +715,10 @@ def propagate_changes_using_dependencies(
711715
deps: Dict[str, Set[str]],
712716
triggered: Set[str],
713717
up_to_date_modules: Set[str],
714-
targets_with_errors: Set[str]) -> None:
718+
targets_with_errors: Set[str]) -> List[Tuple[str, str]]:
715719
# TODO: Multiple type checking passes
716720
num_iter = 0
721+
remaining_modules = []
717722

718723
# Propagate changes until nothing visible has changed during the last
719724
# iteration.
@@ -737,7 +742,13 @@ def propagate_changes_using_dependencies(
737742
# TODO: Preserve order (set is not optimal)
738743
for id, nodes in sorted(todo.items(), key=lambda x: x[0]):
739744
assert id not in up_to_date_modules
740-
triggered |= reprocess_nodes(manager, graph, id, nodes, deps)
745+
# TODO: Is there a better way to detect that the file isn't loaded?
746+
if not manager.modules[id].defs:
747+
# We haven't actually loaded this file! Add it to the
748+
# queue of files that need to be processed fully.
749+
remaining_modules.append((id, manager.modules[id].path))
750+
else:
751+
triggered |= reprocess_nodes(manager, graph, id, nodes, deps)
741752
# Changes elsewhere may require us to reprocess modules that were
742753
# previously considered up to date. For example, there may be a
743754
# dependency loop that loops back to an originally processed module.
@@ -746,6 +757,8 @@ def propagate_changes_using_dependencies(
746757
if DEBUG:
747758
print('triggered:', list(triggered))
748759

760+
return remaining_modules
761+
749762

750763
def find_targets_recursive(
751764
triggers: Set[str],
@@ -993,4 +1006,6 @@ def lookup_target(modules: Dict[str, MypyFile], target: str) -> List[DeferredNod
9931006

9941007

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

0 commit comments

Comments
 (0)