Skip to content

Commit f9f7fd6

Browse files
committed
Fix --no-pretty injection for dmypy commands without -- separator
The previous logic incorrectly appended --no-pretty after -- for all dmypy commands (like dmypy check), which caused --no-pretty to be treated as a filename. It also appended "-- --no-pretty" to dmypy run commands without --, which argparse rejected. Fix by: 1. Only injecting --no-pretty for dmypy run/start (not check/recheck) 2. For dmypy run/start without --, properly parse out dmypy-specific flags and reconstruct the command with -- separator so --no-pretty goes into the mypy flags portion.
1 parent cc0e97b commit f9f7fd6

File tree

1 file changed

+62
-4
lines changed

1 file changed

+62
-4
lines changed

mypy/test/testdaemon.py

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from __future__ import annotations
99

1010
import os
11+
import re
1112
import subprocess
1213
import sys
1314
import tempfile
@@ -76,19 +77,76 @@ def parse_script(input: list[str]) -> list[list[str]]:
7677
return steps
7778

7879

80+
def _add_no_pretty_to_dmypy(input: str) -> str:
81+
"""Add --no-pretty to a dmypy run/start command that has no -- separator.
82+
83+
For dmypy run/start, mypy flags are passed as positional args after --.
84+
When the command has no --, we need to insert -- before the positional args
85+
and append --no-pretty. We must keep any dmypy-specific named flags
86+
(like --export-types, --log-file FILE) before the -- separator.
87+
"""
88+
# Match: "dmypy run" or "dmypy start", then the rest of the args
89+
m = re.match(r"(dmypy (?:run|start))\s*(.*)", input)
90+
if not m:
91+
return input
92+
prefix = m.group(1)
93+
rest = m.group(2)
94+
95+
# Known dmypy run/start flags that take no value
96+
no_value_flags = {"--export-types", "--verbose", "-v"}
97+
# Known dmypy run/start flags that take a value
98+
value_flags = {"--log-file", "--timeout", "--junit-xml", "--perf-stats-file"}
99+
100+
parts = rest.split()
101+
dmypy_flags: list[str] = []
102+
positional: list[str] = []
103+
i = 0
104+
while i < len(parts):
105+
if parts[i] in no_value_flags:
106+
dmypy_flags.append(parts[i])
107+
i += 1
108+
elif parts[i] in value_flags:
109+
dmypy_flags.append(parts[i])
110+
if i + 1 < len(parts):
111+
dmypy_flags.append(parts[i + 1])
112+
i += 2
113+
elif parts[i].startswith("-") and "=" in parts[i]:
114+
# Handle --flag=value style for known flags
115+
flag_name = parts[i].split("=")[0]
116+
if flag_name in value_flags:
117+
dmypy_flags.append(parts[i])
118+
else:
119+
positional.append(parts[i])
120+
i += 1
121+
else:
122+
positional.append(parts[i])
123+
i += 1
124+
125+
dmypy_part = " ".join(dmypy_flags)
126+
positional_part = " ".join(positional)
127+
result = prefix
128+
if dmypy_part:
129+
result += " " + dmypy_part
130+
result += " -- "
131+
if positional_part:
132+
result += positional_part + " "
133+
result += "--no-pretty"
134+
return result
135+
136+
79137
def run_cmd(input: str) -> tuple[int, str]:
80138
if input[1:].startswith("mypy run --") and "--show-error-codes" not in input:
81139
input += " --hide-error-codes"
82140
if "--pretty" not in input:
83-
if input.startswith("dmypy ") and " -- " in input:
84-
# For dmypy commands, mypy flags come after --, so append at end
141+
if input.startswith(("dmypy run ", "dmypy start")) and " -- " in input:
142+
# For dmypy run/start, mypy flags come after --, so append at end
85143
input += " --no-pretty"
86144
elif input.startswith("mypy ") and " -- " in input:
87145
# For mypy commands, options come before --, so insert before --
88146
input = input.replace(" -- ", " --no-pretty -- ", 1)
89147
elif input.startswith(("dmypy run ", "dmypy start")):
90-
# dmypy commands without -- need the separator added
91-
input += " -- --no-pretty"
148+
# dmypy run/start without -- need the separator added
149+
input = _add_no_pretty_to_dmypy(input)
92150
elif input.startswith("mypy "):
93151
input += " --no-pretty"
94152
if input.startswith("dmypy "):

0 commit comments

Comments
 (0)