Skip to content

Add daemon mode -- highly experimental #4130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 42 commits into from
Oct 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f389250
Add dmypy: experimental daemon mode.
Oct 6, 2017
0108b64
Turn serving code into a class
Oct 7, 2017
97d6c6d
Tweaks to daemonize()
Oct 7, 2017
bfde4ac
Different approach to debugging. Different approach to running mypy.
Oct 8, 2017
9688716
Improve processing of file args
Oct 8, 2017
b4ede7d
Simplify command dispatch
Oct 8, 2017
6bf9c7e
Fix crash in validate_meta() when --skip-version-check given
Oct 9, 2017
f92c849
Small fixes
Oct 9, 2017
34fe874
Disallow report-generating options, --no-incremental, and --quick
Oct 9, 2017
6635e95
Save sources, not raw strings
Oct 9, 2017
5c3786a
Primitive tracing of os.stat() calls
Oct 11, 2017
68cc680
Save and reuse meta and tree
Oct 11, 2017
1f754b4
Revive self.meta when writing cache (hope this works)
Oct 11, 2017
9148acf
Fix mypy and lint errors
Oct 11, 2017
398d649
Tweak logging code
Oct 11, 2017
75a9a16
Delete saved cache entry; tweak log message
Oct 11, 2017
c221225
Added tests for dmypy (some still failing)
Oct 13, 2017
6739a06
Skip tests that specify varying flags/options
Oct 13, 2017
af6db88
Include incremental tests from other files (not many)
Oct 13, 2017
7cd4e44
Fix 6 test errors caused by not deleting meta for files with errors
Oct 13, 2017
cf0469e
Fix broken check for mypy.ini.* in has_stable_flags()
Oct 13, 2017
798b7e8
Don't compare options; it doesn't work right
Oct 13, 2017
d916f29
Revive cache verification after each test step
Oct 15, 2017
69de33a
Fix final two failing tests (it was wrong to delete the line 'self.me…
Oct 15, 2017
d4bcd07
Fix mypy errors; clean up file/socket better
Oct 15, 2017
f8034d3
New approach to instrumentation
Oct 16, 2017
a4d5d79
Add GC statistics (and increase GC threshold!)
Oct 16, 2017
657a55d
Report memory usage using getrusage() and psutil
Oct 16, 2017
b72c16d
Older Pythons don't load JSON from bytearray
Oct 16, 2017
9e0df24
Refactor status reading/reporting
Oct 16, 2017
fc663c8
Don't update all_types unless in a test
Oct 16, 2017
46ffbc7
Add -q/--quiet flag to suppress printing stats
Oct 17, 2017
81da5b1
When starting daemon, wait for child process and report status
Oct 17, 2017
80e60b0
Add support for daemon mode to misc/incremental_checker.py
Oct 18, 2017
2caaf0b
When starting daemon wait for it to be serving
Oct 18, 2017
808ac7f
Add testdmypy to PYTEST_FILES (fixes runtests.py)
Oct 18, 2017
e6b46ea
Skip dmypy tests on Windows
Oct 18, 2017
bc15106
Move 'import resource' into the function that uses it
Oct 18, 2017
c9bb0d1
Respond to code review (in some cases by adding a TODO)
Oct 19, 2017
517129d
Fix stricter mypy errors
Oct 19, 2017
ba827e2
Fix lint errors
Oct 19, 2017
626566b
Simplify bound_gc_callback
Oct 19, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 44 additions & 13 deletions misc/incremental_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
CACHE_PATH = ".incremental_checker_cache.json"
MYPY_REPO_URL = "https://github.com/python/mypy.git"
MYPY_TARGET_FILE = "mypy"
DAEMON_CMD = ["python3", "-m", "mypy.dmypy"]

JsonDict = Dict[str, Any]

Expand Down Expand Up @@ -121,23 +122,30 @@ def get_nth_commit(repo_folder_path, n: int) -> Tuple[str, str]:
def run_mypy(target_file_path: Optional[str],
mypy_cache_path: str,
mypy_script: Optional[str],
incremental: bool = True,
*,
incremental: bool = False,
daemon: bool = False,
verbose: bool = False) -> Tuple[float, str]:
"""Runs mypy against `target_file_path` and returns what mypy prints to stdout as a string.

If `incremental` is set to True, this function will use store and retrieve all caching data
inside `mypy_cache_path`. If `verbose` is set to True, this function will pass the "-v -v"
flags to mypy to make it output debugging information.

If `daemon` is True, we use daemon mode; the daemon must be started and stopped by the caller.
"""
if mypy_script is None:
command = ["python3", "-m", "mypy"]
if daemon:
command = DAEMON_CMD + ["check", "-q"]
else:
command = [mypy_script]
command.extend(["--cache-dir", mypy_cache_path])
if incremental:
command.append("--incremental")
if verbose:
command.extend(["-v", "-v"])
if mypy_script is None:
command = ["python3", "-m", "mypy"]
else:
command = [mypy_script]
command.extend(["--cache-dir", mypy_cache_path])
if incremental:
command.append("--incremental")
if verbose:
command.extend(["-v", "-v"])
if target_file_path is not None:
command.append(target_file_path)
start = time.time()
Expand All @@ -148,6 +156,21 @@ def run_mypy(target_file_path: Optional[str],
return runtime, output


def start_daemon(mypy_cache_path: str, verbose: bool) -> None:
stdout, stderr, status = execute(DAEMON_CMD + ["status"], fail_on_error=False)
if status:
cmd = DAEMON_CMD + ["start", "--", "--cache-dir", mypy_cache_path]
if verbose:
cmd.extend(["-v", "-v"])
execute(cmd)


def stop_daemon() -> None:
stdout, stderr, status = execute(DAEMON_CMD + ["status"], fail_on_error=False)
if status == 0:
execute(DAEMON_CMD + ["stop"])


def load_cache(incremental_cache_path: str = CACHE_PATH) -> JsonDict:
if os.path.exists(incremental_cache_path):
with open(incremental_cache_path, 'r') as stream:
Expand Down Expand Up @@ -196,7 +219,9 @@ def test_incremental(commits: List[Tuple[str, str]],
temp_repo_path: str,
target_file_path: Optional[str],
mypy_cache_path: str,
mypy_script: Optional[str]) -> None:
*,
mypy_script: Optional[str] = None,
daemon: bool = False) -> None:
"""Runs incremental mode on all `commits` to verify the output matches the expected output.

This function runs mypy on the `target_file_path` inside the `temp_repo_path`. The
Expand All @@ -208,7 +233,7 @@ def test_incremental(commits: List[Tuple[str, str]],
print('Now testing commit {0}: "{1}"'.format(commit_id, message))
execute(["git", "-C", temp_repo_path, "checkout", commit_id])
runtime, output = run_mypy(target_file_path, mypy_cache_path, mypy_script,
incremental=True)
incremental=True, daemon=daemon)
expected_runtime = cache[commit_id]['runtime'] # type: float
expected_output = cache[commit_id]['output'] # type: str
if output != expected_output:
Expand Down Expand Up @@ -278,11 +303,15 @@ def test_repo(target_repo_url: str, temp_repo_path: str,
save_cache(cache, incremental_cache_path)

# Stage 4: Rewind and re-run mypy (with incremental mode enabled)
if params.daemon:
start_daemon(mypy_cache_path, False)
test_incremental(commits, cache, temp_repo_path, target_file_path, mypy_cache_path,
mypy_script=params.mypy_script)
mypy_script=params.mypy_script, daemon=params.daemon)

# Stage 5: Remove temp files
# Stage 5: Remove temp files, stop daemon
cleanup(temp_repo_path, mypy_cache_path)
if params.daemon:
stop_daemon()


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

if len(sys.argv[1:]) == 0:
parser.print_help()
Expand Down
Loading