Skip to content

Commit f3cc094

Browse files
committed
Refactor violation codes and update related checks and tests accordingly.
1 parent 7a51a15 commit f3cc094

10 files changed

Lines changed: 141 additions & 140 deletions

File tree

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ This plugin implements the following code style checks:
99
- **COP001**: Use module import when importing more than two names
1010
- **COP002**: Import standard library modules as whole modules
1111
- **COP003**: Avoid explicit scalar type annotations
12-
- **COP004A**: Attribute name must be at least 8 characters
13-
- **COP004V**: Variable name must be at least 8 characters
14-
- **COP004G**: Argument name must be at least 8 characters
15-
- **COP004F**: Function name must be at least 8 characters
16-
- **COP004C**: Class name must be at least 8 characters
17-
- **COP005**: Function identifier must be a verb
18-
- **COP006**: Avoid `get_` prefix in async function names
19-
- **COP007**: Avoid temporary variables used only once
20-
- **COP008**: Classes should be marked `typing.final`
21-
- **COP009**: Wrap module dictionaries with `types.MappingProxyType`
22-
- **COP010**: Use dataclasses with `kw_only=True`, `slots=True`, `frozen=True`
12+
- **COP004**: Attribute name must be at least 8 characters
13+
- **COP005**: Variable name must be at least 8 characters
14+
- **COP006**: Argument name must be at least 8 characters
15+
- **COP007**: Function name must be at least 8 characters
16+
- **COP008**: Class name must be at least 8 characters
17+
- **COP009**: Function identifier must be a verb
18+
- **COP010**: Avoid `get_` prefix in async function names
19+
- **COP011**: Avoid temporary variables used only once
20+
- **COP012**: Classes should be marked `typing.final`
21+
- **COP013**: Wrap module dictionaries with `types.MappingProxyType`
22+
- **COP014**: Use dataclasses with `kw_only=True`, `slots=True`, `frozen=True`
2323

2424
## Installation
2525

src/community_of_python_flake8_plugin/checks/function_verb.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def check_is_verb_name(identifier: str) -> bool:
2323
def check_is_property(function_node: ast.AST) -> bool:
2424
if not isinstance(function_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
2525
return False
26-
return any(check_is_property_decorator(decorator) for decorator in function_node.decorator_list) # noqa: COP007
26+
return any(check_is_property_decorator(decorator) for decorator in function_node.decorator_list) # noqa: COP011
2727

2828

2929
def check_is_property_decorator(decorator: ast.expr) -> bool:
@@ -39,7 +39,7 @@ def check_is_property_decorator(decorator: ast.expr) -> bool:
3939
def check_is_pytest_fixture(function_node: ast.AST) -> bool:
4040
if not isinstance(function_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
4141
return False
42-
return any(check_is_fixture_decorator(decorator) for decorator in function_node.decorator_list) # noqa: COP007
42+
return any(check_is_fixture_decorator(decorator) for decorator in function_node.decorator_list) # noqa: COP011
4343

4444

4545
def check_is_fixture_decorator(decorator: ast.expr) -> bool:
@@ -61,12 +61,12 @@ def __init__(self, syntax_tree: ast.AST) -> None:
6161
self.syntax_tree: typing.Final[ast.AST] = syntax_tree
6262

6363
def visit_FunctionDef(self, ast_node: ast.FunctionDef) -> None:
64-
parent_class: typing.Final = retrieve_parent_class(self.syntax_tree, ast_node) # noqa: COP007
64+
parent_class: typing.Final = retrieve_parent_class(self.syntax_tree, ast_node) # noqa: COP011
6565
self.validate_function_name(ast_node, parent_class)
6666
self.generic_visit(ast_node)
6767

6868
def visit_AsyncFunctionDef(self, ast_node: ast.AsyncFunctionDef) -> None:
69-
parent_class: typing.Final = retrieve_parent_class(self.syntax_tree, ast_node) # noqa: COP007
69+
parent_class: typing.Final = retrieve_parent_class(self.syntax_tree, ast_node) # noqa: COP011
7070
self.validate_function_name(ast_node, parent_class)
7171
self.generic_visit(ast_node)
7272

src/community_of_python_flake8_plugin/checks/mapping_proxy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def _check_mapping_assignment(self, ast_node: ast.Assign | ast.AnnAssign) -> Non
4747
# Only check module-level assignments (no parent function/class)
4848
if assigned_value is not None and isinstance(assigned_value, ast.Dict) and assignment_targets:
4949
# Check if this is a module-level assignment
50-
for target in assignment_targets: # noqa: COP007
50+
for target in assignment_targets: # noqa: COP011
5151
if isinstance(target, ast.Name):
5252
self.violations.append(
5353
Violation(

src/community_of_python_flake8_plugin/checks/module_import_many_names.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def validate_import_size(self, ast_node: ast.ImportFrom) -> None:
5353
if module_name is not None and module_name.endswith(".settings"):
5454
return
5555

56-
module_import_exists: typing.Final = any( # noqa: COP007
56+
module_import_exists: typing.Final = any( # noqa: COP011
5757
isinstance(identifier, ast.alias)
5858
and module_name is not None
5959
and check_module_path_exists(f"{module_name}.{identifier.name}")

src/community_of_python_flake8_plugin/checks/name_length.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def check_is_whitelisted_annotation(annotation: ast.expr | None) -> bool:
3333
def check_is_pytest_fixture(ast_node: ast.AST) -> bool:
3434
if not isinstance(ast_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
3535
return False
36-
return any(check_is_fixture_decorator(decorator) for decorator in ast_node.decorator_list) # noqa: COP007
36+
return any(check_is_fixture_decorator(decorator) for decorator in ast_node.decorator_list) # noqa: COP011
3737

3838

3939
def check_is_fixture_decorator(decorator: ast.expr) -> bool:
@@ -55,31 +55,31 @@ def check_inherits_from_whitelisted_class(class_node: ast.ClassDef) -> bool:
5555

5656
@typing.final
5757
class COP004NameLengthCheck(ast.NodeVisitor):
58-
def __init__(self, tree: ast.AST) -> None: # noqa: COP004G
58+
def __init__(self, tree: ast.AST) -> None: # noqa: COP006
5959
self.violations: list[Violation] = []
6060
self.syntax_tree: typing.Final[ast.AST] = tree
6161

6262
def visit_AnnAssign(self, ast_node: ast.AnnAssign) -> None:
6363
if isinstance(ast_node.target, ast.Name):
64-
parent_class: typing.Final = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP007
64+
parent_class: typing.Final = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP011
6565
self.validate_name_length(ast_node.target.id, ast_node, parent_class)
6666
self.generic_visit(ast_node)
6767

6868
def visit_Assign(self, ast_node: ast.Assign) -> None:
6969
for target in ast_node.targets:
7070
if isinstance(target, ast.Name):
71-
parent_class = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP007
71+
parent_class = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP011
7272
self.validate_name_length(target.id, ast_node, parent_class)
7373
self.generic_visit(ast_node)
7474

7575
def visit_FunctionDef(self, ast_node: ast.FunctionDef) -> None:
76-
parent_class: typing.Final = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP007
76+
parent_class: typing.Final = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP011
7777
self.validate_function_name(ast_node, parent_class)
7878
self.validate_function_args(ast_node)
7979
self.generic_visit(ast_node)
8080

8181
def visit_AsyncFunctionDef(self, ast_node: ast.AsyncFunctionDef) -> None:
82-
parent_class: typing.Final = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP007
82+
parent_class: typing.Final = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP011
8383
self.validate_function_name(ast_node, parent_class)
8484
self.validate_function_args(ast_node)
8585
self.generic_visit(ast_node)

src/community_of_python_flake8_plugin/checks/scalar_annotation.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,22 @@ def check_is_scalar_annotation(annotation_node: ast.AST) -> bool:
3939
def find_parent_function(syntax_tree: ast.AST, target_node: ast.AST) -> ast.FunctionDef | ast.AsyncFunctionDef | None:
4040
for potential_parent in ast.walk(syntax_tree):
4141
if isinstance(potential_parent, (ast.FunctionDef, ast.AsyncFunctionDef)):
42-
for child_node in ast.walk(potential_parent): # noqa: COP007
42+
for child_node in ast.walk(potential_parent): # noqa: COP011
4343
if child_node is target_node:
4444
return potential_parent
4545
return None
4646

4747

4848
@typing.final
4949
class ScalarAnnotationCheck(ast.NodeVisitor):
50-
def __init__(self, tree: ast.AST) -> None: # noqa: COP004G
50+
def __init__(self, tree: ast.AST) -> None: # noqa: COP006
5151
self.violations: list[Violation] = []
5252
self.syntax_tree: typing.Final[ast.AST] = tree
5353

5454
def visit_AnnAssign(self, ast_node: ast.AnnAssign) -> None:
5555
if isinstance(ast_node.target, ast.Name):
56-
parent_class: typing.Final = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP007
57-
parent_function: typing.Final = find_parent_function(self.syntax_tree, ast_node) # noqa: COP007
56+
parent_class: typing.Final = find_parent_class_definition(self.syntax_tree, ast_node) # noqa: COP011
57+
parent_function: typing.Final = find_parent_function(self.syntax_tree, ast_node) # noqa: COP011
5858
in_class_body: typing.Final = parent_class is not None and parent_function is None
5959

6060
if not in_class_body:

src/community_of_python_flake8_plugin/plugin.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,23 @@
1616
class PluginCheckProtocol(typing.Protocol):
1717
violations: list[Violation]
1818

19-
def __init__(self, tree: ast.AST) -> None: ... # noqa: COP004G
20-
def visit(self, node: ast.AST) -> None: ... # noqa: COP004F,COP004G,COP008
19+
def __init__(self, tree: ast.AST) -> None: ... # noqa: COP006
20+
def visit(self, node: ast.AST) -> None: ... # noqa: COP007,COP006,COP012
2121

2222

2323
@typing.final
2424
class CommunityOfPythonFlake8Plugin:
25-
name: typing.Final[str] = "community-of-python-flake8-plugin"
26-
version: typing.Final[str] = "0.1.27"
25+
name: typing.Final[str] = "community-of-python-flake8-plugin" # noqa: COP004
26+
version: typing.Final[str] = "0.1.27" # noqa: COP004
2727

28-
def __init__(self, tree: ast.AST) -> None: # noqa: COP004G
28+
def __init__(self, tree: ast.AST) -> None: # noqa: COP006
2929
self.ast_syntax_tree: typing.Final[ast.AST] = tree
3030

31-
def run(self) -> Iterable[tuple[int, int, str, type[object]]]: # noqa: COP004F
31+
def run(self) -> Iterable[tuple[int, int, str, type[object]]]: # noqa: COP007
3232
checks_collection: typing.Final[list[PluginCheckProtocol]] = []
3333

3434
for _, module_name, _ in pkgutil.iter_modules(checks_module.__path__):
35-
module_full_name = f"{checks_module.__name__}.{module_name}" # noqa: COP007
36-
imported_module = importlib.import_module(module_full_name)
35+
imported_module = importlib.import_module(f"{checks_module.__name__}.{module_name}")
3736

3837
for attribute_name in dir(imported_module):
3938
attribute = getattr(imported_module, attribute_name)
@@ -44,5 +43,9 @@ def run(self) -> Iterable[tuple[int, int, str, type[object]]]: # noqa: COP004F
4443

4544
for check_instance in checks_collection:
4645
for violation in check_instance.violations:
47-
message_text = f"{violation.violation_code.code} {violation.violation_code.description}"
48-
yield violation.line_number, violation.column_number, message_text, type(self)
46+
yield (
47+
violation.line_number,
48+
violation.column_number,
49+
f"{violation.violation_code.code} {violation.violation_code.description}",
50+
type(self),
51+
)

src/community_of_python_flake8_plugin/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
def find_parent_class_definition(syntax_tree: ast.AST, target_node: ast.AST) -> ast.ClassDef | None:
66
for potential_parent in ast.walk(syntax_tree):
77
if isinstance(potential_parent, ast.ClassDef):
8-
for child_node in ast.walk(potential_parent): # noqa: COP007
8+
for child_node in ast.walk(potential_parent): # noqa: COP011
99
if child_node is target_node:
1010
return potential_parent
1111
return None

src/community_of_python_flake8_plugin/violation_codes.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
@typing.final
77
@dataclasses.dataclass(frozen=True, kw_only=True, slots=True)
88
class ViolationCodeItem:
9-
code: str # noqa: COP004C
9+
code: str # noqa: COP004
1010
description: str
1111

1212

@@ -24,28 +24,26 @@ class ViolationCodes:
2424
)
2525

2626
# Naming violations (more specific codes)
27-
ATTRIBUTE_NAME_LENGTH = ViolationCodeItem(
28-
code="COP004A", description="Attribute name must be at least 8 characters"
29-
)
30-
VARIABLE_NAME_LENGTH = ViolationCodeItem(code="COP004V", description="Variable name must be at least 8 characters")
31-
ARGUMENT_NAME_LENGTH = ViolationCodeItem(code="COP004G", description="Argument name must be at least 8 characters")
32-
FUNCTION_NAME_LENGTH = ViolationCodeItem(code="COP004F", description="Function name must be at least 8 characters")
33-
CLASS_NAME_LENGTH = ViolationCodeItem(code="COP004C", description="Class name must be at least 8 characters")
27+
ATTRIBUTE_NAME_LENGTH = ViolationCodeItem(code="COP004", description="Attribute name must be at least 8 characters")
28+
VARIABLE_NAME_LENGTH = ViolationCodeItem(code="COP005", description="Variable name must be at least 8 characters")
29+
ARGUMENT_NAME_LENGTH = ViolationCodeItem(code="COP006", description="Argument name must be at least 8 characters")
30+
FUNCTION_NAME_LENGTH = ViolationCodeItem(code="COP007", description="Function name must be at least 8 characters")
31+
CLASS_NAME_LENGTH = ViolationCodeItem(code="COP008", description="Class name must be at least 8 characters")
3432

3533
# Function related violations
36-
FUNCTION_VERB = ViolationCodeItem(code="COP005", description="Function name must start with a verb")
37-
ASYNC_GET_PREFIX = ViolationCodeItem(code="COP006", description="Avoid get_ prefix in async function names")
34+
FUNCTION_VERB = ViolationCodeItem(code="COP009", description="Function name must start with a verb")
35+
ASYNC_GET_PREFIX = ViolationCodeItem(code="COP010", description="Avoid get_ prefix in async function names")
3836

3937
# Variable usage violations
40-
TEMP_VAR = ViolationCodeItem(code="COP007", description="Inline variables that are used only once")
38+
TEMP_VAR = ViolationCodeItem(code="COP011", description="Inline variables that are used only once")
4139

4240
# Class related violations
43-
FINAL_CLASS = ViolationCodeItem(code="COP008", description="Classes must be marked final with @typing.final")
41+
FINAL_CLASS = ViolationCodeItem(code="COP012", description="Classes must be marked final with @typing.final")
4442

4543
# Module level violations
46-
MAPPING_PROXY = ViolationCodeItem(code="COP009", description="Wrap module dictionaries with types.MappingProxyType")
44+
MAPPING_PROXY = ViolationCodeItem(code="COP013", description="Wrap module dictionaries with types.MappingProxyType")
4745

4846
# Dataclass violations
4947
DATACLASS_CONFIG = ViolationCodeItem(
50-
code="COP010", description="Use dataclasses with kw_only=True, slots=True, frozen=True"
48+
code="COP014", description="Use dataclasses with kw_only=True, slots=True, frozen=True"
5149
)

0 commit comments

Comments
 (0)