flake8_simplify 0.30.0__tar.gz → 0.31.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/PKG-INFO +10 -10
  2. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/README.md +1 -2
  3. flake8_simplify-0.31.1/flake8_simplify/__init__.py +45 -0
  4. flake8_simplify-0.31.1/flake8_simplify/registry.py +71 -0
  5. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/rules/ast_assign.py +25 -30
  6. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/rules/ast_bool_op.py +46 -54
  7. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/rules/ast_call.py +40 -84
  8. flake8_simplify-0.31.1/flake8_simplify/rules/ast_classdef.py +19 -0
  9. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/rules/ast_compare.py +15 -24
  10. flake8_simplify-0.31.1/flake8_simplify/rules/ast_expr.py +64 -0
  11. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/rules/ast_for.py +80 -80
  12. flake8_simplify-0.31.1/flake8_simplify/rules/ast_if.py +505 -0
  13. flake8_simplify-0.31.1/flake8_simplify/rules/ast_ifexp.py +61 -0
  14. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/rules/ast_subscript.py +10 -14
  15. flake8_simplify-0.31.1/flake8_simplify/rules/ast_try.py +94 -0
  16. flake8_simplify-0.31.1/flake8_simplify/rules/ast_unary_op.py +82 -0
  17. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/rules/ast_with.py +7 -8
  18. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/utils.py +68 -74
  19. flake8_simplify-0.31.1/pyproject.toml +118 -0
  20. flake8_simplify-0.30.0/pyproject.toml → flake8_simplify-0.31.1/pyproject.toml.orig +31 -23
  21. flake8_simplify-0.30.0/.coveragerc +0 -22
  22. flake8_simplify-0.30.0/.flake8 +0 -6
  23. flake8_simplify-0.30.0/.github/ISSUE_TEMPLATE/adjust-rule.md +0 -25
  24. flake8_simplify-0.30.0/.github/ISSUE_TEMPLATE/rule-request.md +0 -22
  25. flake8_simplify-0.30.0/.github/dependabot.yml +0 -9
  26. flake8_simplify-0.30.0/.github/workflows/lint.yml +0 -36
  27. flake8_simplify-0.30.0/.github/workflows/unit-test.yml +0 -34
  28. flake8_simplify-0.30.0/.gitignore +0 -142
  29. flake8_simplify-0.30.0/.pre-commit-config.yaml +0 -43
  30. flake8_simplify-0.30.0/CHANGELOG.md +0 -109
  31. flake8_simplify-0.30.0/Makefile +0 -26
  32. flake8_simplify-0.30.0/flake8_simplify/__init__.py +0 -170
  33. flake8_simplify-0.30.0/flake8_simplify/constants.py +0 -5
  34. flake8_simplify-0.30.0/flake8_simplify/rules/ast_classdef.py +0 -22
  35. flake8_simplify-0.30.0/flake8_simplify/rules/ast_expr.py +0 -100
  36. flake8_simplify-0.30.0/flake8_simplify/rules/ast_if.py +0 -512
  37. flake8_simplify-0.30.0/flake8_simplify/rules/ast_ifexp.py +0 -65
  38. flake8_simplify-0.30.0/flake8_simplify/rules/ast_try.py +0 -93
  39. flake8_simplify-0.30.0/flake8_simplify/rules/ast_unary_op.py +0 -103
  40. flake8_simplify-0.30.0/mutmut-test.sh +0 -3
  41. flake8_simplify-0.30.0/requirements/dev.in +0 -8
  42. flake8_simplify-0.30.0/requirements/dev.txt +0 -91
  43. flake8_simplify-0.30.0/requirements/lint.in +0 -14
  44. flake8_simplify-0.30.0/requirements/lint.txt +0 -62
  45. flake8_simplify-0.30.0/tests/__init__.py +0 -10
  46. flake8_simplify-0.30.0/tests/test_100_rules.py +0 -517
  47. flake8_simplify-0.30.0/tests/test_200_rules.py +0 -70
  48. flake8_simplify-0.30.0/tests/test_300_rules.py +0 -18
  49. flake8_simplify-0.30.0/tests/test_400_rules.py +0 -130
  50. flake8_simplify-0.30.0/tests/test_900_rules.py +0 -243
  51. flake8_simplify-0.30.0/tests/test_simplify.py +0 -112
  52. flake8_simplify-0.30.0/tox.ini +0 -18
  53. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/LICENSE +0 -0
  54. {flake8_simplify-0.30.0 → flake8_simplify-0.31.1}/flake8_simplify/rules/__init__.py +0 -0
@@ -1,35 +1,36 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flake8_simplify
3
- Version: 0.30.0
3
+ Version: 0.31.1
4
4
  Summary: flake8 plugin which checks for code that can be simplified
5
5
  Keywords: flake8
6
+ Author: Martin Thoma
6
7
  Author-email: Martin Thoma <info@martin-thoma.de>
7
- Maintainer-email: Martin Thoma <info@martin-thoma.de>
8
- Requires-Python: >=3.9.0
9
- Description-Content-Type: text/markdown
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Environment :: Console
12
12
  Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: MIT License
14
13
  Classifier: Natural Language :: English
15
14
  Classifier: Operating System :: OS Independent
16
15
  Classifier: Programming Language :: Python :: 3
17
16
  Classifier: Programming Language :: Python :: 3 :: Only
18
- Classifier: Programming Language :: Python :: 3.9
19
17
  Classifier: Programming Language :: Python :: 3.10
20
18
  Classifier: Programming Language :: Python :: 3.11
21
19
  Classifier: Programming Language :: Python :: 3.12
22
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
23
22
  Classifier: Topic :: Software Development
24
23
  Classifier: Framework :: Flake8
25
- License-File: LICENSE
26
24
  Requires-Dist: flake8>=3.7
25
+ Maintainer: Martin Thoma
26
+ Maintainer-email: Martin Thoma <info@martin-thoma.de>
27
+ Requires-Python: >=3.10
27
28
  Project-URL: Homepage, https://github.com/MartinThoma/flake8-simplify
29
+ Description-Content-Type: text/markdown
28
30
 
29
31
  [![PyPI version](https://badge.fury.io/py/flake8-simplify.svg)](https://badge.fury.io/py/flake8-simplify)
30
32
  [![Code on Github](https://img.shields.io/badge/Code-GitHub-brightgreen)](https://github.com/MartinThoma/flake8-simplify)
31
33
  [![Actions Status](https://github.com/MartinThoma/flake8-simplify/workflows/Unit%20Tests/badge.svg)](https://github.com/MartinThoma/flake8-simplify/actions)
32
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
33
34
 
34
35
  # flake8-simplify
35
36
 
@@ -43,7 +44,7 @@ Install with `pip`:
43
44
  pip install flake8-simplify
44
45
  ```
45
46
 
46
- Python 3.9 to 3.13 are supported.
47
+ Python 3.10 to 3.14 are supported.
47
48
 
48
49
 
49
50
  ## Usage
@@ -653,4 +654,3 @@ dict.get(key, None)
653
654
  # Good
654
655
  dict.get(key)
655
656
  ```
656
-
@@ -1,7 +1,6 @@
1
1
  [![PyPI version](https://badge.fury.io/py/flake8-simplify.svg)](https://badge.fury.io/py/flake8-simplify)
2
2
  [![Code on Github](https://img.shields.io/badge/Code-GitHub-brightgreen)](https://github.com/MartinThoma/flake8-simplify)
3
3
  [![Actions Status](https://github.com/MartinThoma/flake8-simplify/workflows/Unit%20Tests/badge.svg)](https://github.com/MartinThoma/flake8-simplify/actions)
4
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
5
4
 
6
5
  # flake8-simplify
7
6
 
@@ -15,7 +14,7 @@ Install with `pip`:
15
14
  pip install flake8-simplify
16
15
  ```
17
16
 
18
- Python 3.9 to 3.13 are supported.
17
+ Python 3.10 to 3.14 are supported.
19
18
 
20
19
 
21
20
  ## Usage
@@ -0,0 +1,45 @@
1
+ import ast
2
+ import importlib.metadata as importlib_metadata
3
+ from collections.abc import Generator
4
+ from typing import Any
5
+
6
+ from flake8_simplify.registry import get_rules
7
+ from flake8_simplify.utils import add_meta
8
+
9
+
10
+ class Visitor(ast.NodeVisitor):
11
+ """Run every rule registered for a node type on each node of that type."""
12
+
13
+ def __init__(self) -> None:
14
+ self.errors: list[tuple[int, int, str]] = []
15
+ self._rules = get_rules()
16
+
17
+ def visit(self, node: ast.AST) -> Any:
18
+ for rule in self._rules.get(type(node), ()):
19
+ for violation in rule.check(node):
20
+ self.errors.append(
21
+ (
22
+ violation.node.lineno,
23
+ violation.node.col_offset,
24
+ f"{rule.code} {violation.message}",
25
+ )
26
+ )
27
+ self.generic_visit(node)
28
+
29
+
30
+ class Plugin:
31
+ name = __name__
32
+ version = importlib_metadata.version(__name__) # type: ignore
33
+
34
+ def __init__(self, tree: ast.AST):
35
+ self._tree = tree
36
+
37
+ def run(self) -> Generator[tuple[int, int, str, type[Any]], None, None]:
38
+ visitor = Visitor()
39
+
40
+ # Add parent
41
+ add_meta(self._tree)
42
+ visitor.visit(self._tree)
43
+
44
+ for line, col, msg in visitor.errors:
45
+ yield line, col, msg, type(self)
@@ -0,0 +1,71 @@
1
+ """
2
+ Registry of all rules.
3
+
4
+ A rule is a generator function which receives a node of the given type and
5
+ yields a ``Violation`` for every problem it finds. It registers itself with
6
+ the ``rule`` decorator; modules in ``flake8_simplify/rules/`` are discovered
7
+ automatically, so adding a rule never requires touching any other file.
8
+
9
+ @rule("SIM120", ast.ClassDef)
10
+ def get_sim120(node: ast.ClassDef) -> Iterator[Violation]:
11
+ if ...:
12
+ yield Violation(node, "Use 'class Foo:' ...")
13
+ """
14
+
15
+ import ast
16
+ import functools
17
+ import importlib
18
+ import pkgutil
19
+ from collections import defaultdict
20
+ from collections.abc import Callable, Iterator
21
+ from dataclasses import dataclass
22
+ from typing import Any, NamedTuple
23
+
24
+
25
+ class Violation(NamedTuple):
26
+ """A problem found by a rule, reported at the position of ``node``."""
27
+
28
+ node: ast.expr | ast.stmt
29
+ message: str
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class Rule:
34
+ code: str
35
+ node_type: type[ast.AST]
36
+ check: Callable[[Any], Iterator[Violation]]
37
+
38
+
39
+ _RULES: list[Rule] = []
40
+
41
+
42
+ def rule(
43
+ code: str,
44
+ node_type: type[ast.AST],
45
+ ) -> Callable[
46
+ [Callable[[Any], Iterator[Violation]]],
47
+ Callable[[Any], Iterator[Violation]],
48
+ ]:
49
+ """Register a function as the check for ``code`` on ``node_type`` nodes."""
50
+
51
+ def register(
52
+ check: Callable[[Any], Iterator[Violation]],
53
+ ) -> Callable[[Any], Iterator[Violation]]:
54
+ _RULES.append(Rule(code, node_type, check))
55
+ return check
56
+
57
+ return register
58
+
59
+
60
+ @functools.cache
61
+ def get_rules() -> dict[type[ast.AST], list[Rule]]:
62
+ """Get all rules, grouped by the type of node they check."""
63
+ from flake8_simplify import rules
64
+
65
+ for module in pkgutil.iter_modules(rules.__path__):
66
+ importlib.import_module(f"{rules.__name__}.{module.name}")
67
+
68
+ by_node_type: dict[type[ast.AST], list[Rule]] = defaultdict(list)
69
+ for registered in _RULES:
70
+ by_node_type[registered.node_type].append(registered)
71
+ return by_node_type
@@ -1,9 +1,18 @@
1
1
  import ast
2
+ from collections.abc import Iterator
2
3
 
3
- from flake8_simplify.utils import Assign, expression_uses_variable, to_source
4
+ from flake8_simplify.registry import Violation, rule
5
+ from flake8_simplify.utils import (
6
+ expression_uses_variable,
7
+ get_next_sibling,
8
+ get_parent,
9
+ in_same_block,
10
+ to_source,
11
+ )
4
12
 
5
13
 
6
- def get_sim904(node: ast.Assign) -> list[tuple[int, int, str]]:
14
+ @rule("SIM904", ast.Assign)
15
+ def get_sim904(node: ast.Assign) -> Iterator[Violation]:
7
16
  """
8
17
  Assign values to dictionary directly at initialization.
9
18
 
@@ -36,9 +45,8 @@ def get_sim904(node: ast.Assign) -> list[tuple[int, int, str]]:
36
45
  ),
37
46
  ]
38
47
  """
39
- RULE = "SIM904 Initialize dictionary '{dict_name}' directly"
40
- errors: list[tuple[int, int, str]] = []
41
- n2 = node.next_sibling # type: ignore
48
+ RULE = "Initialize dictionary '{dict_name}' directly"
49
+ n2 = get_next_sibling(node)
42
50
  if not (
43
51
  isinstance(node.value, ast.Dict)
44
52
  and isinstance(n2, ast.Assign)
@@ -48,25 +56,20 @@ def get_sim904(node: ast.Assign) -> list[tuple[int, int, str]]:
48
56
  and isinstance(n2.targets[0].value, ast.Name)
49
57
  and isinstance(node.targets[0], ast.Name)
50
58
  and n2.targets[0].value.id == node.targets[0].id
59
+ and in_same_block(node, n2)
51
60
  ):
52
- return errors
61
+ return
53
62
 
54
63
  dict_name = to_source(node.targets[0])
55
64
  # Capture cases where the assigned value uses another dictionary value
56
65
  if expression_uses_variable(n2.value, dict_name):
57
- return errors
66
+ return
58
67
 
59
- errors.append(
60
- (
61
- node.lineno,
62
- node.col_offset,
63
- RULE.format(dict_name=dict_name),
64
- )
65
- )
66
- return errors
68
+ yield Violation(node, RULE.format(dict_name=dict_name))
67
69
 
68
70
 
69
- def get_sim909(node: Assign) -> list[tuple[int, int, str]]:
71
+ @rule("SIM909", ast.Assign)
72
+ def get_sim909(node: ast.Assign) -> Iterator[Violation]:
70
73
  """
71
74
  Avoid reflexive assignments
72
75
 
@@ -86,8 +89,7 @@ def get_sim909(node: Assign) -> list[tuple[int, int, str]]:
86
89
  ),
87
90
  ]
88
91
  """
89
- RULE = "SIM909 Remove reflexive assignment '{code}'"
90
- errors: list[tuple[int, int, str]] = []
92
+ RULE = "Remove reflexive assignment '{code}'"
91
93
 
92
94
  names = []
93
95
  if isinstance(node.value, (ast.Name, ast.Subscript, ast.Tuple)):
@@ -96,18 +98,11 @@ def get_sim909(node: Assign) -> list[tuple[int, int, str]]:
96
98
  names.append(to_source(target))
97
99
 
98
100
  if len(names) == len(set(names)):
99
- return errors
101
+ return
100
102
 
101
- if isinstance(node.parent, ast.ClassDef):
102
- return errors
103
+ if isinstance(get_parent(node), ast.ClassDef):
104
+ return
103
105
 
104
- code = to_source(node.orig)
106
+ code = to_source(node)
105
107
 
106
- errors.append(
107
- (
108
- node.lineno,
109
- node.col_offset,
110
- RULE.format(code=code),
111
- )
112
- )
113
- return errors
108
+ yield Violation(node, RULE.format(code=code))
@@ -1,7 +1,8 @@
1
1
  import ast
2
2
  from collections import defaultdict
3
+ from collections.abc import Iterator
3
4
 
4
- from flake8_simplify.constants import BOOL_CONST_TYPES
5
+ from flake8_simplify.registry import Violation, rule
5
6
  from flake8_simplify.utils import (
6
7
  _get_duplicated_isinstance_call_by_node,
7
8
  is_same_expression,
@@ -9,24 +10,24 @@ from flake8_simplify.utils import (
9
10
  )
10
11
 
11
12
 
13
+ @rule("SIM101", ast.BoolOp)
12
14
  def get_sim101(
13
15
  node: ast.BoolOp,
14
- ) -> list[tuple[int, int, str]]:
16
+ ) -> Iterator[Violation]:
15
17
  """Get a positions where the duplicate isinstance problem appears."""
16
- errors: list[tuple[int, int, str]] = []
17
18
  if not isinstance(node.op, ast.Or):
18
- return errors
19
+ return
19
20
 
20
21
  RULE = (
21
- "SIM101 Multiple isinstance-calls which can be merged into a single "
22
+ "Multiple isinstance-calls which can be merged into a single "
22
23
  "call for variable '{var}'"
23
24
  )
24
25
  for var in _get_duplicated_isinstance_call_by_node(node):
25
- errors.append((node.lineno, node.col_offset, RULE.format(var=var)))
26
- return errors
26
+ yield Violation(node, RULE.format(var=var))
27
27
 
28
28
 
29
- def get_sim109(node: ast.BoolOp) -> list[tuple[int, int, str]]:
29
+ @rule("SIM109", ast.BoolOp)
30
+ def get_sim109(node: ast.BoolOp) -> Iterator[Violation]:
30
31
  """
31
32
  Check if multiple equalities with the same value are combined via "or".
32
33
 
@@ -46,9 +47,8 @@ def get_sim109(node: ast.BoolOp) -> list[tuple[int, int, str]]:
46
47
  ],
47
48
  )
48
49
  """
49
- errors: list[tuple[int, int, str]] = []
50
50
  if not isinstance(node.op, ast.Or):
51
- return errors
51
+ return
52
52
  equalities = [
53
53
  value
54
54
  for value in node.values
@@ -64,25 +64,22 @@ def get_sim109(node: ast.BoolOp) -> list[tuple[int, int, str]]:
64
64
  and isinstance(eq.comparators[0], ast.Name)
65
65
  ):
66
66
  id2vals[eq.left.id].append(eq.comparators[0])
67
- RULE = "SIM109 Use '{value} in {values}' instead of '{or_op}'"
67
+ RULE = "Use '{value} in {values}' instead of '{or_op}'"
68
68
  for value, values in id2vals.items():
69
69
  if len(values) == 1:
70
70
  continue
71
- errors.append(
72
- (
73
- node.lineno,
74
- node.col_offset,
75
- RULE.format(
76
- or_op=to_source(node),
77
- value=value,
78
- values=f"({to_source(ast.Tuple(elts=values))})", # type: ignore
79
- ),
80
- )
71
+ yield Violation(
72
+ node,
73
+ RULE.format(
74
+ or_op=to_source(node),
75
+ value=value,
76
+ values=f"({to_source(ast.Tuple(elts=values))})", # type: ignore
77
+ ),
81
78
  )
82
- return errors
83
79
 
84
80
 
85
- def get_sim220(node: ast.BoolOp) -> list[tuple[int, int, str]]:
81
+ @rule("SIM220", ast.BoolOp)
82
+ def get_sim220(node: ast.BoolOp) -> Iterator[Violation]:
86
83
  """
87
84
  Get a list of all calls of the type "a and not a".
88
85
 
@@ -97,9 +94,8 @@ def get_sim220(node: ast.BoolOp) -> list[tuple[int, int, str]]:
97
94
  ],
98
95
  )
99
96
  """
100
- errors: list[tuple[int, int, str]] = []
101
97
  if not (isinstance(node.op, ast.And) and len(node.values) >= 2):
102
- return errors
98
+ return
103
99
  # We have a boolean And. Let's make sure there is two times the same
104
100
  # expression, but once with a "not"
105
101
  negated_expressions = []
@@ -110,19 +106,19 @@ def get_sim220(node: ast.BoolOp) -> list[tuple[int, int, str]]:
110
106
  else:
111
107
  non_negated_expressions.append(exp)
112
108
  if len(negated_expressions) == 0:
113
- return errors
109
+ return
114
110
 
115
- RULE = "SIM220 Use 'False' instead of '{a} and not {a}'"
111
+ RULE = "Use 'False' instead of '{a} and not {a}'"
116
112
  for negated_expression in negated_expressions:
117
113
  for non_negated_expression in non_negated_expressions:
118
114
  if is_same_expression(negated_expression, non_negated_expression):
119
115
  a = to_source(negated_expression)
120
- errors.append((node.lineno, node.col_offset, RULE.format(a=a)))
121
- return errors
122
- return errors
116
+ yield Violation(node, RULE.format(a=a))
117
+ return
123
118
 
124
119
 
125
- def get_sim221(node: ast.BoolOp) -> list[tuple[int, int, str]]:
120
+ @rule("SIM221", ast.BoolOp)
121
+ def get_sim221(node: ast.BoolOp) -> Iterator[Violation]:
126
122
  """
127
123
  Get a list of all calls of the type "a or not a".
128
124
 
@@ -137,9 +133,8 @@ def get_sim221(node: ast.BoolOp) -> list[tuple[int, int, str]]:
137
133
  ],
138
134
  )
139
135
  """
140
- errors: list[tuple[int, int, str]] = []
141
136
  if not (isinstance(node.op, ast.Or) and len(node.values) >= 2):
142
- return errors
137
+ return
143
138
  # We have a boolean OR. Let's make sure there is two times the same
144
139
  # expression, but once with a "not"
145
140
  negated_expressions = []
@@ -150,19 +145,19 @@ def get_sim221(node: ast.BoolOp) -> list[tuple[int, int, str]]:
150
145
  else:
151
146
  non_negated_expressions.append(exp)
152
147
  if len(negated_expressions) == 0:
153
- return errors
148
+ return
154
149
 
155
- RULE = "SIM221 Use 'True' instead of '{a} or not {a}'"
150
+ RULE = "Use 'True' instead of '{a} or not {a}'"
156
151
  for negated_expression in negated_expressions:
157
152
  for non_negated_expression in non_negated_expressions:
158
153
  if is_same_expression(negated_expression, non_negated_expression):
159
154
  a = to_source(negated_expression)
160
- errors.append((node.lineno, node.col_offset, RULE.format(a=a)))
161
- return errors
162
- return errors
155
+ yield Violation(node, RULE.format(a=a))
156
+ return
163
157
 
164
158
 
165
- def get_sim222(node: ast.BoolOp) -> list[tuple[int, int, str]]:
159
+ @rule("SIM222", ast.BoolOp)
160
+ def get_sim222(node: ast.BoolOp) -> Iterator[Violation]:
166
161
  """
167
162
  Get a list of all calls of the type "... or True".
168
163
 
@@ -177,19 +172,18 @@ def get_sim222(node: ast.BoolOp) -> list[tuple[int, int, str]]:
177
172
  ],
178
173
  )
179
174
  """
180
- errors: list[tuple[int, int, str]] = []
181
175
  if not (isinstance(node.op, ast.Or)):
182
- return errors
176
+ return
183
177
 
184
- RULE = "SIM222 Use 'True' instead of '... or True'"
178
+ RULE = "Use 'True' instead of '... or True'"
185
179
  for exp in node.values:
186
- if isinstance(exp, BOOL_CONST_TYPES) and exp.value is True:
187
- errors.append((node.lineno, node.col_offset, RULE))
188
- return errors
189
- return errors
180
+ if isinstance(exp, ast.Constant) and exp.value is True:
181
+ yield Violation(node, RULE)
182
+ return
190
183
 
191
184
 
192
- def get_sim223(node: ast.BoolOp) -> list[tuple[int, int, str]]:
185
+ @rule("SIM223", ast.BoolOp)
186
+ def get_sim223(node: ast.BoolOp) -> Iterator[Violation]:
193
187
  """
194
188
  Get a list of all calls of the type "... and False".
195
189
 
@@ -204,13 +198,11 @@ def get_sim223(node: ast.BoolOp) -> list[tuple[int, int, str]]:
204
198
  ],
205
199
  )
206
200
  """
207
- errors: list[tuple[int, int, str]] = []
208
201
  if not (isinstance(node.op, ast.And)):
209
- return errors
202
+ return
210
203
 
211
- RULE = "SIM223 Use 'False' instead of '... and False'"
204
+ RULE = "Use 'False' instead of '... and False'"
212
205
  for exp in node.values:
213
- if isinstance(exp, BOOL_CONST_TYPES) and exp.value is False:
214
- errors.append((node.lineno, node.col_offset, RULE))
215
- return errors
216
- return errors
206
+ if isinstance(exp, ast.Constant) and exp.value is False:
207
+ yield Violation(node, RULE)
208
+ return