@neralabs/rerail-pack-python 0.1.4 → 0.1.5
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.
- package/README.md +12 -9
- package/licenses/ruff/UPSTREAM.md +3 -3
- package/package.json +1 -1
- package/rules/ruff-async210-blocking-http-call-in-async-function.json +2 -2
- package/rules/ruff-async222-wait-for-process-in-async-function.json +2 -2
- package/rules/ruff-b905-zip-without-explicit-strict.json +2 -2
- package/rules/ruff-e711-none-comparison.json +189 -5
- package/rules/ruff-f541-f-string-missing-placeholders.json +2 -2
- package/rules/ruff-f632-is-literal.json +222 -5
- package/rules/ruff-f707-default-except-not-last.json +2 -2
- package/rules/ruff-sim112-uncapitalized-environment-variables.json +2 -2
- package/rules/ruff-sim300-yoda-conditions.json +2 -2
package/README.md
CHANGED
|
@@ -19,14 +19,17 @@ checked by `npx vitest run test/engine/catalog/packs.test.ts`.
|
|
|
19
19
|
| `licenses/<tool>/` | The tool's licence and `UPSTREAM.md`, listing every copied file |
|
|
20
20
|
| `candidates/rules/` | Ports still being evaluated (98 Ruff and Bandit ports): never shipped or listed in `pack.json`. 96 have a `conformance.json` port and are scored against the recordings without gating; A005 (GPL-derived fixtures only) and INP001 (tested only with a `namespace-packages` option) are not recorded |
|
|
21
21
|
|
|
22
|
-
Re-recording
|
|
23
|
-
|
|
22
|
+
Re-recording is a maintainer deriving the pack's test data from its pins and archiving it
|
|
23
|
+
([CONTRIBUTING.md](../../CONTRIBUTING.md#pack-test-data)); it is never committed. The recipe
|
|
24
|
+
(`scripts/pack-data/recipes/python.ts`) runs each tool's `generate.py`, in `fixtures` mode and then `corpus` mode over
|
|
25
|
+
django, against the pinned tool versions, under CPython 3.14 (Bandit itself runs from its own install, on CPython
|
|
26
|
+
3.13). The cases Rerail wrote (`fixtures/rerail/`) are authored: a change to them goes in your pull request with
|
|
27
|
+
`git add -f`.
|
|
24
28
|
|
|
25
29
|
```sh
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
python3.14 upstream/bandit/generate.py corpus <bandit 1.9.4 executable> django=<django checkout>
|
|
30
|
+
npm run fixtures:derive -- --pack python # every tool
|
|
31
|
+
npm run fixtures:derive -- --pack python --tool ruff # one
|
|
32
|
+
npm run fixtures:push -- --pack python --tool ruff # on your own branch: archive it and rewrite its test-data.lock
|
|
30
33
|
```
|
|
31
34
|
|
|
32
35
|
Scoring one rule with every false positive and false negative printed:
|
|
@@ -85,7 +88,7 @@ Only matches `xml.sax.parse/parseString/make_parser` calls that are direct child
|
|
|
85
88
|
|
|
86
89
|
### `bandit-b406-import-xml-sax`
|
|
87
90
|
|
|
88
|
-
Port of Bandit 1.9.4's B406 import_xml_sax. Divergence: an import of only xml.sax.saxutils (`from xml.sax.saxutils import ...`, `from xml.sax import saxutils`, aliased or parenthesised) is not reported. saxutils holds XML writing and escaping helpers (escape, quoteattr, unescape, XMLGenerator) and no parser, so defusedxml has nothing to replace it with. `import xml.sax.saxutils` is still reported, since it also binds xml.sax and its parse functions
|
|
91
|
+
Port of Bandit 1.9.4's B406 import_xml_sax. Divergence: an import of only xml.sax.saxutils (`from xml.sax.saxutils import ...`, `from xml.sax import saxutils`, aliased or parenthesised) is not reported. saxutils holds XML writing and escaping helpers (escape, quoteattr, unescape, XMLGenerator) and no parser, so defusedxml has nothing to replace it with. `import xml.sax.saxutils` is still reported, since it also binds xml.sax and its parse functions.
|
|
89
92
|
|
|
90
93
|
### `bandit-b501-request-with-no-cert-validation`
|
|
91
94
|
|
|
@@ -109,7 +112,7 @@ A `shell=` keyword counts as truthy per Bandit's has_shell: anything but a falsy
|
|
|
109
112
|
|
|
110
113
|
### `bandit-b610-django-extra-used`
|
|
111
114
|
|
|
112
|
-
Port of Bandit 1.9.4's B610 django_extra_used: a call of `extra` whose `where` or `tables` is not a list of plain strings, or whose `select` is not a dict of plain strings, bound to QuerySet.extra's six positional slots. Port of the kernel test b610_extra_with_a_non_literal_where_tables_or_select. `# nosec` honoured. Divergence: Bandit reports a call of any function or method named `extra`; the port reports only a method call whose receiver looks like a Django QuerySet or Manager: a name or attribute named `objects`, `qs`, `QS`, `queryset`, `querysets`, `manager` or `managers`, alone or after an underscore-joined prefix (`User.objects`, `self.queryset`, `base_qs`, `_default_manager`); a call of `get_queryset`; a method call on such a receiver (`User.objects.filter(...)`); or `self` or `super()` inside a class with a base whose name ends in `QuerySet` or is `Manager`, `BaseManager` or `BaseUserManager`, optionally dotted (`models.QuerySet`); a base that only ends in `Manager` (`AbstractContextManager`, `PluginManager`, `TreeManager`) does not count. A bare `extra(...)` call and `extra` on any other receiver are not reported
|
|
115
|
+
Port of Bandit 1.9.4's B610 django_extra_used: a call of `extra` whose `where` or `tables` is not a list of plain strings, or whose `select` is not a dict of plain strings, bound to QuerySet.extra's six positional slots. Port of the kernel test b610_extra_with_a_non_literal_where_tables_or_select. `# nosec` honoured. Divergence: Bandit reports a call of any function or method named `extra`; the port reports only a method call whose receiver looks like a Django QuerySet or Manager: a name or attribute named `objects`, `qs`, `QS`, `queryset`, `querysets`, `manager` or `managers`, alone or after an underscore-joined prefix (`User.objects`, `self.queryset`, `base_qs`, `_default_manager`); a call of `get_queryset`; a method call on such a receiver (`User.objects.filter(...)`); or `self` or `super()` inside a class with a base whose name ends in `QuerySet` or is `Manager`, `BaseManager` or `BaseUserManager`, optionally dotted (`models.QuerySet`); a base that only ends in `Manager` (`AbstractContextManager`, `PluginManager`, `TreeManager`) does not count. A bare `extra(...)` call and `extra` on any other receiver are not reported.
|
|
113
116
|
|
|
114
117
|
### `bandit-b613-trojansource`
|
|
115
118
|
|
|
@@ -505,7 +508,7 @@ Port of Ruff's F707 (default-except-not-last) with default settings: a bare `exc
|
|
|
505
508
|
|
|
506
509
|
### `ruff-f722-forward-annotation-syntax-error`
|
|
507
510
|
|
|
508
|
-
Port of Ruff's F722 (forward-annotation-syntax-error) with default settings: a string Ruff parses as a type definition (a string annotation, a `type` value, a `cast`/`TypeVar` argument, a typing generic's `"..."` slice), read with the `annotation` grammar. Three checks: a string Ruff's parser refuses (the parse is one `ERROR` node), reported on the string; each semantic syntax error Ruff's checker reports in a string it parsed (`await` or `yield` outside a function, a walrus rebinding a comprehension variable, duplicate arguments, `__debug__` stored, a name used before its `global`, ...: an `ERROR` node after the expression), reported at the offending node; and Ruff's second error on an `await` evaluated outside any function ("`await` statement outside of a function": the string's host is not in a function body with no class between them, and the `await` is not in a lambda's body or a generator expression's element, conditions or later iterables), at the `await`. Strings nested in one (`List['a b']` inside a string annotation) are read too. Not inside a function decorated with a `no_type_check` that resolves to `typing`, `_typeshed` or `typing_extensions` (Ruff's match_typing_expr): its parameters, defaults, return annotation and body. Ported from the Ruff conformance suite (rerail/conformance/ruff/rules/F722.json at 3f102adcb), with Ruff's `# noqa` honoured as the Ruff CLI honours it. Divergence: a string after the first element of a subscript whose generic resolves to a jaxtyping import (`Float[Array, "b n"]`, `jaxtyping.Float[...]`, `jt.Shaped[...]`) is a jaxtyping shape, which jaxtyping parses with its own grammar, not a forward annotation, so it is not reported. Ruff 0.16.9 reports it
|
|
511
|
+
Port of Ruff's F722 (forward-annotation-syntax-error) with default settings: a string Ruff parses as a type definition (a string annotation, a `type` value, a `cast`/`TypeVar` argument, a typing generic's `"..."` slice), read with the `annotation` grammar. Three checks: a string Ruff's parser refuses (the parse is one `ERROR` node), reported on the string; each semantic syntax error Ruff's checker reports in a string it parsed (`await` or `yield` outside a function, a walrus rebinding a comprehension variable, duplicate arguments, `__debug__` stored, a name used before its `global`, ...: an `ERROR` node after the expression), reported at the offending node; and Ruff's second error on an `await` evaluated outside any function ("`await` statement outside of a function": the string's host is not in a function body with no class between them, and the `await` is not in a lambda's body or a generator expression's element, conditions or later iterables), at the `await`. Strings nested in one (`List['a b']` inside a string annotation) are read too. Not inside a function decorated with a `no_type_check` that resolves to `typing`, `_typeshed` or `typing_extensions` (Ruff's match_typing_expr): its parameters, defaults, return annotation and body. Ported from the Ruff conformance suite (rerail/conformance/ruff/rules/F722.json at 3f102adcb), with Ruff's `# noqa` honoured as the Ruff CLI honours it. Divergence: a string after the first element of a subscript whose generic resolves to a jaxtyping import (`Float[Array, "b n"]`, `jaxtyping.Float[...]`, `jt.Shaped[...]`) is a jaxtyping shape, which jaxtyping parses with its own grammar, not a forward annotation, so it is not reported. Ruff 0.16.9 reports it. A shape inside a string annotation (`"Float[Array, 'b n']"`) is still reported.
|
|
509
512
|
|
|
510
513
|
### `ruff-f811-redefined-while-unused`
|
|
511
514
|
|
|
@@ -387,8 +387,8 @@ Paths are relative to the pack directory, `packs/python/`.
|
|
|
387
387
|
| `upstream/ruff/fixtures/syntax_errors/yield_scope.py` | `crates/ruff_linter/resources/test/fixtures/syntax_errors/yield_scope.py` | verbatim |
|
|
388
388
|
|
|
389
389
|
> `recording.json` is a port readiness recording, and no file of this pack, so it is recorded here rather than in the
|
|
390
|
-
> table above: the tool-pack's `recording.lock` names it
|
|
391
|
-
> It carries excerpts of this upstream's tests (`crates/ruff_linter/src/rules/*/mod.rs`,
|
|
390
|
+
> table above: the tool-pack's `recording.lock` names it by its sha256, and the bytes are an object in S3, not a file in
|
|
391
|
+
> git (docs/port-readiness.md). It carries excerpts of this upstream's tests (`crates/ruff_linter/src/rules/*/mod.rs`,
|
|
392
392
|
> `crates/ruff_linter/src/linter.rs`: their test modules' string literals), redistributed under the licence above,
|
|
393
|
-
> together with Rerail's Apache-2.0;
|
|
393
|
+
> together with Rerail's Apache-2.0; `LICENSE` beside this file is this upstream's own, at the pinned commit.
|
|
394
394
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-async210-blocking-http-call-in-async-function",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
6
|
"description": "Don't make blocking HTTP calls with requests, httpx, urllib or urllib3 inside async functions; they stall the event loop.",
|
|
7
7
|
"scope": {
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"violation": {
|
|
148
148
|
"anchor": "witness.span",
|
|
149
149
|
"code": "ASYNC210",
|
|
150
|
-
"message": "
|
|
150
|
+
"message": "Use an existing async client, or `await asyncio.to_thread(helper, ...)` for the request and response handling; preserve the API and options.",
|
|
151
151
|
"suppress": {
|
|
152
152
|
"noqa": {
|
|
153
153
|
"codes": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-async222-wait-for-process-in-async-function",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
6
|
"description": "Don't call os.wait, os.waitpid or the other blocking os.wait functions inside async functions; they block the event loop.",
|
|
7
7
|
"scope": {
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"violation": {
|
|
131
131
|
"anchor": "witness.span",
|
|
132
132
|
"code": "ASYNC222",
|
|
133
|
-
"message": "
|
|
133
|
+
"message": "Offload the wait with `await asyncio.to_thread(wait_fn, ...)`; preserve arguments and status. Await `proc.wait()` only for an async process.",
|
|
134
134
|
"suppress": {
|
|
135
135
|
"noqa": {
|
|
136
136
|
"codes": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-b905-zip-without-explicit-strict",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
6
|
"description": "Pass strict= explicitly to zip() over two or more iterables on Python 3.10+; otherwise mismatched lengths are truncated silently.",
|
|
7
7
|
"scope": {
|
|
@@ -415,7 +415,7 @@
|
|
|
415
415
|
"violation": {
|
|
416
416
|
"anchor": "witness.span",
|
|
417
417
|
"code": "B905",
|
|
418
|
-
"message": "`
|
|
418
|
+
"message": "Pass `strict=` explicitly: `strict=True` when lengths must match, `strict=False` when truncation is intended.",
|
|
419
419
|
"suppress": {
|
|
420
420
|
"noqa": {
|
|
421
421
|
"codes": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-e711-none-comparison",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
6
|
"description": "Use is None or is not None instead of == or != to compare with None; equality can be overridden and gives surprising results.",
|
|
7
7
|
"scope": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"clauses": [
|
|
14
14
|
{
|
|
15
|
-
"id": "none-comparison",
|
|
15
|
+
"id": "none-comparison-equal",
|
|
16
16
|
"forbid": {
|
|
17
17
|
"ast": {
|
|
18
18
|
"language": "python",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
{
|
|
114
114
|
"precedes": {
|
|
115
115
|
"stopBy": "neighbor",
|
|
116
|
-
"regex": "
|
|
116
|
+
"regex": "^==$",
|
|
117
117
|
"precedes": {
|
|
118
118
|
"stopBy": "neighbor",
|
|
119
119
|
"not": {
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
{
|
|
128
128
|
"follows": {
|
|
129
129
|
"stopBy": "neighbor",
|
|
130
|
-
"regex": "
|
|
130
|
+
"regex": "^==$",
|
|
131
131
|
"follows": {
|
|
132
132
|
"stopBy": "neighbor",
|
|
133
133
|
"not": {
|
|
@@ -185,7 +185,191 @@
|
|
|
185
185
|
"violation": {
|
|
186
186
|
"anchor": "witness.span",
|
|
187
187
|
"code": "E711",
|
|
188
|
-
"message": "
|
|
188
|
+
"message": "Use `is None` instead of `== None` for this comparison.",
|
|
189
|
+
"suppress": {
|
|
190
|
+
"noqa": {
|
|
191
|
+
"codes": [
|
|
192
|
+
"E711"
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"id": "none-comparison-not-equal",
|
|
200
|
+
"forbid": {
|
|
201
|
+
"ast": {
|
|
202
|
+
"language": "python",
|
|
203
|
+
"utils": {
|
|
204
|
+
"constant": {
|
|
205
|
+
"any": [
|
|
206
|
+
{
|
|
207
|
+
"kind": "string",
|
|
208
|
+
"not": {
|
|
209
|
+
"has": {
|
|
210
|
+
"stopBy": "end",
|
|
211
|
+
"kind": "interpolation"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"kind": "concatenated_string",
|
|
217
|
+
"not": {
|
|
218
|
+
"has": {
|
|
219
|
+
"stopBy": "end",
|
|
220
|
+
"kind": "interpolation"
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"kind": "integer"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"kind": "float"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"kind": "none"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"kind": "true"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"kind": "false"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"kind": "ellipsis"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"kind": "parenthesized_expression",
|
|
244
|
+
"has": {
|
|
245
|
+
"stopBy": "neighbor",
|
|
246
|
+
"matches": "constant"
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"kind": "tuple",
|
|
251
|
+
"not": {
|
|
252
|
+
"has": {
|
|
253
|
+
"stopBy": "neighbor",
|
|
254
|
+
"not": {
|
|
255
|
+
"any": [
|
|
256
|
+
{
|
|
257
|
+
"matches": "constant"
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"regex": "^[(),]$"
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
},
|
|
269
|
+
"constant-non-singleton": {
|
|
270
|
+
"all": [
|
|
271
|
+
{
|
|
272
|
+
"matches": "constant"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"not": {
|
|
276
|
+
"matches": "singleton"
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
]
|
|
280
|
+
},
|
|
281
|
+
"compared-operand": {
|
|
282
|
+
"inside": {
|
|
283
|
+
"stopBy": "neighbor",
|
|
284
|
+
"kind": "comparison_operator"
|
|
285
|
+
},
|
|
286
|
+
"any": [
|
|
287
|
+
{
|
|
288
|
+
"all": [
|
|
289
|
+
{
|
|
290
|
+
"not": {
|
|
291
|
+
"follows": {
|
|
292
|
+
"stopBy": "neighbor",
|
|
293
|
+
"regex": "(?s)."
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"precedes": {
|
|
299
|
+
"stopBy": "neighbor",
|
|
300
|
+
"regex": "^!=$",
|
|
301
|
+
"precedes": {
|
|
302
|
+
"stopBy": "neighbor",
|
|
303
|
+
"not": {
|
|
304
|
+
"matches": "constant-non-singleton"
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
"follows": {
|
|
313
|
+
"stopBy": "neighbor",
|
|
314
|
+
"regex": "^!=$",
|
|
315
|
+
"follows": {
|
|
316
|
+
"stopBy": "neighbor",
|
|
317
|
+
"not": {
|
|
318
|
+
"matches": "constant-non-singleton"
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
},
|
|
325
|
+
"operand": {
|
|
326
|
+
"any": [
|
|
327
|
+
{
|
|
328
|
+
"matches": "compared-operand"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"inside": {
|
|
332
|
+
"stopBy": "neighbor",
|
|
333
|
+
"kind": "parenthesized_expression",
|
|
334
|
+
"matches": "operand"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
]
|
|
338
|
+
},
|
|
339
|
+
"singleton": {
|
|
340
|
+
"any": [
|
|
341
|
+
{
|
|
342
|
+
"kind": "none"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"kind": "true"
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"kind": "false"
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"kind": "ellipsis"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"kind": "parenthesized_expression",
|
|
355
|
+
"has": {
|
|
356
|
+
"stopBy": "neighbor",
|
|
357
|
+
"matches": "singleton"
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
]
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
"rule": {
|
|
364
|
+
"kind": "none",
|
|
365
|
+
"matches": "operand"
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
"violation": {
|
|
370
|
+
"anchor": "witness.span",
|
|
371
|
+
"code": "E711",
|
|
372
|
+
"message": "Use `is not None` instead of `!= None` for this comparison.",
|
|
189
373
|
"suppress": {
|
|
190
374
|
"noqa": {
|
|
191
375
|
"codes": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-f541-f-string-missing-placeholders",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
6
|
"description": "Remove the f prefix from Python f-strings that have no placeholders; it suggests interpolation that never happens.",
|
|
7
7
|
"scope": { "include": ["**/*"], "exclude": [] },
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"violation": {
|
|
39
39
|
"anchor": "witness.span",
|
|
40
40
|
"code": "F541",
|
|
41
|
-
"message": "Remove the `f` prefix
|
|
41
|
+
"message": "Remove the `f` prefix and unescape doubled braces to keep this string's runtime value unchanged.",
|
|
42
42
|
"suppress": {
|
|
43
43
|
"noqa": {
|
|
44
44
|
"codes": [
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-f632-is-literal",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
|
-
"description": "Use == instead of is
|
|
6
|
+
"description": "Use == or != instead of is or is not to compare literal values; the identity of such values is unreliable.",
|
|
7
7
|
"scope": {
|
|
8
8
|
"include": [
|
|
9
9
|
"**/*"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"clauses": [
|
|
14
14
|
{
|
|
15
|
-
"id": "is-literal",
|
|
15
|
+
"id": "is-literal-is",
|
|
16
16
|
"forbid": {
|
|
17
17
|
"ast": {
|
|
18
18
|
"language": "python",
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
]
|
|
151
151
|
},
|
|
152
152
|
"is-literal-op": {
|
|
153
|
-
"regex": "^is
|
|
153
|
+
"regex": "^is$",
|
|
154
154
|
"any": [
|
|
155
155
|
{
|
|
156
156
|
"follows": {
|
|
@@ -217,7 +217,224 @@
|
|
|
217
217
|
"violation": {
|
|
218
218
|
"anchor": "capture.C",
|
|
219
219
|
"code": "F632",
|
|
220
|
-
"message": "Use `==` to compare
|
|
220
|
+
"message": "Use `==` instead of `is` to compare this literal value.",
|
|
221
|
+
"each": "O",
|
|
222
|
+
"suppress": {
|
|
223
|
+
"noqa": {
|
|
224
|
+
"codes": [
|
|
225
|
+
"F632"
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"id": "is-literal-is-not",
|
|
233
|
+
"forbid": {
|
|
234
|
+
"ast": {
|
|
235
|
+
"language": "python",
|
|
236
|
+
"utils": {
|
|
237
|
+
"constant": {
|
|
238
|
+
"any": [
|
|
239
|
+
{
|
|
240
|
+
"kind": "string",
|
|
241
|
+
"not": {
|
|
242
|
+
"has": {
|
|
243
|
+
"stopBy": "end",
|
|
244
|
+
"kind": "interpolation"
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"kind": "concatenated_string",
|
|
250
|
+
"not": {
|
|
251
|
+
"has": {
|
|
252
|
+
"stopBy": "end",
|
|
253
|
+
"kind": "interpolation"
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"kind": "integer"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"kind": "float"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"kind": "none"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"kind": "true"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"kind": "false"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"kind": "ellipsis"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"kind": "parenthesized_expression",
|
|
277
|
+
"has": {
|
|
278
|
+
"stopBy": "neighbor",
|
|
279
|
+
"matches": "constant"
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"kind": "tuple",
|
|
284
|
+
"not": {
|
|
285
|
+
"has": {
|
|
286
|
+
"stopBy": "neighbor",
|
|
287
|
+
"not": {
|
|
288
|
+
"any": [
|
|
289
|
+
{
|
|
290
|
+
"matches": "constant"
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"regex": "^[(),]$"
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
]
|
|
301
|
+
},
|
|
302
|
+
"singleton": {
|
|
303
|
+
"any": [
|
|
304
|
+
{
|
|
305
|
+
"kind": "none"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"kind": "true"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"kind": "false"
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"kind": "ellipsis"
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"kind": "parenthesized_expression",
|
|
318
|
+
"has": {
|
|
319
|
+
"stopBy": "neighbor",
|
|
320
|
+
"matches": "singleton"
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
},
|
|
325
|
+
"constant-non-singleton": {
|
|
326
|
+
"all": [
|
|
327
|
+
{
|
|
328
|
+
"matches": "constant"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"not": {
|
|
332
|
+
"matches": "singleton"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
]
|
|
336
|
+
},
|
|
337
|
+
"literal-operand": {
|
|
338
|
+
"any": [
|
|
339
|
+
{
|
|
340
|
+
"matches": "constant-non-singleton"
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
"kind": "set"
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"kind": "set_comprehension"
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"kind": "list"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
"kind": "list_comprehension"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"kind": "dictionary"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"kind": "dictionary_comprehension"
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"kind": "parenthesized_expression",
|
|
362
|
+
"has": {
|
|
363
|
+
"stopBy": "neighbor",
|
|
364
|
+
"matches": "literal-operand"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
},
|
|
369
|
+
"is-literal-op": {
|
|
370
|
+
"regex": "^is[\\s\\\\]+not$",
|
|
371
|
+
"any": [
|
|
372
|
+
{
|
|
373
|
+
"follows": {
|
|
374
|
+
"stopBy": "neighbor",
|
|
375
|
+
"matches": "literal-operand"
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"precedes": {
|
|
380
|
+
"stopBy": "neighbor",
|
|
381
|
+
"matches": "literal-operand"
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
]
|
|
385
|
+
},
|
|
386
|
+
"is-literal-in-string": {
|
|
387
|
+
"any": [
|
|
388
|
+
{
|
|
389
|
+
"kind": "string"
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"kind": "concatenated_string"
|
|
393
|
+
}
|
|
394
|
+
],
|
|
395
|
+
"parse": {
|
|
396
|
+
"grammar": "annotation",
|
|
397
|
+
"has": {
|
|
398
|
+
"stopBy": "end",
|
|
399
|
+
"any": [
|
|
400
|
+
{
|
|
401
|
+
"kind": "comparison_operator",
|
|
402
|
+
"has": {
|
|
403
|
+
"stopBy": "neighbor",
|
|
404
|
+
"matches": "is-literal-op",
|
|
405
|
+
"capture": "O"
|
|
406
|
+
},
|
|
407
|
+
"capture": "C"
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
"matches": "is-literal-in-string"
|
|
411
|
+
}
|
|
412
|
+
]
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
"rule": {
|
|
418
|
+
"any": [
|
|
419
|
+
{
|
|
420
|
+
"matches": "is-literal-op",
|
|
421
|
+
"inside": {
|
|
422
|
+
"stopBy": "neighbor",
|
|
423
|
+
"kind": "comparison_operator",
|
|
424
|
+
"pattern": "$C"
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"matches": "is-literal-in-string"
|
|
429
|
+
}
|
|
430
|
+
]
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
"violation": {
|
|
435
|
+
"anchor": "capture.C",
|
|
436
|
+
"code": "F632",
|
|
437
|
+
"message": "Use `!=` instead of `is not` to compare this literal value.",
|
|
221
438
|
"each": "O",
|
|
222
439
|
"suppress": {
|
|
223
440
|
"noqa": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-f707-default-except-not-last",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
6
|
"description": "Put a bare except handler last in its try statement; Python rejects any handler after it.",
|
|
7
7
|
"scope": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"violation": {
|
|
37
37
|
"anchor": "witness.span",
|
|
38
38
|
"code": "F707",
|
|
39
|
-
"message": "
|
|
39
|
+
"message": "Move this bare `except:` handler after all typed handlers; a bare handler must be last.",
|
|
40
40
|
"suppress": {
|
|
41
41
|
"noqa": {
|
|
42
42
|
"codes": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-sim112-uncapitalized-environment-variables",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
6
|
"description": "Use uppercase names when reading environment variables through os.environ or os.getenv; the lowercase proxy variables are exempt.",
|
|
7
7
|
"scope": {
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
"violation": {
|
|
155
155
|
"anchor": "witness.span",
|
|
156
156
|
"code": "SIM112",
|
|
157
|
-
"message": "
|
|
157
|
+
"message": "Uppercase only if the deployment uses that name; preserve intentional lowercase keys because lookups are case-sensitive on POSIX.",
|
|
158
158
|
"suppress": {
|
|
159
159
|
"noqa": {
|
|
160
160
|
"codes": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "rerail.policy/v1",
|
|
3
3
|
"id": "ruff-sim300-yoda-conditions",
|
|
4
|
-
"revision":
|
|
4
|
+
"revision": 2,
|
|
5
5
|
"mode": "steer",
|
|
6
6
|
"description": "Put the variable first and the constant or literal second in comparisons, avoiding Yoda conditions; it reads the way you would say it.",
|
|
7
7
|
"scope": {
|
|
@@ -473,7 +473,7 @@
|
|
|
473
473
|
"violation": {
|
|
474
474
|
"anchor": "witness.span",
|
|
475
475
|
"code": "SIM300",
|
|
476
|
-
"message": "
|
|
476
|
+
"message": "Put the variable first; reverse `<`/`>` and `<=`/`>=` when swapping operands, and keep equality operators unchanged.",
|
|
477
477
|
"suppress": {
|
|
478
478
|
"noqa": {
|
|
479
479
|
"codes": [
|