Skip to content

Commit 2dbeaf7

Browse files
gvanrossumJukkaL
authored andcommitted
Add daemon mode -- highly experimental (#4130)
Add dmypy: experimental daemon mode. In this mode mypy keeps the ASTs from previous incremental runs in memory so that successive runs can be much faster by reusing previous ATSs for some modules that have no changed dependencies.
1 parent 1673e27 commit 2dbeaf7

File tree

9 files changed

+1154
-83
lines changed

9 files changed

+1154
-83
lines changed

misc/incremental_checker.py

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
CACHE_PATH = ".incremental_checker_cache.json"
5050
MYPY_REPO_URL = "https://github.com/python/mypy.git"
5151
MYPY_TARGET_FILE = "mypy"
52+
DAEMON_CMD = ["python3", "-m", "mypy.dmypy"]
5253

5354
JsonDict = Dict[str, Any]
5455

@@ -121,23 +122,30 @@ def get_nth_commit(repo_folder_path, n: int) -> Tuple[str, str]:
121122
def run_mypy(target_file_path: Optional[str],
122123
mypy_cache_path: str,
123124
mypy_script: Optional[str],
124-
incremental: bool = True,
125+
*,
126+
incremental: bool = False,
127+
daemon: bool = False,
125128
verbose: bool = False) -> Tuple[float, str]:
126129
"""Runs mypy against `target_file_path` and returns what mypy prints to stdout as a string.
127130
128131
If `incremental` is set to True, this function will use store and retrieve all caching data
129132
inside `mypy_cache_path`. If `verbose` is set to True, this function will pass the "-v -v"
130133
flags to mypy to make it output debugging information.
134+
135+
If `daemon` is True, we use daemon mode; the daemon must be started and stopped by the caller.
131136
"""
132-
if mypy_script is None:
133-
command = ["python3", "-m", "mypy"]
137+
if daemon:
138+
command = DAEMON_CMD + ["check", "-q"]
134139
else:
135-
command = [mypy_script]
136-
command.extend(["--cache-dir", mypy_cache_path])
137-
if incremental:
138-
command.append("--incremental")
139-
if verbose:
140-
command.extend(["-v", "-v"])
140+
if mypy_script is None:
141+
command = ["python3", "-m", "mypy"]
142+
else:
143+
command = [mypy_script]
144+
command.extend(["--cache-dir", mypy_cache_path])
145+
if incremental:
146+
command.append("--incremental")
147+
if verbose:
148+
command.extend(["-v", "-v"])
141149
if target_file_path is not None:
142150
command.append(target_file_path)
143151
start = time.time()
@@ -148,6 +156,21 @@ def run_mypy(target_file_path: Optional[str],
148156
return runtime, output
149157

150158

159+
def start_daemon(mypy_cache_path: str, verbose: bool) -> None:
160+
stdout, stderr, status = execute(DAEMON_CMD + ["status"], fail_on_error=False)
161+
if status:
162+
cmd = DAEMON_CMD + ["start", "--", "--cache-dir", mypy_cache_path]
163+
if verbose:
164+
cmd.extend(["-v", "-v"])
165+
execute(cmd)
166+
167+
168+
def stop_daemon() -> None:
169+
stdout, stderr, status = execute(DAEMON_CMD + ["status"], fail_on_error=False)
170+
if status == 0:
171+
execute(DAEMON_CMD + ["stop"])
172+
173+
151174
def load_cache(incremental_cache_path: str = CACHE_PATH) -> JsonDict:
152175
if os.path.exists(incremental_cache_path):
153176
with open(incremental_cache_path, 'r') as stream:
@@ -196,7 +219,9 @@ def test_incremental(commits: List[Tuple[str, str]],
196219
temp_repo_path: str,
197220
target_file_path: Optional[str],
198221
mypy_cache_path: str,
199-
mypy_script: Optional[str]) -> None:
222+
*,
223+
mypy_script: Optional[str] = None,
224+
daemon: bool = False) -> None:
200225
"""Runs incremental mode on all `commits` to verify the output matches the expected output.
201226
202227
This function runs mypy on the `target_file_path` inside the `temp_repo_path`. The
@@ -208,7 +233,7 @@ def test_incremental(commits: List[Tuple[str, str]],
208233
print('Now testing commit {0}: "{1}"'.format(commit_id, message))
209234
execute(["git", "-C", temp_repo_path, "checkout", commit_id])
210235
runtime, output = run_mypy(target_file_path, mypy_cache_path, mypy_script,
211-
incremental=True)
236+
incremental=True, daemon=daemon)
212237
expected_runtime = cache[commit_id]['runtime'] # type: float
213238
expected_output = cache[commit_id]['output'] # type: str
214239
if output != expected_output:
@@ -278,11 +303,15 @@ def test_repo(target_repo_url: str, temp_repo_path: str,
278303
save_cache(cache, incremental_cache_path)
279304

280305
# Stage 4: Rewind and re-run mypy (with incremental mode enabled)
306+
if params.daemon:
307+
start_daemon(mypy_cache_path, False)
281308
test_incremental(commits, cache, temp_repo_path, target_file_path, mypy_cache_path,
282-
mypy_script=params.mypy_script)
309+
mypy_script=params.mypy_script, daemon=params.daemon)
283310

284-
# Stage 5: Remove temp files
311+
# Stage 5: Remove temp files, stop daemon
285312
cleanup(temp_repo_path, mypy_cache_path)
313+
if params.daemon:
314+
stop_daemon()
286315

287316

288317
def main() -> None:
@@ -309,6 +338,8 @@ def main() -> None:
309338
parser.add_argument("--sample", type=int, help="use a random sample of size SAMPLE")
310339
parser.add_argument("--seed", type=str, help="random seed")
311340
parser.add_argument("--mypy-script", type=str, help="alternate mypy script to run")
341+
parser.add_argument("--daemon", action='store_true',
342+
help="use mypy daemon instead of incremental (highly experimental)")
312343

313344
if len(sys.argv[1:]) == 0:
314345
parser.print_help()

0 commit comments

Comments
 (0)