Skip to content

Commit e2ddfc3

Browse files
Lukas Geigerclaude
andcommitted
fix: use parse_known_args and detect flake8/pylint via python -m
parse_cli_args now uses parse_known_args so unrecognized arguments (Qt flags, etc.) pass through instead of hard-exiting. LinterRunner detects flake8/pylint via python -m fallback when not in PATH. Added 6 unit tests for CLI arg parsing and real flake8 verification. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3fe9390 commit e2ddfc3

2 files changed

Lines changed: 77 additions & 5 deletions

File tree

PythonBox_v8.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,10 @@ def parse_cli_args(argv: Optional[List[str]] = None) -> argparse.Namespace:
210210
parser.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS,
211211
help="Diese Hilfe anzeigen")
212212

213-
args = parser.parse_args(sys.argv[1:] if argv is None else argv)
213+
args, remaining = parser.parse_known_args(sys.argv[1:] if argv is None else argv)
214214
if args.open is None and args.file:
215215
args.open = args.file
216+
args._remaining = remaining
216217
return args
217218

218219

@@ -1237,6 +1238,26 @@ def _check_available_linters(self):
12371238
"""Prüft welche Linter verfügbar sind"""
12381239
self.has_pylint = shutil.which("pylint") is not None
12391240
self.has_flake8 = shutil.which("flake8") is not None
1241+
if not self.has_flake8:
1242+
try:
1243+
subprocess.run([sys.executable, "-m", "flake8", "--version"],
1244+
capture_output=True, timeout=5)
1245+
self.has_flake8 = True
1246+
self._flake8_via_module = True
1247+
except Exception:
1248+
self._flake8_via_module = False
1249+
else:
1250+
self._flake8_via_module = False
1251+
if not self.has_pylint:
1252+
try:
1253+
subprocess.run([sys.executable, "-m", "pylint", "--version"],
1254+
capture_output=True, timeout=5)
1255+
self.has_pylint = True
1256+
self._pylint_via_module = True
1257+
except Exception:
1258+
self._pylint_via_module = False
1259+
else:
1260+
self._pylint_via_module = False
12401261

12411262
def run_linter(self, code: str, file_path: Optional[str] = None) -> List[Dict]:
12421263
"""Führt Linter aus und gibt Ergebnisse zurück"""
@@ -1271,8 +1292,10 @@ def _run_flake8(self, file_path: str) -> List[Dict]:
12711292
"""Führt Flake8 aus"""
12721293
results = []
12731294
try:
1295+
cmd = ([sys.executable, "-m", "flake8"] if getattr(self, '_flake8_via_module', False)
1296+
else ["flake8"])
12741297
proc = subprocess.run(
1275-
["flake8", "--format=%(row)d:%(col)d:%(code)s:%(text)s", file_path],
1298+
[*cmd, "--format=%(row)d:%(col)d:%(code)s:%(text)s", file_path],
12761299
capture_output=True, text=True, timeout=10
12771300
)
12781301

@@ -1299,8 +1322,10 @@ def _run_pylint(self, file_path: str) -> List[Dict]:
12991322
"""Führt Pylint aus"""
13001323
results = []
13011324
try:
1325+
cmd = ([sys.executable, "-m", "pylint"] if getattr(self, '_pylint_via_module', False)
1326+
else ["pylint"])
13021327
proc = subprocess.run(
1303-
["pylint", "--output-format=text", "--msg-template={line}:{column}:{msg_id}:{msg}",
1328+
[*cmd, "--output-format=text", "--msg-template={line}:{column}:{msg_id}:{msg}",
13041329
file_path],
13051330
capture_output=True, text=True, timeout=30
13061331
)
@@ -4137,9 +4162,8 @@ def main(argv: Optional[List[str]] = None):
41374162
if args.lint:
41384163
sys.exit(run_lint_cli(args.lint))
41394164

4140-
cli_args = list(sys.argv[1:] if argv is None else argv)
41414165
startup_file = args.open
4142-
app = QApplication([sys.argv[0], *cli_args])
4166+
app = QApplication([sys.argv[0]] + args._remaining)
41434167
icon_path = Path(__file__).with_name("PythonBox.ico")
41444168
icon = QIcon(str(icon_path)) if icon_path.exists() else QIcon()
41454169
if not icon.isNull():

tests/test_cli_lint.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
ROOT = Path(__file__).resolve().parents[1]
99
SCRIPT = ROOT / "PythonBox_v8.py"
10+
sys.path.insert(0, str(ROOT))
11+
from PythonBox_v8 import parse_cli_args
1012

1113

1214
def run_lint(target: str, timeout: int = 30) -> subprocess.CompletedProcess:
@@ -80,5 +82,51 @@ def test_no_gui_started(self):
8082
os.unlink(path)
8183

8284

85+
class TestParseCLIArgs(unittest.TestCase):
86+
87+
def test_open_flag(self):
88+
args = parse_cli_args(["--open", "test.py"])
89+
self.assertEqual(args.open, "test.py")
90+
self.assertIsNone(args.lint)
91+
92+
def test_lint_flag(self):
93+
args = parse_cli_args(["--lint", "test.py"])
94+
self.assertEqual(args.lint, "test.py")
95+
self.assertIsNone(args.open)
96+
97+
def test_positional_file(self):
98+
args = parse_cli_args(["test.py"])
99+
self.assertEqual(args.open, "test.py")
100+
self.assertIsNone(args.lint)
101+
102+
def test_no_args(self):
103+
args = parse_cli_args([])
104+
self.assertIsNone(args.open)
105+
self.assertIsNone(args.lint)
106+
107+
def test_unknown_args_preserved(self):
108+
args = parse_cli_args(["--open", "test.py", "-style", "fusion"])
109+
self.assertEqual(args.open, "test.py")
110+
self.assertIn("-style", args._remaining)
111+
112+
def test_lint_with_real_flake8(self):
113+
with tempfile.NamedTemporaryFile(suffix=".py", mode="w",
114+
encoding="utf-8", delete=False) as f:
115+
f.write("import os\nimport os\n")
116+
f.flush()
117+
path = f.name
118+
try:
119+
result = run_lint(path)
120+
if result.returncode == 1:
121+
lines = result.stdout.strip().split("\n")
122+
finding_lines = [l for l in lines if path in l]
123+
self.assertTrue(len(finding_lines) > 0,
124+
"flake8 should find duplicate import")
125+
for line in finding_lines:
126+
self.assertRegex(line, r".+:\d+:\d+: \S+ .+")
127+
finally:
128+
os.unlink(path)
129+
130+
83131
if __name__ == "__main__":
84132
unittest.main()

0 commit comments

Comments
 (0)