python-linters 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_linters-0.2.0 → python_linters-0.2.1}/PKG-INFO +1 -1
- {python_linters-0.2.0 → python_linters-0.2.1}/pyproject.toml +1 -1
- {python_linters-0.2.0 → python_linters-0.2.1}/pyproject.toml.orig +1 -1
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/config_check.py +40 -13
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/lint_report.py +30 -5
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/references/ruff.reference.toml +19 -9
- {python_linters-0.2.0 → python_linters-0.2.1}/README.md +0 -0
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/__init__.py +0 -0
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/__main__.py +0 -0
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/cli_commands.py +0 -0
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/reference_files.py +0 -0
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/references/ty.reference.toml +0 -0
- {python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/tool_errors.py +0 -0
|
@@ -169,7 +169,9 @@ def _covers_rule(
|
|
|
169
169
|
return False
|
|
170
170
|
if selector in meta_prefixes:
|
|
171
171
|
return True
|
|
172
|
-
selector_linters = {
|
|
172
|
+
selector_linters = {
|
|
173
|
+
r["linter"] for r in rules if r["code"] and r["code"].startswith(selector)
|
|
174
|
+
}
|
|
173
175
|
return selector_linters == {linter}
|
|
174
176
|
|
|
175
177
|
|
|
@@ -221,9 +223,14 @@ def _get_new_categories(
|
|
|
221
223
|
for prefix, linter in sorted(categories.items()):
|
|
222
224
|
if any(_covers(k, prefix, category_linters, meta_prefixes) for k in known):
|
|
223
225
|
continue
|
|
224
|
-
prefix_rules = [
|
|
226
|
+
prefix_rules = [
|
|
227
|
+
r for r in rules if r["code"] and r["code"].rstrip(string.digits) == prefix
|
|
228
|
+
]
|
|
225
229
|
if all(
|
|
226
|
-
any(
|
|
230
|
+
any(
|
|
231
|
+
_covers_rule(k, r["code"], r["linter"], rules, meta_prefixes)
|
|
232
|
+
for k in known
|
|
233
|
+
)
|
|
227
234
|
for r in prefix_rules
|
|
228
235
|
):
|
|
229
236
|
continue
|
|
@@ -255,9 +262,13 @@ def check_ruff_config(toml_path: Path) -> RuffConfigCheck:
|
|
|
255
262
|
commented = _parse_toml_comments(toml_path)
|
|
256
263
|
|
|
257
264
|
known = selected | commented
|
|
258
|
-
meta_prefixes = {"PL"} | {
|
|
265
|
+
meta_prefixes = {"PL"} | {
|
|
266
|
+
p for p, linters in category_linters.items() if len(linters) > 1
|
|
267
|
+
}
|
|
259
268
|
|
|
260
|
-
new_categories = _get_new_categories(
|
|
269
|
+
new_categories = _get_new_categories(
|
|
270
|
+
rules, categories, category_linters, known, meta_prefixes
|
|
271
|
+
)
|
|
261
272
|
removed = _get_removed(rules, selected)
|
|
262
273
|
|
|
263
274
|
untriaged_codeless = [n for n in _get_codeless_rules(rules) if n not in known]
|
|
@@ -293,24 +304,36 @@ def format_ruff_report(toml_path: Path, check: RuffConfigCheck) -> str:
|
|
|
293
304
|
if check.new_categories:
|
|
294
305
|
lines.append(f"NEW categories not yet triaged ({len(check.new_categories)}):")
|
|
295
306
|
lines.append(" Add to select or comment out with '# excluded' in ruff.toml:\n")
|
|
296
|
-
lines.extend(
|
|
307
|
+
lines.extend(
|
|
308
|
+
f' "{prefix}",\t# {linter}' for prefix, linter in check.new_categories
|
|
309
|
+
)
|
|
297
310
|
lines.append("")
|
|
298
311
|
|
|
299
312
|
if check.removed:
|
|
300
|
-
lines.append(
|
|
313
|
+
lines.append(
|
|
314
|
+
f"REMOVED/RENAMED categories still in select ({len(check.removed)}):"
|
|
315
|
+
)
|
|
301
316
|
lines.extend(f" {code}" for code in check.removed)
|
|
302
317
|
lines.append("")
|
|
303
318
|
|
|
304
319
|
if check.untriaged_codeless:
|
|
305
|
-
lines.append(
|
|
306
|
-
|
|
320
|
+
lines.append(
|
|
321
|
+
f"Code-less rules not yet triaged ({len(check.untriaged_codeless)}):"
|
|
322
|
+
)
|
|
323
|
+
lines.append(
|
|
324
|
+
" Add to select by name or comment out with '# excluded' in ruff.toml:\n"
|
|
325
|
+
)
|
|
307
326
|
lines.extend(f' "{name}",' for name in check.untriaged_codeless)
|
|
308
327
|
lines.append("")
|
|
309
328
|
|
|
310
329
|
if check.untriaged_preview:
|
|
311
330
|
lines.append(f"Preview rules not yet triaged ({len(check.untriaged_preview)}):")
|
|
312
|
-
lines.append(
|
|
313
|
-
|
|
331
|
+
lines.append(
|
|
332
|
+
" Add to select by name or cover with an '# excluded' line in ruff.toml:\n"
|
|
333
|
+
)
|
|
334
|
+
lines.extend(
|
|
335
|
+
f' "{name}",\t# {code}' for code, name in check.untriaged_preview
|
|
336
|
+
)
|
|
314
337
|
lines.append("")
|
|
315
338
|
|
|
316
339
|
if check.is_clean:
|
|
@@ -395,7 +418,9 @@ def format_ty_report(config_path: Path, check: TyConfigCheck) -> str:
|
|
|
395
418
|
]
|
|
396
419
|
|
|
397
420
|
if check.untriaged:
|
|
398
|
-
lines.append(
|
|
421
|
+
lines.append(
|
|
422
|
+
f"UNTRIAGED rules ty knows that the config omits ({len(check.untriaged)}):"
|
|
423
|
+
)
|
|
399
424
|
lines.extend(
|
|
400
425
|
f' {name} = "???" # default: {check.default_levels[name]}'
|
|
401
426
|
for name in check.untriaged
|
|
@@ -403,7 +428,9 @@ def format_ty_report(config_path: Path, check: TyConfigCheck) -> str:
|
|
|
403
428
|
lines.append("")
|
|
404
429
|
|
|
405
430
|
if check.stale:
|
|
406
|
-
lines.append(
|
|
431
|
+
lines.append(
|
|
432
|
+
f"STALE rules named in config that ty no longer knows ({len(check.stale)}):"
|
|
433
|
+
)
|
|
407
434
|
lines.extend(f" {name}" for name in check.stale)
|
|
408
435
|
lines.append("")
|
|
409
436
|
|
|
@@ -61,7 +61,12 @@ class Location:
|
|
|
61
61
|
message: str
|
|
62
62
|
|
|
63
63
|
def to_dict(self) -> dict[str, object]:
|
|
64
|
-
return {
|
|
64
|
+
return {
|
|
65
|
+
"file": self.file,
|
|
66
|
+
"line": self.line,
|
|
67
|
+
"col": self.col,
|
|
68
|
+
"message": self.message,
|
|
69
|
+
}
|
|
65
70
|
|
|
66
71
|
|
|
67
72
|
@dataclass
|
|
@@ -123,7 +128,16 @@ def run_ruff(project_path: Path) -> dict[str, FindingGroup]:
|
|
|
123
128
|
# selector, bad config, ...). Empty stdout on exit 2 must never read
|
|
124
129
|
# as "0 findings" — `run_checked` raises instead of returning in that case.
|
|
125
130
|
result = run_checked(
|
|
126
|
-
[
|
|
131
|
+
[
|
|
132
|
+
sys.executable,
|
|
133
|
+
"-m",
|
|
134
|
+
"ruff",
|
|
135
|
+
"check",
|
|
136
|
+
"--no-cache",
|
|
137
|
+
"--output-format",
|
|
138
|
+
"json",
|
|
139
|
+
".",
|
|
140
|
+
],
|
|
127
141
|
project_path,
|
|
128
142
|
"ruff",
|
|
129
143
|
ok_codes=(0, 1),
|
|
@@ -226,8 +240,15 @@ def run_pymodularity(project_path: Path) -> dict[str, FindingGroup]:
|
|
|
226
240
|
# 2 `uv` missing or an uncaught exception (docs/rules.md "JSON output").
|
|
227
241
|
# A failure must never read as "0 findings".
|
|
228
242
|
result = run_checked(
|
|
229
|
-
[
|
|
230
|
-
|
|
243
|
+
[
|
|
244
|
+
sys.executable,
|
|
245
|
+
"-m",
|
|
246
|
+
"pymodularity",
|
|
247
|
+
"check",
|
|
248
|
+
"--output-format",
|
|
249
|
+
"json",
|
|
250
|
+
str(project_path),
|
|
251
|
+
],
|
|
231
252
|
project_path,
|
|
232
253
|
"pymodularity",
|
|
233
254
|
ok_codes=(0, 1),
|
|
@@ -259,7 +280,11 @@ def build_report(project_path: Path) -> tuple[dict[str, object], int]:
|
|
|
259
280
|
sections: dict[str, object] = {}
|
|
260
281
|
grand_total = 0
|
|
261
282
|
|
|
262
|
-
for tool, run in (
|
|
283
|
+
for tool, run in (
|
|
284
|
+
("ruff", run_ruff),
|
|
285
|
+
("ty", run_ty),
|
|
286
|
+
("pymodularity", run_pymodularity),
|
|
287
|
+
):
|
|
263
288
|
print(f"Running {tool} on {project_path} ...", file=sys.stderr)
|
|
264
289
|
violations = run(project_path)
|
|
265
290
|
total = sum(group.count for group in violations.values())
|
{python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/references/ruff.reference.toml
RENAMED
|
@@ -321,9 +321,9 @@ ignore = [
|
|
|
321
321
|
# ANN401 (typing.Any disallowed) stays ON: with basedpyright dropped
|
|
322
322
|
# in favor of ty, ANN401 is the gate's only coverage for explicit
|
|
323
323
|
# Any (basedpyright's reportExplicitAny): ty has no equivalent rule.
|
|
324
|
-
# missing
|
|
325
|
-
#
|
|
326
|
-
|
|
324
|
+
# missing-return-type-special-method stays ON: ty types the target of
|
|
325
|
+
# `with X() as x` as Unknown when `__enter__` has no return type. ruff
|
|
326
|
+
# fixes `__init__ -> None` and `__str__ -> str` itself (safe fix).
|
|
327
327
|
"missing-type-args", # missing type on *args — typically pass-through,
|
|
328
328
|
# type depends on caller
|
|
329
329
|
"missing-type-kwargs", # missing type on **kwargs — same reasoning as
|
|
@@ -339,18 +339,18 @@ ignore = [
|
|
|
339
339
|
# than max_snr
|
|
340
340
|
|
|
341
341
|
# ── Code style ──
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
342
|
+
# lambda-assignment stays ON: a lambda cannot annotate its parameters,
|
|
343
|
+
# so ty types `strip = lambda x: x.strip()` as `(x) -> Unknown` and
|
|
344
|
+
# accepts `strip(1)`.
|
|
345
345
|
"in-dict-keys", # use `key in dict` — `key in dict.keys()` is more
|
|
346
346
|
# explicit about intent; Python Zen says explicit >
|
|
347
347
|
# implicit
|
|
348
348
|
"superfluous-else-return", # the else branch makes the two paths visually
|
|
349
349
|
# symmetric and easier to read
|
|
350
350
|
"superfluous-else-raise", # same reasoning as superfluous-else-return
|
|
351
|
-
# super
|
|
352
|
-
#
|
|
353
|
-
|
|
351
|
+
# super-call-with-parameters stays ON: zero-argument super() fails in a
|
|
352
|
+
# dataclass(slots=True) before Python 3.14, but ruff skips slots
|
|
353
|
+
# dataclasses for this rule (checked on ruff 0.17.3).
|
|
354
354
|
"compare-to-empty-string", # `s == ""` is more explicit than `not s` (the
|
|
355
355
|
# latter also matches None, 0, [])
|
|
356
356
|
|
|
@@ -396,6 +396,11 @@ ignore = [
|
|
|
396
396
|
"unused-async", # async test doubles mirror the awaited signature they replace
|
|
397
397
|
"float-equality-comparison", # asserting an exactly representable result is correct
|
|
398
398
|
"too-many-locals", # an integration test sets up many real collaborators
|
|
399
|
+
"missing-type-function-argument", # pytest fixtures: the fixture defines the type
|
|
400
|
+
"missing-return-type-private-function", # helpers and fakes local to a test module
|
|
401
|
+
"missing-return-type-special-method", # `__init__` / `__enter__` on test doubles
|
|
402
|
+
"import-outside-top-level", # imports inside a test patch or isolate the import
|
|
403
|
+
"private-member-access", # tests inspect internal state on purpose
|
|
399
404
|
]
|
|
400
405
|
"test_*.py" = [
|
|
401
406
|
"assert",
|
|
@@ -409,6 +414,11 @@ ignore = [
|
|
|
409
414
|
"unused-async",
|
|
410
415
|
"float-equality-comparison",
|
|
411
416
|
"too-many-locals",
|
|
417
|
+
"missing-type-function-argument",
|
|
418
|
+
"missing-return-type-private-function",
|
|
419
|
+
"missing-return-type-special-method",
|
|
420
|
+
"import-outside-top-level",
|
|
421
|
+
"private-member-access",
|
|
412
422
|
]
|
|
413
423
|
|
|
414
424
|
# ── isort ───────────────────────────────────────────────────────────────────
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_linters-0.2.0 → python_linters-0.2.1}/src/python_linters/references/ty.reference.toml
RENAMED
|
File without changes
|
|
File without changes
|