Skip to content

Commit

Permalink
Support flake8 v5+ (#2)
Browse files Browse the repository at this point in the history
* Rename "CLST" to "CSM" in codes.
* Removed support for Python 3.7 and added 3.10 and 3.11.
* Fix Github actions.
  • Loading branch information
atollk committed Jul 14, 2023
1 parent 834dcc7 commit 00368aa
Show file tree
Hide file tree
Showing 18 changed files with 74 additions and 76 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python-black.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: [3.8]
python-version: [3.11]

steps:
- uses: actions/checkout@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: [3.7, 3.8]
python-version: ["3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v1
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ flake8 plugin that checks rules regarding the staticmethod and classmethod decor

## Options

The plugin offers one flag, `--select_clst1`, accepting a list of error
The plugin offers one flag, `--select_csm1`, accepting a list of error
codes (see below) to be enabled. By default, the enabled errors
are `CLST101` and `CLST131`.
are `CSM101` and `CSM131`.

## Error Codes

### CLST100
### CSM100

`@staticmethod` should not be used.

### CLST101
### CSM101

A method marked as `@staticmethod` should not reference the class it
is defined in. Use `@classmethod` otherwise.
Expand All @@ -38,7 +38,7 @@ class MyClass:
return cls.__name__
```

### CLST102
### CSM102

Do not inherit and override a method marked as `@staticmethod`.

Expand All @@ -63,11 +63,11 @@ class MyClass:
return cls.__name__
```

### CLST130
### CSM130

`@classmethod` should not be used.

### CLST131
### CSM131

A method marked as `@classmethod` should access the parameter `cls`.
Use `@staticmethod` otherwise.
Expand All @@ -88,7 +88,7 @@ class MyClass:
return "MyClass"
```

### CLST132
### CSM132
A method marked as `@classmethod` should not reference the class it
is defined in. Use the `cls` parameter.

Expand Down
34 changes: 15 additions & 19 deletions flake8_classmethod_staticmethod/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
import flake8.options.manager

DEFAULT_SELECT = [
"CLST101",
"CLST131",
"CSM101",
"CSM131",
]

PYTHON_38 = sys.version_info >= (3, 8)


class Checker:
"""
Expand All @@ -28,7 +26,7 @@ def __init__(self, tree: ast.AST):
@staticmethod
def add_options(option_manager: flake8.options.manager.OptionManager):
option_manager.add_option(
"--select_clst1",
"--select_csm1",
type=str,
comma_separated_list=True,
default=DEFAULT_SELECT,
Expand All @@ -43,9 +41,7 @@ def parse_options(
options: argparse.Namespace,
extra_args,
):
cls.enabled_errors = [
int(option[4:]) for option in options.select_clst1
]
cls.enabled_errors = [int(option[3:]) for option in options.select_csm1]

def run(self) -> Iterable[Tuple[int, int, str, type]]:
for cls_node in ast.walk(self.tree):
Expand All @@ -66,16 +62,16 @@ def _check_function_node(self, fn_node: ast.FunctionDef, classname: str):
)
if is_staticmethod:
if 100 in self.enabled_errors:
yield from _clst100(fn_node)
yield from _csm100(fn_node)
if 101 in self.enabled_errors:
yield from _clst101(fn_node, classname)
yield from _csm101(fn_node, classname)
if is_classmethod:
if 130 in self.enabled_errors:
yield from _clst130(fn_node)
yield from _csm130(fn_node)
if 131 in self.enabled_errors:
yield from _clst131(fn_node)
yield from _csm131(fn_node)
if 132 in self.enabled_errors:
yield from _clst132(fn_node, classname)
yield from _csm132(fn_node, classname)


ERROR_MESSAGES = {
Expand All @@ -98,16 +94,16 @@ def _error_tuple(error_code: int, node: ast.AST) -> Tuple[int, int, str, type]:
return (
node.lineno,
node.col_offset,
f"CLST{error_code} {ERROR_MESSAGES[error_code]}",
f"CSM{error_code} {ERROR_MESSAGES[error_code]}",
Checker,
)


def _clst100(node: ast.FunctionDef) -> Iterable[Tuple[int, int, str, type]]:
def _csm100(node: ast.FunctionDef) -> Iterable[Tuple[int, int, str, type]]:
yield _error_tuple(100, node)


def _clst101(
def _csm101(
node: ast.FunctionDef, classname: str
) -> Iterable[Tuple[int, int, str, type]]:
references_class = any(
Expand All @@ -118,18 +114,18 @@ def _clst101(
yield _error_tuple(101, node)


def _clst130(node: ast.FunctionDef) -> Iterable[Tuple[int, int, str, type]]:
def _csm130(node: ast.FunctionDef) -> Iterable[Tuple[int, int, str, type]]:
yield _error_tuple(130, node)


def _clst131(node: ast.FunctionDef) -> Iterable[Tuple[int, int, str, type]]:
def _csm131(node: ast.FunctionDef) -> Iterable[Tuple[int, int, str, type]]:
if node.args.args:
cls_param = node.args.args[0].arg
if not _function_uses_identifier(node, cls_param):
yield _error_tuple(131, node)


def _clst132(
def _csm132(
node: ast.FunctionDef, classname: str
) -> Iterable[Tuple[int, int, str, type]]:
if _function_uses_identifier(node, classname):
Expand Down
3 changes: 3 additions & 0 deletions requirements/py310.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
flake8>=5,<6
pytest-flake8-path>=1.5.0,<2
pytest>=7,<8
3 changes: 3 additions & 0 deletions requirements/py311.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
flake8>=5,<6
pytest-flake8-path>=1.5.0,<2
pytest>=7,<8
3 changes: 0 additions & 3 deletions requirements/py37.txt

This file was deleted.

6 changes: 3 additions & 3 deletions requirements/py38.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
flake8>=3.0,<4
pytest-flake8dir>=2.2,<3
pytest>=5.4,<6
flake8>=5,<6
pytest-flake8-path>=1.5.0,<2
pytest>=7,<8
6 changes: 3 additions & 3 deletions requirements/py39.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
flake8>=3.0,<4
pytest-flake8dir>=2.2,<3
pytest>=5.4,<6
flake8>=5,<6
pytest-flake8-path>=1.5.0,<2
pytest>=7,<8
9 changes: 5 additions & 4 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = flake8-classmethod-staticmethod
version = 1.0
version = 2.0
description = flake8 plugin that checks rules regarding the staticmethod and classmethod decorators.
long_description = file: README.md
long_description_content_type = text/markdown
Expand All @@ -16,18 +16,19 @@ classifiers =
Natural Language :: English
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11

[options]
packages =
flake8_classmethod_staticmethod
include_package_data = True
python_requires = >=3.7
python_requires = >=3.8
zip_safe = False

[options.entry_points]
flake8.extension =
CLST1 = flake8_classmethod_staticmethod.checker:Checker
CSM1 = flake8_classmethod_staticmethod.checker:Checker

7 changes: 3 additions & 4 deletions tests/test_clst100.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from flake8_classmethod_staticmethod.checker import PYTHON_38
from tests.util import BaseTest


class Test_CLST100(BaseTest):
class Test_CSM100(BaseTest):
def error_code(self) -> str:
return "CLST100"
return "CSM100"

def test_pass_1(self):
code = """
Expand All @@ -27,4 +26,4 @@ def bar():
pass
"""
result = self.run_flake8(code)
self.assert_error_at(result, "CLST100", 3 if PYTHON_38 else 2, 5)
self.assert_error_at(result, "CSM100", 4, 5)
7 changes: 3 additions & 4 deletions tests/test_clst101.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from flake8_classmethod_staticmethod.checker import PYTHON_38
from tests.util import BaseTest


class Test_CLST101(BaseTest):
class Test_CSM101(BaseTest):
def error_code(self) -> str:
return "CLST101"
return "CSM101"

def test_pass_1(self):
code = """
Expand Down Expand Up @@ -37,4 +36,4 @@ def bar():
return Foo.__name__
"""
result = self.run_flake8(code)
self.assert_error_at(result, "CLST101", 3 if PYTHON_38 else 2, 5)
self.assert_error_at(result, "CSM101", 4, 5)
7 changes: 3 additions & 4 deletions tests/test_clst130.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from flake8_classmethod_staticmethod.checker import PYTHON_38
from tests.util import BaseTest


class Test_CLST130(BaseTest):
class Test_CSM130(BaseTest):
def error_code(self) -> str:
return "CLST130"
return "CSM130"

def test_pass_1(self):
code = """
Expand All @@ -27,4 +26,4 @@ def bar(cls):
pass
"""
result = self.run_flake8(code)
self.assert_error_at(result, "CLST130", 3 if PYTHON_38 else 2, 5)
self.assert_error_at(result, "CSM130", 4, 5)
7 changes: 3 additions & 4 deletions tests/test_clst131.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from flake8_classmethod_staticmethod.checker import PYTHON_38
from tests.util import BaseTest


class Test_CLST131(BaseTest):
class Test_CSM131(BaseTest):
def error_code(self) -> str:
return "CLST131"
return "CSM131"

def test_pass_1(self):
code = """
Expand Down Expand Up @@ -40,4 +39,4 @@ def bar(cls):
return 123
"""
result = self.run_flake8(code)
self.assert_error_at(result, "CLST131", 3 if PYTHON_38 else 2, 5)
self.assert_error_at(result, "CSM131", 4, 5)
7 changes: 3 additions & 4 deletions tests/test_clst132.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from flake8_classmethod_staticmethod.checker import PYTHON_38
from tests.util import BaseTest


class Test_CLST132(BaseTest):
class Test_CSM132(BaseTest):
def error_code(self) -> str:
return "CLST132"
return "CSM132"

def test_pass_1(self):
code = """
Expand Down Expand Up @@ -41,4 +40,4 @@ def bar(cls):
return Foo.__name__
"""
result = self.run_flake8(code)
self.assert_error_at(result, "CLST132", 3 if PYTHON_38 else 2, 5)
self.assert_error_at(result, "CSM132", 4, 5)
7 changes: 3 additions & 4 deletions tests/test_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


class Test_General:
def test_pass_1(self, flake8dir):
def test_pass_1(self, flake8_path):
code = """
class Foo:
@some_decorator(123) # noqa
Expand All @@ -12,8 +12,7 @@ def bar(self):
@other.decorator(key=123) # noqa
def baz(self):
pass
"""
flake8dir.make_example_py(textwrap.dedent(code))
result = flake8dir.run_flake8()
(flake8_path / "example.py").write_text(textwrap.dedent(code))
result = flake8_path.run_flake8()
assert result.exit_code == 0
10 changes: 5 additions & 5 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ def error_code(self) -> str:
raise NotImplementedError

@pytest.fixture(autouse=True)
def _flake8dir(self, flake8dir):
self.flake8dir = flake8dir
def _flake8dir(self, flake8_path):
self.flake8_path = flake8_path

def run_flake8(self, code: str) -> List[ReportedMessage]:
self.flake8dir.make_example_py(textwrap.dedent(code))
args = [f"--select_clst1={self.error_code()}"]
result = self.flake8dir.run_flake8(args)
(self.flake8_path / "example.py").write_text(textwrap.dedent(code))
args = [f"--select_csm1={self.error_code()}"]
result = self.flake8_path.run_flake8(args)
return [ReportedMessage.from_raw(report) for report in result.out_lines]

def assert_error_at(
Expand Down

0 comments on commit 00368aa

Please sign in to comment.