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.
- code_standards-7.0.0.dist-info/METADATA +53 -0
- code_standards-7.0.0.dist-info/RECORD +99 -0
- code_standards-7.0.0.dist-info/WHEEL +4 -0
- code_standards-7.0.0.dist-info/entry_points.txt +3 -0
- code_standards-7.0.0.dist-info/licenses/LICENSE +21 -0
- sarj_standards/__init__.py +30 -0
- sarj_standards/__main__.py +5 -0
- sarj_standards/_meta.py +22 -0
- sarj_standards/api.py +890 -0
- sarj_standards/cli/__init__.py +0 -0
- sarj_standards/cli/main.py +2466 -0
- sarj_standards/configs/cli-reference.v1.json +1 -0
- sarj_standards/configs/doctor.config.json +22 -0
- sarj_standards/configs/eslint.application.mjs +1366 -0
- sarj_standards/configs/eslint.peers.json +44 -0
- sarj_standards/configs/eslint.strict.mjs +1060 -0
- sarj_standards/configs/markdownlint.strict.yaml +12 -0
- sarj_standards/configs/pyright.strict.json +96 -0
- sarj_standards/configs/ruff.application.toml +363 -0
- sarj_standards/configs/ruff.strict.toml +338 -0
- sarj_standards/configs/rule-inventory.v1.json +1 -0
- sarj_standards/configs/rule-ledger.json +846 -0
- sarj_standards/configs/rule-warning-levels.v1.json +1 -0
- sarj_standards/configs/taplo.strict.toml +14 -0
- sarj_standards/configs/yamllint.strict.yaml +25 -0
- sarj_standards/libs/__init__.py +0 -0
- sarj_standards/libs/adoption/__init__.py +0 -0
- sarj_standards/libs/adoption/configs.py +36 -0
- sarj_standards/libs/adoption/doctor.py +1346 -0
- sarj_standards/libs/adoption/exclusions.py +66 -0
- sarj_standards/libs/adoption/hooks.py +423 -0
- sarj_standards/libs/adoption/launcher.py +240 -0
- sarj_standards/libs/adoption/lifecycle.py +493 -0
- sarj_standards/libs/adoption/manifest.py +550 -0
- sarj_standards/libs/adoption/packagemanager.py +285 -0
- sarj_standards/libs/adoption/retired_suppressions.py +371 -0
- sarj_standards/libs/adoption/scaffold.py +1660 -0
- sarj_standards/libs/adoption/service.py +441 -0
- sarj_standards/libs/adoption/transaction.py +274 -0
- sarj_standards/libs/adoption/upgrade.py +516 -0
- sarj_standards/libs/adoption/uvtool.py +62 -0
- sarj_standards/libs/catalogs/__init__.py +9 -0
- sarj_standards/libs/catalogs/slack_automations.py +627 -0
- sarj_standards/libs/corpus/__init__.py +25 -0
- sarj_standards/libs/corpus/manifest.py +211 -0
- sarj_standards/libs/corpus/snapshot.py +222 -0
- sarj_standards/libs/diagnostics/__init__.py +65 -0
- sarj_standards/libs/diagnostics/analysis.schema.json +161 -0
- sarj_standards/libs/diagnostics/baseline.py +131 -0
- sarj_standards/libs/diagnostics/models.py +574 -0
- sarj_standards/libs/diagnostics/serialize.py +290 -0
- sarj_standards/libs/diagnostics/source.py +172 -0
- sarj_standards/libs/filesystem.py +11 -0
- sarj_standards/libs/linting/__init__.py +0 -0
- sarj_standards/libs/linting/analysis.py +422 -0
- sarj_standards/libs/linting/external.py +1454 -0
- sarj_standards/libs/linting/library_policy.py +688 -0
- sarj_standards/libs/linting/policy.py +152 -0
- sarj_standards/libs/linting/runner.py +442 -0
- sarj_standards/libs/linting/textlint.py +1605 -0
- sarj_standards/libs/release/__init__.py +98 -0
- sarj_standards/libs/release/_values.py +24 -0
- sarj_standards/libs/release/artifacts.py +191 -0
- sarj_standards/libs/release/causality.py +80 -0
- sarj_standards/libs/release/changes.py +48 -0
- sarj_standards/libs/release/process.py +128 -0
- sarj_standards/libs/release/publish.py +85 -0
- sarj_standards/libs/release/registry.py +271 -0
- sarj_standards/libs/release/release_age.py +218 -0
- sarj_standards/libs/release/rollout.py +1163 -0
- sarj_standards/libs/release/tags.py +373 -0
- sarj_standards/libs/release/typescript.py +191 -0
- sarj_standards/libs/repository/__init__.py +0 -0
- sarj_standards/libs/repository/cli_reference_artifact.py +324 -0
- sarj_standards/libs/repository/comment_corpus.py +536 -0
- sarj_standards/libs/repository/config_generation.py +146 -0
- sarj_standards/libs/repository/docs.py +347 -0
- sarj_standards/libs/repository/hooks.py +118 -0
- sarj_standards/libs/repository/ledger.py +99 -0
- sarj_standards/libs/repository/repository.py +744 -0
- sarj_standards/libs/repository/rule_authoring.py +246 -0
- sarj_standards/libs/repository/rule_catalog_artifact.py +479 -0
- sarj_standards/libs/repository/rule_changes.py +318 -0
- sarj_standards/libs/repository/rule_inventory_artifact.py +142 -0
- sarj_standards/libs/repository/rule_lifecycle.py +167 -0
- sarj_standards/libs/repository/rule_maintenance.py +225 -0
- sarj_standards/libs/rules/__init__.py +74 -0
- sarj_standards/libs/rules/catalog.py +145 -0
- sarj_standards/libs/rules/contracts.py +382 -0
- sarj_standards/libs/rules/corpus_runner.py +365 -0
- sarj_standards/libs/rules/evaluation.py +177 -0
- sarj_standards/libs/setup/__init__.py +4 -0
- sarj_standards/libs/setup/repository.py +40 -0
- sarj_standards/py.typed +0 -0
- sarj_standards/schemas/__init__.py +4 -0
- sarj_standards/schemas/_paths.py +7 -0
- sarj_standards/schemas/rule-catalog.v1.json +1 -0
- sarj_standards/schemas/rule-catalog.v1.schema.json +112 -0
- 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.
|