|
42 | 42 | MEM_PROFILE = False # type: Final # If True, dump memory profile after initialization
|
43 | 43 |
|
44 | 44 | if sys.platform == 'win32':
|
| 45 | + from subprocess import STARTUPINFO |
| 46 | + |
45 | 47 | def daemonize(options: Options,
|
46 | 48 | timeout: Optional[int] = None,
|
47 | 49 | log_file: Optional[str] = None) -> int:
|
48 | 50 | """Create the daemon process via "dmypy daemon" and pass options via command line
|
49 | 51 |
|
50 |
| - This uses the DETACHED_PROCESS flag to invoke the Server. |
51 |
| - See https://docs.microsoft.com/en-us/windows/desktop/procthread/process-creation-flags |
| 52 | + When creating the daemon grandchild, we create it in a new console, which is |
| 53 | + started hidden. We cannot use DETACHED_PROCESS since it will cause console windows |
| 54 | + to pop up when starting. See |
| 55 | + https://github.com/python/cpython/pull/4150#issuecomment-340215696 |
| 56 | + for more on why we can't have nice things. |
52 | 57 |
|
53 | 58 | It also pickles the options to be unpickled by mypy.
|
54 | 59 | """
|
55 | 60 | command = [sys.executable, '-m', 'mypy.dmypy', 'daemon']
|
56 | 61 | pickeled_options = pickle.dumps((options.snapshot(), timeout, log_file))
|
57 | 62 | command.append('--options-data="{}"'.format(base64.b64encode(pickeled_options).decode()))
|
| 63 | + info = STARTUPINFO(dwFlags=0x1, # STARTF_USESHOWWINDOW aka use wShowWindow's value |
| 64 | + wShowWindow=0, # SW_HIDE aka make the window invisible |
| 65 | + ) |
58 | 66 | try:
|
59 |
| - subprocess.Popen(command, creationflags=0x8) # DETACHED_PROCESS |
| 67 | + subprocess.Popen(command, |
| 68 | + creationflags=0x10, # CREATE_NEW_CONSOLE |
| 69 | + startupinfo=info) |
60 | 70 | return 0
|
61 | 71 | except subprocess.CalledProcessError as e:
|
62 | 72 | return e.returncode
|
|
0 commit comments