sarj-python-lint 0.67.12__tar.gz → 0.67.13__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.
Files changed (103) hide show
  1. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/PKG-INFO +1 -1
  2. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/pyproject.toml +1 -1
  3. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_registry.py +0 -4
  4. sarj_python_lint-0.67.12/src/sarj_python_lint/rules/no_apirouter_root_trailing_slash.py +0 -120
  5. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/.gitignore +0 -0
  6. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/LICENSE +0 -0
  7. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/README.md +0 -0
  8. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/__init__.py +0 -0
  9. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/__main__.py +0 -0
  10. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/_filesystem.py +0 -0
  11. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  12. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/_secret_names.py +0 -0
  13. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/_version.py +0 -0
  14. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/py.typed +0 -0
  15. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/ratchet.py +0 -0
  16. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rule_base.py +0 -0
  17. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/__init__.py +0 -0
  18. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  19. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_comments.py +0 -0
  20. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  21. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  22. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_first_party.py +0 -0
  23. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_imports.py +0 -0
  24. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_logging.py +0 -0
  25. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_paths.py +0 -0
  26. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  27. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_pytest.py +0 -0
  28. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_sql.py +0 -0
  29. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  30. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  31. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/created_at_order_requires_tiebreaker.py +0 -0
  32. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/defect_xfail_requires_strict.py +0 -0
  33. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  34. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  35. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/duplicate_test_body.py +0 -0
  36. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/duplicated_override_docstring.py +0 -0
  37. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/fastapi_openapi_contract.py +0 -0
  38. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/fixture_returns_bare_tuple.py +0 -0
  39. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  40. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/kwarg_heavy_construction_in_test.py +0 -0
  41. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  42. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_aggregation_in_store_query.py +0 -0
  43. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  44. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  45. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  46. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_file_level_escape_hatch_noqa.py +0 -0
  47. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_file_level_suppression.py +0 -0
  48. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  49. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  50. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_gen_random_uuid_in_sql.py +0 -0
  51. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  52. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  53. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_isinstance_union_chain.py +0 -0
  54. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_long_comment.py +0 -0
  55. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  56. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_optional_tenant_predicate.py +0 -0
  57. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_query_with_many_joins.py +0 -0
  58. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  59. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  60. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  61. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  62. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_sentinel_return_on_except.py +0 -0
  63. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_stdlib_logging.py +0 -0
  64. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  65. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  66. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  67. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  68. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  69. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  70. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  71. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  72. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  73. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  74. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  75. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  76. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  77. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  78. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  79. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  80. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  81. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  82. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  83. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  84. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  85. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  86. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  87. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_timedelta_for_durations.py +0 -0
  88. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  89. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  90. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  91. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/pydantic_at_boundaries.py +0 -0
  92. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  93. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  94. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  95. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  96. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  97. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  98. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/source_coupled_test.py +0 -0
  99. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/stepdown.py +0 -0
  100. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  101. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  102. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/trivially_true_assertion.py +0 -0
  103. {sarj_python_lint-0.67.12 → sarj_python_lint-0.67.13}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sarj-python-lint
3
- Version: 0.67.12
3
+ Version: 0.67.13
4
4
  Summary: Custom Python lint rules — AST-based, pre-commit-friendly, hypermodern defaults
5
5
  Project-URL: Homepage, https://code-standards.sarj.ai/rules/python/
6
6
  Project-URL: Documentation, https://code-standards.sarj.ai/rules/python/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sarj-python-lint"
3
- version = "0.67.12"
3
+ version = "0.67.13"
4
4
  description = "Custom Python lint rules — AST-based, pre-commit-friendly, hypermodern defaults"
5
5
  readme = "README.md"
6
6
  authors = [{ name = "sarj-ai" }]
@@ -27,9 +27,6 @@ from sarj_python_lint.rules.mock_without_spec import MockWithoutSpec
27
27
  from sarj_python_lint.rules.no_aggregation_in_store_query import (
28
28
  NoAggregationInStoreQuery,
29
29
  )
30
- from sarj_python_lint.rules.no_apirouter_root_trailing_slash import (
31
- NoApirouterRootTrailingSlash,
32
- )
33
30
  from sarj_python_lint.rules.no_comment_cruft import NoCommentCruft
34
31
  from sarj_python_lint.rules.no_cors_wildcard_with_credentials import (
35
32
  NoCorsWildcardWithCredentials,
@@ -154,7 +151,6 @@ REGISTRY: Mapping[str, type[Rule]] = MappingProxyType(
154
151
  SourceCoupledTest.id: SourceCoupledTest,
155
152
  NoQueryWithManyJoins.id: NoQueryWithManyJoins,
156
153
  NoAggregationInStoreQuery.id: NoAggregationInStoreQuery,
157
- NoApirouterRootTrailingSlash.id: NoApirouterRootTrailingSlash,
158
154
  NoSelectStar.id: NoSelectStar,
159
155
  NoGenericSingleExportModule.id: NoGenericSingleExportModule,
160
156
  Stepdown.id: Stepdown,
@@ -1,120 +0,0 @@
1
- """SARJ405 — APIRouter collection roots use an empty path, not ``/``.
2
-
3
- Examples: https://github.com/sarj-ai/standards/blob/main/packages/python/tests/rules/test_no_apirouter_root_trailing_slash.py
4
- """
5
-
6
- from __future__ import annotations
7
-
8
- import ast
9
- from pathlib import PurePosixPath
10
- from typing import TYPE_CHECKING, ClassVar, final, override
11
-
12
- from sarj_python_lint.rule_base import (
13
- AutofixPolicy,
14
- Diagnostic,
15
- ExampleFile,
16
- ExampleOutcome,
17
- Rule,
18
- RuleCategory,
19
- RuleDocumentation,
20
- RuleExample,
21
- Severity,
22
- parse_or_none,
23
- )
24
- from sarj_python_lint.rules._ast_index import nodes
25
- from sarj_python_lint.rules._fastapi import FastapiIndex
26
- from sarj_python_lint.rules._paths import is_generated, is_test_path
27
-
28
-
29
- if TYPE_CHECKING:
30
- from pathlib import Path
31
-
32
-
33
- _DOCUMENTATION_EXAMPLE_DIR_NAMES = frozenset({"docs_src"})
34
-
35
-
36
- @final
37
- class NoApirouterRootTrailingSlash(Rule):
38
- id: str = "no-apirouter-root-trailing-slash"
39
- code: str = "SARJ405"
40
- documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
41
- summary="APIRouter collection-root operations should use an empty path instead of `/`.",
42
- rationale=(
43
- "A `/` path beneath an APIRouter prefix makes the prefix without its trailing slash redirect, "
44
- "rather than serving the canonical collection URL directly."
45
- ),
46
- remediation="Declare the APIRouter operation path as an empty string so the prefix itself is canonical.",
47
- category=RuleCategory.CORRECTNESS,
48
- autofix=AutofixPolicy.NONE,
49
- limitations=(
50
- "Only FastAPI and APIRouter bindings whose constructor provenance is visible in one module are resolved.",
51
- "Dynamic route paths are ignored because their runtime value cannot be proven.",
52
- "Tests, generated sources, and FastAPI documentation-source examples are excluded.",
53
- ),
54
- examples=(
55
- RuleExample(
56
- example_id="router-root-trailing-slash",
57
- title="APIRouter root operation adds a trailing slash",
58
- outcome=ExampleOutcome.MATCH,
59
- files=(
60
- ExampleFile.python(
61
- "api.py",
62
- "from fastapi import APIRouter\n\nrouter = APIRouter(prefix='/items')\n\n"
63
- "@router.get('/')\nasync def list_items() -> list[str]:\n return []\n",
64
- ),
65
- ),
66
- focus_path=PurePosixPath("api.py"),
67
- expected_count=1,
68
- public=True,
69
- ),
70
- RuleExample(
71
- example_id="canonical-router-root",
72
- title="APIRouter root operation uses its prefix directly",
73
- outcome=ExampleOutcome.NO_MATCH,
74
- files=(
75
- ExampleFile.python(
76
- "api.py",
77
- "from fastapi import APIRouter\n\nrouter = APIRouter(prefix='/items')\n\n"
78
- "@router.get('')\nasync def list_items() -> list[str]:\n return []\n",
79
- ),
80
- ),
81
- focus_path=PurePosixPath("api.py"),
82
- expected_count=0,
83
- public=True,
84
- ),
85
- ),
86
- )
87
- description: str = documentation.summary
88
-
89
- @override
90
- def check(self, path: Path, source: str) -> list[Diagnostic]:
91
- if (
92
- is_test_path(path)
93
- or is_generated(path, source)
94
- or any(part.lower() in _DOCUMENTATION_EXAMPLE_DIR_NAMES for part in path.parts)
95
- ):
96
- return []
97
- tree = parse_or_none(path, source)
98
- if tree is None:
99
- return []
100
- index = FastapiIndex(tree, path=path)
101
- decorators: dict[int, ast.Call] = {}
102
- for function in nodes(tree, ast.FunctionDef, ast.AsyncFunctionDef):
103
- for route in index.routes(function):
104
- if route.receiver_kind == "APIRouter" and route.path == "/":
105
- decorators[id(route.decorator)] = route.decorator
106
-
107
- return [
108
- Diagnostic(
109
- path=path,
110
- line=decorator.lineno,
111
- col=decorator.col_offset + 1,
112
- code=self.code,
113
- severity=Severity.WARNING,
114
- message=(
115
- "APIRouter collection-root path is `/`, so the prefix without a slash redirects — "
116
- "declare the path as an empty string. Suppress with `# sarj-noqa: SARJ405`."
117
- ),
118
- )
119
- for decorator in sorted(decorators.values(), key=lambda node: (node.lineno, node.col_offset))
120
- ]