codelaw-rules-python 0.2.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 (139) hide show
  1. codelaw_rules_python/LICENSE +23 -0
  2. codelaw_rules_python/NOTICE +14 -0
  3. codelaw_rules_python/README.md +189 -0
  4. codelaw_rules_python/codelaw-pack.toml +6 -0
  5. codelaw_rules_python/corpus.toml +103 -0
  6. codelaw_rules_python/data/python/stdlib.json +331 -0
  7. codelaw_rules_python/presets/py/conventions.toml +5 -0
  8. codelaw_rules_python/presets/py/project.toml +4 -0
  9. codelaw_rules_python/presets/py/recommended.toml +99 -0
  10. codelaw_rules_python/rules/graph/no-unused-exports.md +69 -0
  11. codelaw_rules_python/rules/py/abstract-base-class-without-abstract-method.md +50 -0
  12. codelaw_rules_python/rules/py/all-sorted.cases.md +74 -0
  13. codelaw_rules_python/rules/py/all-sorted.md +33 -0
  14. codelaw_rules_python/rules/py/ambiguous-class-name.md +41 -0
  15. codelaw_rules_python/rules/py/ambiguous-function-name.md +41 -0
  16. codelaw_rules_python/rules/py/ambiguous-variable-name.cases.md +47 -0
  17. codelaw_rules_python/rules/py/ambiguous-variable-name.md +39 -0
  18. codelaw_rules_python/rules/py/assert-false.md +34 -0
  19. codelaw_rules_python/rules/py/assert-raises-exception.md +51 -0
  20. codelaw_rules_python/rules/py/assert-tuple.md +38 -0
  21. codelaw_rules_python/rules/py/assignment-to-os-environ.md +43 -0
  22. codelaw_rules_python/rules/py/batched-without-explicit-strict.md +52 -0
  23. codelaw_rules_python/rules/py/break-outside-loop.md +41 -0
  24. codelaw_rules_python/rules/py/cached-instance-method.md +55 -0
  25. codelaw_rules_python/rules/py/continue-outside-loop.md +41 -0
  26. codelaw_rules_python/rules/py/default-except-not-last.md +48 -0
  27. codelaw_rules_python/rules/py/duplicate-dict-key-variable.md +39 -0
  28. codelaw_rules_python/rules/py/duplicate-dict-key.md +39 -0
  29. codelaw_rules_python/rules/py/duplicate-handler-exception.md +43 -0
  30. codelaw_rules_python/rules/py/duplicate-set-value.md +33 -0
  31. codelaw_rules_python/rules/py/duplicate-try-block-exception.md +47 -0
  32. codelaw_rules_python/rules/py/empty-method-without-abstract-decorator.md +55 -0
  33. codelaw_rules_python/rules/py/except-with-empty-tuple.md +44 -0
  34. codelaw_rules_python/rules/py/except-with-non-exception-classes.md +44 -0
  35. codelaw_rules_python/rules/py/f-string-docstring.md +40 -0
  36. codelaw_rules_python/rules/py/f-string-missing-placeholders.cases.md +49 -0
  37. codelaw_rules_python/rules/py/f-string-missing-placeholders.md +33 -0
  38. codelaw_rules_python/rules/py/format-invalid.md +38 -0
  39. codelaw_rules_python/rules/py/format-missing-argument.md +38 -0
  40. codelaw_rules_python/rules/py/format-mixed-numbering.md +38 -0
  41. codelaw_rules_python/rules/py/format-unused-named-argument.md +37 -0
  42. codelaw_rules_python/rules/py/format-unused-positional-argument.md +37 -0
  43. codelaw_rules_python/rules/py/forward-annotation-syntax-error.md +44 -0
  44. codelaw_rules_python/rules/py/function-call-in-default-argument.md +51 -0
  45. codelaw_rules_python/rules/py/function-uses-loop-variable.cases.md +57 -0
  46. codelaw_rules_python/rules/py/function-uses-loop-variable.md +42 -0
  47. codelaw_rules_python/rules/py/getattr-with-constant.cases.md +31 -0
  48. codelaw_rules_python/rules/py/getattr-with-constant.md +33 -0
  49. codelaw_rules_python/rules/py/if-tuple.md +40 -0
  50. codelaw_rules_python/rules/py/import-shadowed-by-loop-var.md +45 -0
  51. codelaw_rules_python/rules/py/invalid-print-syntax.md +42 -0
  52. codelaw_rules_python/rules/py/is-literal.md +36 -0
  53. codelaw_rules_python/rules/py/jump-statement-in-finally.cases.md +15 -0
  54. codelaw_rules_python/rules/py/jump-statement-in-finally.md +47 -0
  55. codelaw_rules_python/rules/py/lambda-assignment.cases.md +48 -0
  56. codelaw_rules_python/rules/py/lambda-assignment.md +35 -0
  57. codelaw_rules_python/rules/py/late-future-import.md +40 -0
  58. codelaw_rules_python/rules/py/loop-variable-overrides-iterator.md +41 -0
  59. codelaw_rules_python/rules/py/map-without-explicit-strict.md +46 -0
  60. codelaw_rules_python/rules/py/module-import-not-at-top.cases.md +64 -0
  61. codelaw_rules_python/rules/py/module-import-not-at-top.md +46 -0
  62. codelaw_rules_python/rules/py/multiple-imports-on-one-line.md +38 -0
  63. codelaw_rules_python/rules/py/multiple-starred-expressions.md +38 -0
  64. codelaw_rules_python/rules/py/mutable-contextvar-default.md +42 -0
  65. codelaw_rules_python/rules/py/nested-star-import.md +42 -0
  66. codelaw_rules_python/rules/py/no-bare-except.cases.md +37 -0
  67. codelaw_rules_python/rules/py/no-bare-except.md +44 -0
  68. codelaw_rules_python/rules/py/no-explicit-stacklevel.md +38 -0
  69. codelaw_rules_python/rules/py/no-mutable-default.cases.md +58 -0
  70. codelaw_rules_python/rules/py/no-mutable-default.md +44 -0
  71. codelaw_rules_python/rules/py/no-print.cases.md +40 -0
  72. codelaw_rules_python/rules/py/no-print.md +42 -0
  73. codelaw_rules_python/rules/py/no-star-import.cases.md +11 -0
  74. codelaw_rules_python/rules/py/no-star-import.md +47 -0
  75. codelaw_rules_python/rules/py/no-tunable-literals.cases.md +54 -0
  76. codelaw_rules_python/rules/py/no-tunable-literals.md +58 -0
  77. codelaw_rules_python/rules/py/none-comparison.md +36 -0
  78. codelaw_rules_python/rules/py/not-in-test.md +35 -0
  79. codelaw_rules_python/rules/py/not-is-test.md +35 -0
  80. codelaw_rules_python/rules/py/percent-format-count-mismatch.md +38 -0
  81. codelaw_rules_python/rules/py/percent-format-expected-mapping.md +38 -0
  82. codelaw_rules_python/rules/py/percent-format-expected-sequence.md +38 -0
  83. codelaw_rules_python/rules/py/percent-format-invalid.md +38 -0
  84. codelaw_rules_python/rules/py/percent-format-missing-argument.md +38 -0
  85. codelaw_rules_python/rules/py/percent-format-mixed-placeholders.md +38 -0
  86. codelaw_rules_python/rules/py/percent-format-star-requires-sequence.md +38 -0
  87. codelaw_rules_python/rules/py/percent-format-unsupported-character.md +38 -0
  88. codelaw_rules_python/rules/py/percent-format-unused-named-argument.md +37 -0
  89. codelaw_rules_python/rules/py/raise-literal.md +38 -0
  90. codelaw_rules_python/rules/py/raise-not-implemented.md +38 -0
  91. codelaw_rules_python/rules/py/raise-without-from-inside-except.cases.md +46 -0
  92. codelaw_rules_python/rules/py/raise-without-from-inside-except.md +45 -0
  93. codelaw_rules_python/rules/py/re-sub-positional-args.md +42 -0
  94. codelaw_rules_python/rules/py/redefined-while-unused.cases.md +186 -0
  95. codelaw_rules_python/rules/py/redefined-while-unused.md +53 -0
  96. codelaw_rules_python/rules/py/redundant-tuple-in-exception-handler.md +39 -0
  97. codelaw_rules_python/rules/py/return-outside-function.md +41 -0
  98. codelaw_rules_python/rules/py/reuse-of-groupby-generator.cases.md +40 -0
  99. codelaw_rules_python/rules/py/reuse-of-groupby-generator.md +46 -0
  100. codelaw_rules_python/rules/py/setattr-with-constant.md +33 -0
  101. codelaw_rules_python/rules/py/star-arg-unpacking-after-keyword-arg.md +38 -0
  102. codelaw_rules_python/rules/py/star-import-usage.cases.md +35 -0
  103. codelaw_rules_python/rules/py/star-import-usage.md +43 -0
  104. codelaw_rules_python/rules/py/static-key-dict-comprehension.md +38 -0
  105. codelaw_rules_python/rules/py/strip-with-multi-characters.md +39 -0
  106. codelaw_rules_python/rules/py/too-many-expressions-in-star-assignment.md +38 -0
  107. codelaw_rules_python/rules/py/true-false-comparison.cases.md +33 -0
  108. codelaw_rules_python/rules/py/true-false-comparison.md +36 -0
  109. codelaw_rules_python/rules/py/type-comparison.md +41 -0
  110. codelaw_rules_python/rules/py/unary-prefix-increment.md +40 -0
  111. codelaw_rules_python/rules/py/undefined-export.md +55 -0
  112. codelaw_rules_python/rules/py/undefined-future-feature.md +39 -0
  113. codelaw_rules_python/rules/py/undefined-local.cases.md +80 -0
  114. codelaw_rules_python/rules/py/undefined-local.md +48 -0
  115. codelaw_rules_python/rules/py/undefined-name.cases.md +132 -0
  116. codelaw_rules_python/rules/py/undefined-name.md +42 -0
  117. codelaw_rules_python/rules/py/unintentional-type-annotation.cases.md +13 -0
  118. codelaw_rules_python/rules/py/unintentional-type-annotation.md +38 -0
  119. codelaw_rules_python/rules/py/unreliable-callable-check.md +36 -0
  120. codelaw_rules_python/rules/py/unsorted-imports.cases.md +159 -0
  121. codelaw_rules_python/rules/py/unsorted-imports.md +60 -0
  122. codelaw_rules_python/rules/py/unused-annotation.md +36 -0
  123. codelaw_rules_python/rules/py/unused-import.cases.md +289 -0
  124. codelaw_rules_python/rules/py/unused-import.md +45 -0
  125. codelaw_rules_python/rules/py/unused-loop-control-variable.cases.md +30 -0
  126. codelaw_rules_python/rules/py/unused-loop-control-variable.md +36 -0
  127. codelaw_rules_python/rules/py/unused-variable.cases.md +169 -0
  128. codelaw_rules_python/rules/py/unused-variable.md +38 -0
  129. codelaw_rules_python/rules/py/useless-comparison.md +41 -0
  130. codelaw_rules_python/rules/py/useless-contextlib-suppress.md +44 -0
  131. codelaw_rules_python/rules/py/useless-expression.cases.md +57 -0
  132. codelaw_rules_python/rules/py/useless-expression.md +45 -0
  133. codelaw_rules_python/rules/py/yield-outside-function.md +44 -0
  134. codelaw_rules_python/rules/py/zip-without-explicit-strict.cases.md +26 -0
  135. codelaw_rules_python/rules/py/zip-without-explicit-strict.md +46 -0
  136. codelaw_rules_python-0.2.0.dist-info/METADATA +199 -0
  137. codelaw_rules_python-0.2.0.dist-info/RECORD +139 -0
  138. codelaw_rules_python-0.2.0.dist-info/WHEEL +4 -0
  139. codelaw_rules_python-0.2.0.dist-info/licenses/LICENSE +23 -0
@@ -0,0 +1,289 @@
1
+ # py/unused-import — cases
2
+
3
+ ### case: every import of a block
4
+
5
+ ```py
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ import a
10
+ import b
11
+ ```
12
+
13
+ ```expect
14
+ 4:12 py/unused-import
15
+ 5:12 py/unused-import
16
+ ```
17
+
18
+ ```fixed
19
+ from typing import TYPE_CHECKING
20
+
21
+ if TYPE_CHECKING:
22
+ pass
23
+ ```
24
+
25
+ ### case: names nested in an annotation with a default
26
+
27
+ ```py
28
+ from typing import List, Optional
29
+
30
+
31
+ def main(args: Optional[List[str]] = None) -> int:
32
+ return 0
33
+ ```
34
+
35
+ ```expect
36
+ (none)
37
+ ```
38
+
39
+ ### case: annotated assignment
40
+
41
+ ```py
42
+ from typing import Any, Set
43
+
44
+
45
+ def f():
46
+ seen: Set[Any] = set()
47
+ return seen
48
+ ```
49
+
50
+ ```expect
51
+ (none)
52
+ ```
53
+
54
+ ### case: string inside a typing generic
55
+
56
+ ```py
57
+ from typing import TYPE_CHECKING, Dict
58
+
59
+ if TYPE_CHECKING:
60
+ from .names import NormalizedName
61
+
62
+ PackageSet = Dict["NormalizedName", int]
63
+ ```
64
+
65
+ ```expect
66
+ (none)
67
+ ```
68
+
69
+ ### case: type comments are not read, as in Ruff
70
+
71
+ ```py
72
+ from types import TracebackType
73
+
74
+
75
+ def f(a):
76
+ # type: (TracebackType) -> None
77
+ pass
78
+ ```
79
+
80
+ ```expect
81
+ 1:19 py/unused-import
82
+ ```
83
+
84
+ ### case: listed in __all__
85
+
86
+ ```py
87
+ from .core import load
88
+
89
+ __all__ = ["load"]
90
+ ```
91
+
92
+ ```expect
93
+ (none)
94
+ ```
95
+
96
+ ### case: redundant alias re-exports
97
+
98
+ ```py
99
+ from .core import load as load
100
+ ```
101
+
102
+ ```expect
103
+ (none)
104
+ ```
105
+
106
+ ### case: used only in a string annotation
107
+
108
+ ```py
109
+ from typing import TYPE_CHECKING
110
+
111
+ if TYPE_CHECKING:
112
+ from .models import User
113
+
114
+
115
+ def name(user: "User") -> str:
116
+ return ""
117
+ ```
118
+
119
+ ```expect
120
+ (none)
121
+ ```
122
+
123
+ ### case: future imports are used by being there
124
+
125
+ ```py
126
+ from __future__ import annotations
127
+ ```
128
+
129
+ ```expect
130
+ (none)
131
+ ```
132
+
133
+ ### case: one of several names
134
+
135
+ ```py
136
+ from os.path import join, split
137
+
138
+ print(join("a", "b"))
139
+ ```
140
+
141
+ ```expect
142
+ 1:27 py/unused-import
143
+ ```
144
+
145
+ ```fixed
146
+ from os.path import join
147
+
148
+ print(join("a", "b"))
149
+ ```
150
+
151
+ ### case: import with a fallback in except
152
+
153
+ ```py
154
+ try:
155
+ import ujson
156
+ except ImportError:
157
+ ujson = None
158
+ ```
159
+
160
+ ```expect
161
+ (none)
162
+ ```
163
+
164
+ ### case: last import of a name wins
165
+
166
+ ```py
167
+ import re
168
+ import re
169
+ ```
170
+
171
+ ```expect
172
+ 2:8 py/unused-import
173
+ ```
174
+
175
+ ### case: function-level import
176
+
177
+ ```py
178
+ def f():
179
+ import json
180
+ return 1
181
+ ```
182
+
183
+ ```expect
184
+ 2:12 py/unused-import
185
+ ```
186
+
187
+ ```fixed
188
+ def f():
189
+ return 1
190
+ ```
191
+
192
+ ### case: used inside a function
193
+
194
+ ```py
195
+ import json
196
+
197
+
198
+ def f():
199
+ return json.dumps({})
200
+ ```
201
+
202
+ ```expect
203
+ (none)
204
+ ```
205
+
206
+ ### case: importing __all__ defines the exports
207
+
208
+ ```py
209
+ from io import __all__
210
+ ```
211
+
212
+ ```expect
213
+ (none)
214
+ ```
215
+
216
+ ### case: class-level import is an attribute
217
+
218
+ ```py
219
+ class C:
220
+ from os.path import join
221
+ ```
222
+
223
+ ```expect
224
+ (none)
225
+ ```
226
+
227
+ ### case: submodule loaded for an aliased package
228
+
229
+ ```py
230
+ import multiprocessing as mp
231
+ import multiprocessing.connection
232
+
233
+ mp.connection.wait([])
234
+ ```
235
+
236
+ ```expect
237
+ (none)
238
+ ```
239
+
240
+ ### case: __all__ built from another module's __all__
241
+
242
+ ```py
243
+ from . import sub
244
+ from .sub import *
245
+ from .core import load
246
+
247
+ __all__ = ["sub"] + sub.__all__
248
+ ```
249
+
250
+ ```expect
251
+ (none)
252
+ ```
253
+
254
+ ### case: __all__ extended and appended
255
+
256
+ ```py
257
+ from .core import load, save, drop
258
+
259
+ __all__ = []
260
+ __all__.extend(["load"])
261
+ __all__.append("save")
262
+ ```
263
+
264
+ ```expect
265
+ 1:31 py/unused-import
266
+ ```
267
+
268
+ ```fixed
269
+ from .core import load, save
270
+
271
+ __all__ = []
272
+ __all__.extend(["load"])
273
+ __all__.append("save")
274
+ ```
275
+
276
+ ### case: a TypeAlias string uses a TYPE_CHECKING import
277
+
278
+ ```py
279
+ from typing import TYPE_CHECKING, TypeAlias
280
+
281
+ if TYPE_CHECKING:
282
+ from decimal import Decimal
283
+
284
+ Number: TypeAlias = "Decimal | int"
285
+ ```
286
+
287
+ ```expect
288
+ (none)
289
+ ```
@@ -0,0 +1,45 @@
1
+ ---
2
+ id: py/unused-import
3
+ title: "Every imported name is used"
4
+ languages: [python]
5
+ fix: suggest
6
+ fix_reason: "an import can run code when it loads, and removing it drops that side effect"
7
+ stability: preview
8
+ ported_from: [ruff/F401]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ Each name an `import` binds is read somewhere in the module, listed in `__all__`, or re-exported with `import x as x`.
13
+
14
+ **Why:** An unused import is dead weight: it slows start-up, can hide a missing dependency, and makes readers look for a use that isn't there.
15
+
16
+ ```codelaw
17
+ native: py/unused-import
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### Python
23
+
24
+ #### Don't
25
+
26
+ ```py
27
+ import os
28
+ import sys
29
+
30
+ print(sys.argv)
31
+ ```
32
+
33
+ #### Do
34
+
35
+ ```py
36
+ import sys
37
+
38
+ print(sys.argv)
39
+ ```
40
+
41
+ ## Differences from the source
42
+
43
+ - An import counts as used when any read of its name exists, wherever it is; Ruff tracks each binding separately, so `import os` read and then imported again unused is reported by Ruff only.
44
+ - Ruff's special handling of `__init__.py` (suggesting `__all__` or a redundant alias instead of removal) is not reproduced; the fix is `suggest` everywhere.
45
+ - Imports inside a `try` body (the "is this installed?" pattern) are reported without an edit.
@@ -0,0 +1,30 @@
1
+ # py/unused-loop-control-variable — cases
2
+
3
+ ### case: one of two targets
4
+
5
+ ```py
6
+ for key, value in pairs:
7
+ print(value)
8
+ ```
9
+
10
+ ```expect
11
+ 1:5 py/unused-loop-control-variable
12
+ ```
13
+
14
+ ```fixed
15
+ for _key, value in pairs:
16
+ print(value)
17
+ ```
18
+
19
+ ### case: used after the loop: no rename
20
+
21
+ ```py
22
+ def f(xs):
23
+ for x in xs:
24
+ pass
25
+ return x
26
+ ```
27
+
28
+ ```expect
29
+ 2:9 py/unused-loop-control-variable
30
+ ```
@@ -0,0 +1,36 @@
1
+ ---
2
+ id: py/unused-loop-control-variable
3
+ title: "Every loop variable is used in the loop"
4
+ languages: [python]
5
+ fix: suggest
6
+ fix_reason: "the rename is offered only when the name isn't used anywhere else; otherwise a person decides"
7
+ stability: preview
8
+ ported_from: [ruff/B007]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A `for` loop's target names are read in the loop body, or start with `_` to say they aren't needed.
13
+
14
+ **Why:** An unused loop variable often means the body uses the wrong name.
15
+
16
+ ```codelaw
17
+ native: py/unused-loop-control-variable
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### Python
23
+
24
+ #### Don't
25
+
26
+ ```py
27
+ for i in range(3):
28
+ retry()
29
+ ```
30
+
31
+ #### Do
32
+
33
+ ```py
34
+ for _i in range(3):
35
+ retry()
36
+ ```
@@ -0,0 +1,169 @@
1
+ # py/unused-variable — cases
2
+
3
+ ### case: read in a nested format spec
4
+
5
+ ```py
6
+ def f(x):
7
+ width = 3
8
+ return f"{x:{width}d}"
9
+ ```
10
+
11
+ ```expect
12
+ (none)
13
+ ```
14
+
15
+ ### case: underscore names are deliberate
16
+
17
+ ```py
18
+ def f():
19
+ _ = compute()
20
+ _unused = 1
21
+ ```
22
+
23
+ ```expect
24
+ (none)
25
+ ```
26
+
27
+ ### case: locals() reads everything
28
+
29
+ ```py
30
+ def f():
31
+ x = 1
32
+ return locals()
33
+ ```
34
+
35
+ ```expect
36
+ (none)
37
+ ```
38
+
39
+ ### case: nonlocal use
40
+
41
+ ```py
42
+ def f():
43
+ x = 1
44
+ def g():
45
+ nonlocal x
46
+ x = 2
47
+ return g
48
+ ```
49
+
50
+ ```expect
51
+ (none)
52
+ ```
53
+
54
+ ### case: module level is not checked
55
+
56
+ ```py
57
+ x = 1
58
+ ```
59
+
60
+ ```expect
61
+ (none)
62
+ ```
63
+
64
+ ### case: only the last assignment is reported
65
+
66
+ ```py
67
+ def f():
68
+ x = 1
69
+ x = 2
70
+ ```
71
+
72
+ ```expect
73
+ 3:5 py/unused-variable
74
+ ```
75
+
76
+ ```fixed
77
+ def f():
78
+ pass
79
+ ```
80
+
81
+ ### case: unused exception name
82
+
83
+ ```py
84
+ def f():
85
+ try:
86
+ pass
87
+ except ValueError as err:
88
+ pass
89
+ ```
90
+
91
+ ```expect
92
+ 4:26 py/unused-variable
93
+ ```
94
+
95
+ ```fixed
96
+ def f():
97
+ try:
98
+ pass
99
+ except ValueError:
100
+ pass
101
+ ```
102
+
103
+ ### case: loop variables are B007's business
104
+
105
+ ```py
106
+ def f():
107
+ for i in range(3):
108
+ pass
109
+ ```
110
+
111
+ ```expect
112
+ (none)
113
+ ```
114
+
115
+ ### case: augmented assignment reads
116
+
117
+ ```py
118
+ def f():
119
+ t = 1
120
+ t += 1
121
+ ```
122
+
123
+ ```expect
124
+ (none)
125
+ ```
126
+
127
+ ### case: unpacking a call result is not reported
128
+
129
+ ```py
130
+ def f(s):
131
+ name, j = s.split()
132
+ return j
133
+ ```
134
+
135
+ ```expect
136
+ (none)
137
+ ```
138
+
139
+ ### case: unpacking a tuple literal is
140
+
141
+ ```py
142
+ def f():
143
+ head, tail = 1, 2
144
+ return tail
145
+ ```
146
+
147
+ ```expect
148
+ 2:5 py/unused-variable
149
+ ```
150
+
151
+ ### case: module-level except name
152
+
153
+ ```py
154
+ try:
155
+ pass
156
+ except ValueError as err:
157
+ pass
158
+ ```
159
+
160
+ ```expect
161
+ 3:22 py/unused-variable
162
+ ```
163
+
164
+ ```fixed
165
+ try:
166
+ pass
167
+ except ValueError:
168
+ pass
169
+ ```
@@ -0,0 +1,38 @@
1
+ ---
2
+ id: py/unused-variable
3
+ title: "Every local variable is used"
4
+ languages: [python]
5
+ fix: suggest
6
+ fix_reason: "dropping the assignment of a plain value is safe, but the right edit for unpacking or `with` targets needs a person"
7
+ stability: preview
8
+ ported_from: [ruff/F841]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A variable assigned in a function (including `with … as` and `except … as` targets) is read somewhere in that function.
13
+
14
+ **Why:** An unused local is dead code, or a sign the value was meant to be used and isn't.
15
+
16
+ ```codelaw
17
+ native: py/unused-variable
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### Python
23
+
24
+ #### Don't
25
+
26
+ ```py
27
+ def handle(request):
28
+ result = compute(request)
29
+ return None
30
+ ```
31
+
32
+ #### Do
33
+
34
+ ```py
35
+ def handle(request):
36
+ compute(request)
37
+ return None
38
+ ```
@@ -0,0 +1,41 @@
1
+ ---
2
+ id: py/useless-comparison
3
+ title: "No comparison whose result is thrown away"
4
+ languages: [python]
5
+ fix: manual
6
+ fix_reason: "whether an assignment or an assertion was meant needs a person"
7
+ stability: preview
8
+ ported_from: [ruff/B015]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A comparison isn't written as a statement on its own.
13
+
14
+ **Why:** Its result is discarded; usually `=` or `assert` was meant.
15
+
16
+ ```codelaw
17
+ native: py/useless-comparison
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Use `=` if an assignment was meant, or `assert` if a check was.
23
+ 2. Otherwise remove the line.
24
+
25
+ ## Examples
26
+
27
+ ### Python
28
+
29
+ #### Don't
30
+
31
+ ```py
32
+ def reset(state):
33
+ state.count == 0
34
+ ```
35
+
36
+ #### Do
37
+
38
+ ```py
39
+ def reset(state):
40
+ state.count = 0
41
+ ```
@@ -0,0 +1,44 @@
1
+ ---
2
+ id: py/useless-contextlib-suppress
3
+ title: "`contextlib.suppress()` names an exception"
4
+ languages: [python]
5
+ fix: manual
6
+ fix_reason: "the exceptions to suppress are the author's choice"
7
+ stability: preview
8
+ ported_from: [ruff/B022]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ `contextlib.suppress()` is called with at least one exception class.
13
+
14
+ **Why:** With no arguments it suppresses nothing, so the `with` block is misleading.
15
+
16
+ ```codelaw
17
+ native: py/useless-contextlib-suppress
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Pass the exceptions to suppress, or remove the `with` statement.
23
+
24
+ ## Examples
25
+
26
+ ### Python
27
+
28
+ #### Don't
29
+
30
+ ```py
31
+ import contextlib
32
+
33
+ with contextlib.suppress():
34
+ remove("cache")
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```py
40
+ import contextlib
41
+
42
+ with contextlib.suppress(FileNotFoundError):
43
+ remove("cache")
44
+ ```