code-standards 7.0.0__py3-none-any.whl

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 (99) hide show
  1. code_standards-7.0.0.dist-info/METADATA +53 -0
  2. code_standards-7.0.0.dist-info/RECORD +99 -0
  3. code_standards-7.0.0.dist-info/WHEEL +4 -0
  4. code_standards-7.0.0.dist-info/entry_points.txt +3 -0
  5. code_standards-7.0.0.dist-info/licenses/LICENSE +21 -0
  6. sarj_standards/__init__.py +30 -0
  7. sarj_standards/__main__.py +5 -0
  8. sarj_standards/_meta.py +22 -0
  9. sarj_standards/api.py +890 -0
  10. sarj_standards/cli/__init__.py +0 -0
  11. sarj_standards/cli/main.py +2466 -0
  12. sarj_standards/configs/cli-reference.v1.json +1 -0
  13. sarj_standards/configs/doctor.config.json +22 -0
  14. sarj_standards/configs/eslint.application.mjs +1366 -0
  15. sarj_standards/configs/eslint.peers.json +44 -0
  16. sarj_standards/configs/eslint.strict.mjs +1060 -0
  17. sarj_standards/configs/markdownlint.strict.yaml +12 -0
  18. sarj_standards/configs/pyright.strict.json +96 -0
  19. sarj_standards/configs/ruff.application.toml +363 -0
  20. sarj_standards/configs/ruff.strict.toml +338 -0
  21. sarj_standards/configs/rule-inventory.v1.json +1 -0
  22. sarj_standards/configs/rule-ledger.json +846 -0
  23. sarj_standards/configs/rule-warning-levels.v1.json +1 -0
  24. sarj_standards/configs/taplo.strict.toml +14 -0
  25. sarj_standards/configs/yamllint.strict.yaml +25 -0
  26. sarj_standards/libs/__init__.py +0 -0
  27. sarj_standards/libs/adoption/__init__.py +0 -0
  28. sarj_standards/libs/adoption/configs.py +36 -0
  29. sarj_standards/libs/adoption/doctor.py +1346 -0
  30. sarj_standards/libs/adoption/exclusions.py +66 -0
  31. sarj_standards/libs/adoption/hooks.py +423 -0
  32. sarj_standards/libs/adoption/launcher.py +240 -0
  33. sarj_standards/libs/adoption/lifecycle.py +493 -0
  34. sarj_standards/libs/adoption/manifest.py +550 -0
  35. sarj_standards/libs/adoption/packagemanager.py +285 -0
  36. sarj_standards/libs/adoption/retired_suppressions.py +371 -0
  37. sarj_standards/libs/adoption/scaffold.py +1660 -0
  38. sarj_standards/libs/adoption/service.py +441 -0
  39. sarj_standards/libs/adoption/transaction.py +274 -0
  40. sarj_standards/libs/adoption/upgrade.py +516 -0
  41. sarj_standards/libs/adoption/uvtool.py +62 -0
  42. sarj_standards/libs/catalogs/__init__.py +9 -0
  43. sarj_standards/libs/catalogs/slack_automations.py +627 -0
  44. sarj_standards/libs/corpus/__init__.py +25 -0
  45. sarj_standards/libs/corpus/manifest.py +211 -0
  46. sarj_standards/libs/corpus/snapshot.py +222 -0
  47. sarj_standards/libs/diagnostics/__init__.py +65 -0
  48. sarj_standards/libs/diagnostics/analysis.schema.json +161 -0
  49. sarj_standards/libs/diagnostics/baseline.py +131 -0
  50. sarj_standards/libs/diagnostics/models.py +574 -0
  51. sarj_standards/libs/diagnostics/serialize.py +290 -0
  52. sarj_standards/libs/diagnostics/source.py +172 -0
  53. sarj_standards/libs/filesystem.py +11 -0
  54. sarj_standards/libs/linting/__init__.py +0 -0
  55. sarj_standards/libs/linting/analysis.py +422 -0
  56. sarj_standards/libs/linting/external.py +1454 -0
  57. sarj_standards/libs/linting/library_policy.py +688 -0
  58. sarj_standards/libs/linting/policy.py +152 -0
  59. sarj_standards/libs/linting/runner.py +442 -0
  60. sarj_standards/libs/linting/textlint.py +1605 -0
  61. sarj_standards/libs/release/__init__.py +98 -0
  62. sarj_standards/libs/release/_values.py +24 -0
  63. sarj_standards/libs/release/artifacts.py +191 -0
  64. sarj_standards/libs/release/causality.py +80 -0
  65. sarj_standards/libs/release/changes.py +48 -0
  66. sarj_standards/libs/release/process.py +128 -0
  67. sarj_standards/libs/release/publish.py +85 -0
  68. sarj_standards/libs/release/registry.py +271 -0
  69. sarj_standards/libs/release/release_age.py +218 -0
  70. sarj_standards/libs/release/rollout.py +1163 -0
  71. sarj_standards/libs/release/tags.py +373 -0
  72. sarj_standards/libs/release/typescript.py +191 -0
  73. sarj_standards/libs/repository/__init__.py +0 -0
  74. sarj_standards/libs/repository/cli_reference_artifact.py +324 -0
  75. sarj_standards/libs/repository/comment_corpus.py +536 -0
  76. sarj_standards/libs/repository/config_generation.py +146 -0
  77. sarj_standards/libs/repository/docs.py +347 -0
  78. sarj_standards/libs/repository/hooks.py +118 -0
  79. sarj_standards/libs/repository/ledger.py +99 -0
  80. sarj_standards/libs/repository/repository.py +744 -0
  81. sarj_standards/libs/repository/rule_authoring.py +246 -0
  82. sarj_standards/libs/repository/rule_catalog_artifact.py +479 -0
  83. sarj_standards/libs/repository/rule_changes.py +318 -0
  84. sarj_standards/libs/repository/rule_inventory_artifact.py +142 -0
  85. sarj_standards/libs/repository/rule_lifecycle.py +167 -0
  86. sarj_standards/libs/repository/rule_maintenance.py +225 -0
  87. sarj_standards/libs/rules/__init__.py +74 -0
  88. sarj_standards/libs/rules/catalog.py +145 -0
  89. sarj_standards/libs/rules/contracts.py +382 -0
  90. sarj_standards/libs/rules/corpus_runner.py +365 -0
  91. sarj_standards/libs/rules/evaluation.py +177 -0
  92. sarj_standards/libs/setup/__init__.py +4 -0
  93. sarj_standards/libs/setup/repository.py +40 -0
  94. sarj_standards/py.typed +0 -0
  95. sarj_standards/schemas/__init__.py +4 -0
  96. sarj_standards/schemas/_paths.py +7 -0
  97. sarj_standards/schemas/rule-catalog.v1.json +1 -0
  98. sarj_standards/schemas/rule-catalog.v1.schema.json +112 -0
  99. sarj_standards/schemas/slack-automations.v1.schema.json +1751 -0
@@ -0,0 +1,12 @@
1
+ # Sarj strict Markdown lint configuration for markdownlint / markdownlint-cli2
2
+ default: true
3
+ MD013: false # Line length (handled by text editor / formatter)
4
+ MD033: false # Allow inline HTML when necessary (e.g., details/summary, alerts)
5
+ MD041: false # First line in file does not strictly need to be top-level heading (for snippets/partials)
6
+ MD024:
7
+ siblings_only: true # Allow duplicate heading names in different sections
8
+ MD029:
9
+ style: "ordered"
10
+ MD040: true # Require language specified on fenced code blocks
11
+ MD053:
12
+ ignored_definitions: [] # Treat pseudo-reference comments as removable unused definitions.
@@ -0,0 +1,96 @@
1
+ {
2
+ // Maximally-strict pyright / basedpyright config.
3
+ //
4
+ // MUST be JSON(C), not TOML: pyright's `extends` silently ignores a bare-key
5
+ // .toml file (it loads JSON only), so a .toml strict config never actually
6
+ // applies — the type checker just runs on its defaults. JSONC keeps comments.
7
+ "typeCheckingMode": "strict",
8
+ "strictListInference": true,
9
+ "strictDictionaryInference": true,
10
+ "strictSetInference": true,
11
+ "strictParameterNoneValue": true,
12
+ "deprecateTypingAliases": true,
13
+ "enableExperimentalFeatures": false,
14
+
15
+ "reportUnusedImport": "error",
16
+ "reportUnusedVariable": "error",
17
+ "reportDeprecated": "error",
18
+ // Off: FastAPI/Starlette route handler functions (@router.get, etc.) are called
19
+ // via framework dispatch, not direct module invocations.
20
+ "reportUnusedFunction": false,
21
+ // Off: third-party untyped SDKs (e.g. google.cloud.pubsub_v1, psycopg) cause workspace-wide noise.
22
+ "reportMissingTypeStubs": false,
23
+
24
+ "reportUnknownMemberType": "error",
25
+ "reportUnknownParameterType": "error",
26
+ "reportMissingParameterType": "error",
27
+ "reportUnknownVariableType": "error",
28
+ "reportUnknownArgumentType": "error",
29
+ "reportMissingTypeArgument": "error",
30
+ "reportUnknownLambdaType": "error",
31
+ "reportUnusedClass": "error",
32
+ // Fires on every builder/fluent call (argparse.add_argument, query builders, …)
33
+ // where the returned handle is intentionally discarded — noise, not type safety.
34
+ "reportUnusedCallResult": false,
35
+ "reportUnusedCoroutine": "error",
36
+
37
+ "reportUnnecessaryIsInstance": "error",
38
+ // Exhaustive match fallbacks are required by SARJ032 and remain useful to
39
+ // runtime checkers when a type grows, so they are not unnecessary branches.
40
+ "reportUnnecessaryComparison": "none",
41
+ "reportUnnecessaryCast": "error",
42
+ "reportUnnecessaryContains": "error",
43
+ "reportConstantRedefinition": "error",
44
+ "reportCallIssue": "error",
45
+ "reportMatchNotExhaustive": "error",
46
+ "reportUntypedFunctionDecorator": "error",
47
+ "reportUnnecessaryTypeIgnoreComment": "error",
48
+ "reportReturnType": "error",
49
+ "reportPropertyTypeMismatch": "error",
50
+ "reportArgumentType": "error",
51
+ // reportPrivateUsage stays at error. Pyright resolves the declaring class and
52
+ // catches private base-class access that syntax-only checks cannot see, but it
53
+ // cannot distinguish first-party modules from dependency implementation APIs.
54
+ // A necessary dependency-boundary reach therefore needs a reasoned line-level
55
+ // suppression; disabling the check would also hide actionable local defects.
56
+ "reportPrivateUsage": "error",
57
+ // Pin strict-mode defaults that define module API visibility. Explicit keys
58
+ // keep upgrades from silently weakening private imports or dynamic exports.
59
+ "reportPrivateImportUsage": "error",
60
+ "reportUnsupportedDunderAll": "error",
61
+ // Off: low value — forcing `@override` on every `ast.NodeVisitor.visit_*` hook
62
+ // (and similar framework dispatch methods) is noise, not safety.
63
+ "reportImplicitOverride": false,
64
+ // Off: ruff owns string-concat style. ruff's ISC003 forbids explicit `+` of
65
+ // string literals (prefers implicit), which directly contradicts flagging
66
+ // implicit concatenation here — the two cannot both be satisfied. ruff's ISC001
67
+ // still catches the dangerous single-line "missing comma" accident.
68
+ "reportImplicitStringConcatenation": "none",
69
+ // (reportShadowedImports was removed from pyright upstream — pyright 1.1.411
70
+ // AND basedpyright both reject it as unrecognized; basedpyright likewise
71
+ // rejects reportInvalidExceptionType — so both are omitted to keep every
72
+ // checker's output clean.)
73
+ "reportMissingSuperCall": "error",
74
+ "reportUninitializedInstanceVariable": "error",
75
+ "reportInconsistentConstructor": "error",
76
+ "reportInvalidStubStatement": "error",
77
+ "reportSelfClsParameterName": "error",
78
+ "reportTypeCommentUsage": "error",
79
+ // basedpyright-only (8 keys): reportInvalidCast, reportUnsafeMultipleInheritance,
80
+ // reportImplicitRelativeImport, reportExplicitAny, reportIgnoreCommentWithoutRule,
81
+ // reportPrivateLocalImportUsage, reportAny, reportUnannotatedClassAttribute.
82
+ // Plain pyright (verified on 1.1.411) prints `Config contains unrecognized
83
+ // setting "<key>"` once per key and then IGNORES it — the run still exits 0
84
+ // with "0 errors". The warnings are cosmetic; the keys stay because
85
+ // basedpyright is the canonical checker and dropping them would silently
86
+ // weaken it. Consumers on plain pyright lose only these eight checks.
87
+ "reportInvalidCast": "error",
88
+ "reportUnsafeMultipleInheritance": "error",
89
+ "reportImplicitRelativeImport": "error",
90
+ "reportUnreachable": "error",
91
+ "reportExplicitAny": "error",
92
+ "reportIgnoreCommentWithoutRule": "error",
93
+ "reportPrivateLocalImportUsage": "error",
94
+ "reportAny": "error",
95
+ "reportUnannotatedClassAttribute": "error"
96
+ }
@@ -0,0 +1,363 @@
1
+ # Shared strict Ruff policy. Comments document durable behavior and compatibility
2
+ # constraints; repository-specific evaluation evidence stays outside the package.
3
+ line-length = 120
4
+ extend-exclude = ["sdk"]
5
+
6
+ [format]
7
+ quote-style = "double"
8
+ indent-style = "space"
9
+ skip-magic-trailing-comma = false
10
+ line-ending = "auto"
11
+ # Markdown has its own canonical linter. Ruff 0.16+ otherwise reformats Python
12
+ # fences in existing prose when a repository runs `ruff format .`.
13
+ exclude = ["*.md"]
14
+
15
+ [lint]
16
+ select = ["ALL"]
17
+ external = ["SARJ"]
18
+ preview = true
19
+ # Let Ruff's native UP037 own quoted annotations, including TYPE_CHECKING-only
20
+ # imports. Its fix is intentionally unsafe when it must change annotation
21
+ # evaluation semantics, so consumer baselines can grandfather existing debt.
22
+ future-annotations = true
23
+ logger-objects = ["loguru.logger"] # treat loguru as a logger so G004/G010 fire on it (the house logger)
24
+ # TC001/2/3 stay advisory but are never auto-applied: their unsafe fixes can
25
+ # move runtime-evaluated framework annotations into `TYPE_CHECKING`, changing
26
+ # behavior under deferred annotations. Marking them unfixable preserves the
27
+ # warning without applying a potentially breaking rewrite.
28
+ unfixable = ["TC001", "TC002", "TC003"]
29
+
30
+ extend-select = [
31
+ "ANN401",
32
+ "RUF013",
33
+ "RUF022",
34
+ "RUF023",
35
+ "RUF052",
36
+ "TC001",
37
+ "TC002",
38
+ "TC003",
39
+
40
+ "UP041",
41
+ "UP045",
42
+ "UP046",
43
+ "UP047",
44
+ "UP049",
45
+
46
+ "FURB101",
47
+ "FURB103",
48
+ "FURB113",
49
+ "FURB118",
50
+ "FURB148",
51
+ "FURB152",
52
+ "FURB154",
53
+ "FURB163",
54
+ "FURB166",
55
+ "FURB171",
56
+ "FURB177",
57
+ "FURB180",
58
+ "FURB192",
59
+
60
+ "ASYNC100",
61
+ "ASYNC105",
62
+ "ASYNC109",
63
+
64
+ "B904",
65
+ "S112",
66
+ "TRY400",
67
+ "TRY401",
68
+
69
+ "ASYNC210",
70
+ "ASYNC220",
71
+ "ASYNC230",
72
+ "ASYNC251",
73
+ "PERF402",
74
+ "SIM117",
75
+
76
+ "PT006",
77
+ "PT007",
78
+ "PT009",
79
+ "PT011",
80
+ "PT012",
81
+
82
+ "FAST001",
83
+ "FAST002",
84
+ "FAST003",
85
+
86
+ "LOG001",
87
+ "LOG002",
88
+ "LOG007",
89
+ "LOG009",
90
+ "LOG015",
91
+ "G010",
92
+
93
+ "FBT001",
94
+ "FBT002",
95
+ "FBT003",
96
+ ]
97
+
98
+ # The ignore list is derived from rule semantics rather than consumer
99
+ # suppressions. Security, naming, and correctness checks remain enabled unless a
100
+ # narrower authority owns the concern or the rule conflicts with the formatter.
101
+ # The D/DOC block below documents the deliberate docstring policy.
102
+ ignore = [
103
+ # Every entry below has a durable semantic reason. Builtin-shadowing checks
104
+ # remain enabled, while assertion and hardcoded-secret checks are scoped to
105
+ # tests instead of being disabled repository-wide.
106
+
107
+ # Sarj owns these comment concerns with narrower, syntax-aware rules and
108
+ # tracked-reference exemptions. Ruff's generic variants double-report
109
+ # commented code and reject even ticket-backed TODOs.
110
+ "ERA001",
111
+ "FIX002",
112
+ "TD002",
113
+ "TD003",
114
+ "TD004",
115
+
116
+ # Complexity thresholds are heuristics rather than correctness rules. These
117
+ # limits conflict with enforced guard-clause style, penalize branching that is
118
+ # intrinsic to visitors and dispatchers, and count keyword-only parameters.
119
+ # Narrower checks still catch deeply nested code and positional-argument
120
+ # explosion without imposing arbitrary function-size ceilings.
121
+ "C901",
122
+ "PLR0911",
123
+ "PLR0912",
124
+ "PLR0913",
125
+ "PLR0915",
126
+
127
+ # DOCSTRINGS: the standard is LESS PROSE, NOT MORE. Code documents itself;
128
+ # a docstring earns its place by saying something the signature cannot.
129
+ #
130
+ # The dividing line, applied to every D/DOC rule:
131
+ # KEPT — rules that DELETE prose, or catch a docstring contradicting the code
132
+ # IGNORED — rules that DEMAND prose, or tax the wording of prose already written
133
+ #
134
+ # An earlier version of this file enforced the whole family and said so
135
+ # ("the docstring-punctuation family ... are now ENFORCED"). That put the
136
+ # config in direct conflict with this repo's own rules: DOC201 REQUIRES a
137
+ # `Returns:` section restating the return annotation, while SARJ050
138
+ # `redundant-docstring` and `no-restated-comment` exist to DELETE prose that
139
+ # restates the signature. The linter was manufacturing the exact noise the
140
+ # custom rules were written to remove, and every author paid the tax.
141
+
142
+ # Missing docstrings are not a defect.
143
+ "D100", "D101", "D102", "D103", "D104", "D105", "D106", "D107",
144
+
145
+ # Mutually-exclusive pairs: ruff requires one of each to be off.
146
+ "D203",
147
+ "D213",
148
+
149
+ # DEMAND MORE PROSE. These make a machine ask for text that the signature,
150
+ # the type annotations and the `raise` statements already carry.
151
+ "D417", # undocumented-param — describe every argument
152
+ "DOC201", # docstring-missing-returns — describe the return
153
+ "DOC402", # docstring-missing-yields — describe the yield
154
+ "DOC501", # docstring-missing-exception
155
+
156
+ # WORDING AND SECTION CEREMONY. None of these catch a defect; they tax someone
157
+ # for writing a short useful sentence, which is the sentence most worth having.
158
+ "D200", # one-line docstring should fit on one line
159
+ "D205", # blank line required between summary and description
160
+ "D400", # first line should end with a period
161
+ "D401", # first line should be in imperative mood ("gets" -> "Get")
162
+ "D403", # first word should be capitalized
163
+ "D404", # first word should not be "This"
164
+ "D405", "D406", "D407", "D408", "D409", # section name / underline formatting
165
+ "D410", "D411", "D412", "D413", # blank lines around sections
166
+ "D415", # first line should end with terminal punctuation
167
+ "D416", # section name should end with a colon
168
+ "D420", # section order
169
+ "D421", # property docstring should not start with a verb
170
+
171
+ # DELIBERATELY STILL ENFORCED — every one of these REMOVES text or catches a
172
+ # docstring that lies about the code, so they pull the same direction as the
173
+ # rules above rather than against them:
174
+ # D402 first line is the function's signature (pure restatement)
175
+ # D414 section has no content (empty `Returns:`)
176
+ # D418 @overload carrying a docstring
177
+ # D419 empty docstring
178
+ # DOC102 documented parameter not in the signature (docstring lies)
179
+ # DOC202 `Returns:` on a function that returns nothing
180
+ # DOC403 `Yields:` on a function that never yields
181
+ # DOC502 documented exception that is never raised
182
+ # Also kept: D201/D202/D206-D212/D300/D301 — mechanical whitespace and quote
183
+ # style, formatter-adjacent, no prose implications.
184
+ # CPY001 requires per-file headers even when licensing is declared at the
185
+ # package or repository level. The shared policy does not mandate duplicate
186
+ # copyright prose in every source file.
187
+ "CPY001",
188
+
189
+ # COM812 conflicts with the formatter. Reproduced, not assumed: on
190
+ # packages/iac/src/sarj_iac_lint/_hcl.py — a file `ruff format --check` calls
191
+ # already formatted — COM812 reports two sites, and applying its fix makes the
192
+ # same file format-dirty, because the comma it adds is a magic trailing comma
193
+ # and the formatter then explodes `_parse_body`'s parameters one per line.
194
+ # `skip-magic-trailing-comma = false` above is what makes that bite.
195
+ "COM812",
196
+
197
+ # E501 is the formatter's job. Content that remains long after formatting is
198
+ # generally an unsplittable literal, URL, or message; manually altering it
199
+ # would not improve code structure.
200
+ "E501",
201
+
202
+ # RUF001 rejects legitimate characters in multilingual user-facing text.
203
+ # `allowed-confusables` cannot express a whole writing system safely, so this
204
+ # shared policy does not treat non-ASCII product copy as suspicious by default.
205
+ "RUF001",
206
+
207
+ # PLC2701 is replaced by SARJ048 because lexical underscores cannot
208
+ # distinguish first-party private imports from dependency implementation
209
+ # imports. SARJ048 resolves modules against the project tree and reports only
210
+ # first-party boundaries. Consumers without the Sarj Python hooks should
211
+ # re-enable PLC2701 rather than leaving this concern unchecked.
212
+ "PLC2701",
213
+ ]
214
+
215
+ # SLF001 stays enabled, with a documented limitation: Ruff cannot determine
216
+ # whether an underscored attribute belongs to first-party or dependency code.
217
+ # Dependency-boundary access therefore requires an inline, reasoned suppression;
218
+ # projects with adapter layers may scope that exception locally. Pyright's
219
+ # reportPrivateUsage remains independent and may require its own line-level
220
+ # explanation.
221
+
222
+ [lint.isort]
223
+ force-single-line = false
224
+ lines-after-imports = 2
225
+ force-sort-within-sections = true
226
+
227
+ # Under PEP 649 (py314) plain annotations are lazy, so TC001-003 moving their
228
+ # imports into `TYPE_CHECKING` is safe — EXCEPT for constructs that eagerly read
229
+ # `__annotations__` at class-creation time (pydantic models/settings, dataclasses,
230
+ # NamedTuple, TypedDict) and FastAPI route decorators that resolve body/param
231
+ # models at request time. Listing them stops TC001-003 from flagging (and its
232
+ # unsafe fix from breaking) their field-type imports.
233
+ [lint.flake8-type-checking]
234
+ runtime-evaluated-base-classes = [
235
+ "pydantic.BaseModel",
236
+ "pydantic_settings.BaseSettings",
237
+ "typing.NamedTuple",
238
+ "typing.TypedDict",
239
+ ]
240
+ runtime-evaluated-decorators = [
241
+ "pydantic.dataclasses.dataclass",
242
+ "dataclasses.dataclass",
243
+ "fastapi.APIRouter.post",
244
+ "fastapi.APIRouter.get",
245
+ "fastapi.APIRouter.put",
246
+ "fastapi.APIRouter.delete",
247
+ "fastapi.APIRouter.patch",
248
+ "fastapi.APIRouter.head",
249
+ "fastapi.APIRouter.options",
250
+ "fastapi.APIRouter.trace",
251
+ "fastapi.APIRouter.websocket",
252
+ "fastapi.APIRouter.api_route",
253
+ "fastapi.FastAPI.post",
254
+ "fastapi.FastAPI.get",
255
+ "fastapi.FastAPI.put",
256
+ "fastapi.FastAPI.delete",
257
+ "fastapi.FastAPI.patch",
258
+ "fastapi.FastAPI.head",
259
+ "fastapi.FastAPI.options",
260
+ "fastapi.FastAPI.trace",
261
+ "fastapi.FastAPI.websocket",
262
+ "fastapi.FastAPI.api_route",
263
+ ]
264
+
265
+ [lint.flake8-pytest-style]
266
+ # PT011's defaults omit RuntimeError even though a broad RuntimeError assertion
267
+ # can pass for the wrong failure. Include it with Ruff's defaults. Protocol
268
+ # exceptions such as AttributeError and TypeError remain excluded because their
269
+ # interpreter-owned messages are version-sensitive.
270
+ raises-require-match-for = [
271
+ "BaseException",
272
+ "Exception",
273
+ "ValueError",
274
+ "OSError",
275
+ "IOError",
276
+ "EnvironmentError",
277
+ "RuntimeError",
278
+ "socket.error",
279
+ ]
280
+
281
+ # PT030's defaults cover only Warning, UserWarning, and DeprecationWarning.
282
+ # The remaining broad built-in warning categories have the same false-pass risk:
283
+ # an unrelated warning from the code under test can satisfy pytest.warns(). Keep
284
+ # project-owned warning subclasses exempt because their type is already specific.
285
+ warns-extend-require-match-for = [
286
+ "BytesWarning",
287
+ "EncodingWarning",
288
+ "FutureWarning",
289
+ "ImportWarning",
290
+ "PendingDeprecationWarning",
291
+ "ResourceWarning",
292
+ "RuntimeWarning",
293
+ "SyntaxWarning",
294
+ "UnicodeWarning",
295
+ ]
296
+
297
+ [lint.flake8-tidy-imports.banned-api]
298
+ "unittest.mock.Mock".msg = "Prefer real fixtures or hand-rolled fakes implementing the relevant ABC. If a mock is genuinely required, import with `# noqa: TID251 — <reason>`."
299
+ "unittest.mock.AsyncMock".msg = "Same as Mock."
300
+ "unittest.mock.MagicMock".msg = "Same as Mock."
301
+ "unittest.mock.patch".msg = "Prefer dependency injection via fixtures over monkey-patching."
302
+ "pytest_mock".msg = "pytest-mock's `mocker` fixture is unittest.mock with a different spelling — it bypasses the mock bans above without any noqa trail. Use real fixtures/fakes; for a genuine external boundary use `from unittest import mock` + inline `# noqa: TID251 — <reason>`."
303
+
304
+ "datetime.datetime.utcnow".msg = "Deprecated in Python 3.12. Use `datetime.now(UTC)`."
305
+ "pickle.load".msg = "Pickle deserializes arbitrary objects and is unsafe on untrusted input. Use JSON via Pydantic, or msgspec/orjson."
306
+ "pickle.loads".msg = "Same — pickle is unsafe."
307
+
308
+ "os.environ".msg = "Use a Pydantic Settings class instead. If you genuinely need raw os.environ, add `# noqa: TID251 — <reason>` inline."
309
+ "os.getenv".msg = "Same — use a Pydantic Settings class instead of os.getenv."
310
+
311
+ "fastapi.UploadFile".msg = "Use a pre-signed URL so the client uploads directly to object storage."
312
+ "pydantic.alias_generators.to_camel".msg = "Don't camelCase API contracts in the backend. Keep snake_case; transform on the frontend with Zod."
313
+ "typing.cast".msg = "Prefer discriminated unions or `isinstance` narrowing over `cast`."
314
+ "psycopg.sql.Literal".msg = "Use parameterized queries (psycopg's `%s` placeholders) instead of sql.Literal."
315
+ "uuid.uuid4".msg = "Use uuid.uuid7() — time-ordered, aligns with the DB uuidv7() default. For unguessable secrets use secrets.token_urlsafe(), not a UUID."
316
+
317
+ # Generated application-profile library policy. Edit the catalog, not this file.
318
+ "aioredis".msg = "LIB020: aioredis was merged into redis-py; use redis.asyncio. Replace with redis.asyncio."
319
+ "argparse".msg = "LIB001: The application profile standardizes command-line interfaces on Typer. Replace with Typer."
320
+ "backports.cached_property".msg = "LIB018: Python 3.14 provides functools.cached_property. Replace with functools.cached_property."
321
+ "backports.zoneinfo".msg = "LIB012: Python 3.14 provides zoneinfo. Replace with zoneinfo."
322
+ "boto".msg = "LIB019: Boto 2 is obsolete; migrate to boto3 and review API differences. Replace with boto3."
323
+ "cerberus".msg = "LIB007: The application profile standardizes validation and serialization on Pydantic. Replace with Pydantic."
324
+ "click".msg = "LIB002: Use Typer for typed command-line interfaces instead of direct Click APIs. Replace with Typer."
325
+ "enum34".msg = "LIB016: Remove the obsolete enum34 backport on Python 3.14. Replace with enum."
326
+ "flask".msg = "LIB006: The application profile standardizes HTTP APIs on FastAPI; this is an architectural migration. Replace with FastAPI."
327
+ "futures".msg = "LIB017: Remove the obsolete futures backport on Python 3.14. Replace with concurrent.futures."
328
+ "importlib_metadata".msg = "LIB013: Python 3.14 provides importlib.metadata. Replace with importlib.metadata."
329
+ "importlib_resources".msg = "LIB014: Python 3.14 provides importlib.resources. Replace with importlib.resources."
330
+ "marshmallow".msg = "LIB007: The application profile standardizes validation and serialization on Pydantic. Replace with Pydantic."
331
+ "mock".msg = "LIB022: Python 3.14 provides unittest.mock. Replace with unittest.mock."
332
+ "nose".msg = "LIB021: Nose is unmaintained; use pytest. Replace with pytest."
333
+ "optparse".msg = "LIB001: The application profile standardizes command-line interfaces on Typer. Replace with Typer."
334
+ "pandas".msg = "LIB003: Use Polars; migration must account for its expressions and lack of a pandas index model. Replace with Polars."
335
+ "pathlib2".msg = "LIB011: Python 3.14 provides pathlib. Replace with pathlib."
336
+ "pkg_resources".msg = "LIB009: Do not use pkg_resources; choose the focused importlib or packaging API. Replace with importlib.metadata/importlib.resources/packaging."
337
+ "pytz".msg = "LIB008: Use zoneinfo; explicitly review DST ambiguity, localization, and fold behavior. Replace with zoneinfo."
338
+ "requests".msg = "LIB004: Use HTTPX; review timeout defaults, exception types, streaming, and client lifetimes. Replace with HTTPX."
339
+ "tomli".msg = "LIB010: Python 3.14 provides tomllib. Replace with tomllib."
340
+ "ujson".msg = "LIB005: Use orjson; its dumps function returns bytes and option semantics differ. Replace with orjson."
341
+
342
+ [lint.per-file-ignores]
343
+ # Tests legitimately assert, use fixtures and magic values, and invoke the
344
+ # binary under test. Scope those exemptions to test paths so assertion and
345
+ # hardcoded-secret checks remain active in shipped code. Test trees also need
346
+ # not be importable packages, and deterministic test PRNG use is not a secret
347
+ # generation risk.
348
+ "**/tests/**" = ["S101", "S105", "S106", "S311", "INP001", "FBT001", "FBT002", "FBT003", "PLR2004", "S404", "S603", "S607", "PLR6301"]
349
+ "**/test/**" = ["S311"]
350
+ "**/integration_tests/**" = ["S311"]
351
+ # A test-named module outside a test tree is still test code.
352
+ "**/test_*.py" = ["ANN201", "ANN202", "S101", "S105", "S106", "S311", "INP001"]
353
+ "**/*_test.py" = ["S311"]
354
+ "**/conftest.py" = ["S101", "S105", "S106", "S311", "INP001"]
355
+ # Standalone scripts are not importable packages, so INP001 does not apply.
356
+ "scripts/**" = ["T201", "S", "BLE001", "TRY002", "INP001"]
357
+ # CLI entrypoints print to stdout — that's their job, not stray debug output.
358
+ "**/__main__.py" = ["T201"]
359
+ "**/cli/**/*.py" = ["T201"]
360
+ # NOTE: `"__init__.py" = []` and `"**/settings.py" = []` used to sit here. Ruff
361
+ # per-file-ignores are additive and an empty list cannot un-ignore anything, so
362
+ # both entries were no-ops; they are removed rather than left as config that
363
+ # reads like an exemption.