Migrate linting to ruff

- Configure `ruff` as a drop in replacement for `flake8`, `isort` and `pyupgrade`
- Lint for required `from __future__ import annotations` in `src/`
- Enable automatic fixing of linting errors in pre-commit
- Applied ruff `--fix` for `I001` on `src/pytest_bdd/parser.py`
- Applied ruff `--fix` for `UP032` on `src/pytest_bdd/gherkin_terminal_reporter.py`
- Applied ruff `--fix` for `tests/feature/test_feature_base_dir.py`
- Applied ruff `--fix` for `tests/feature/test_feature_base_dir.py`
- Ignore `B904` error on `src/pytest_bdd/scenario.py`
- Fix invalid pre-commit config error due to indentation syntax error
- Freeze pre-commit dependency versions
This commit is contained in:
Kieran Ryan 2024-12-30 00:17:26 +00:00
parent 7decb11aac
commit 51a30872c4
6 changed files with 39 additions and 59 deletions

View File

@ -1,33 +1,16 @@
# See https://pre-commit.com for more information # See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks # See https://pre-commit.com/hooks.html for more hooks
repos: repos:
- repo: https://github.com/psf/black - repo: https://github.com/pre-commit/pre-commit-hooks
# If you update the version here, also update it in tox.ini (py*-pytestlatest-linters) rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0
rev: 24.10.0
hooks: hooks:
- id: black - id: trailing-whitespace
- repo: https://github.com/pycqa/isort - id: end-of-file-fixer
rev: 5.13.2 - id: check-yaml
- id: check-added-large-files
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: f0b5944bef86f50d875305821a0ab0d8c601e465 # frozen: v0.8.4
hooks: hooks:
- id: isort - id: ruff
name: isort (python) args: [ --fix ]
- repo: https://github.com/pre-commit/pre-commit-hooks - id: ruff-format
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.0
hooks:
- id: pyupgrade
args: ["--py39-plus"]
- repo: https://github.com/pycqa/flake8
rev: "7.1.1"
hooks:
- id: flake8
additional_dependencies: [
"flake8-pyproject",
"flake8-bugbear",
]

View File

@ -57,21 +57,25 @@ sphinx-autobuild = "*"
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.black] [tool.ruff]
line-length = 120 line-length = 120
target-version = ["py39", "py310", "py311", "py312", "py313"] target-version = "py39"
lint.select = [
"B", # flake8-bugbear
"E4", # pycodestyle - error - import
"E7", # pycodestyle - error - statement
"E9", # pycodestyle - error - runtime
"F", # pyflakes
"I", # isort
"UP", # pyupgrade
]
lint.isort.required-imports = [
"from __future__ import annotations",
]
[tool.flake8] [tool.ruff.lint.per-file-ignores]
# E1: indentation: already covered by `black` # Lint `I002` (required imports) for `from __future__ import annotations` in `src/`
# E2: whitespace: already covered by `black` "!src/**.py" = ["I002"]
# E3: blank line: already covered by `black`
# E501: line length: already covered by `black`
extend-ignore = "E1,E2,E3,E501"
[tool.isort]
profile = "black"
line_length = 120
multi_line_output = 3
[tool.coverage.report] [tool.coverage.report]
exclude_lines = [ exclude_lines = [

View File

@ -31,10 +31,9 @@ def configure(config: Config) -> None:
raise Exception( raise Exception(
"gherkin-terminal-reporter is not compatible with any other terminal reporter." "gherkin-terminal-reporter is not compatible with any other terminal reporter."
"You can use only one terminal reporter." "You can use only one terminal reporter."
"Currently '{0}' is used." f"Currently '{current_reporter.__class__}' is used."
"Please decide to use one by deactivating {0} or gherkin-terminal-reporter.".format( f"Please decide to use one by deactivating {current_reporter.__class__} "
current_reporter.__class__ "or gherkin-terminal-reporter."
)
) )
gherkin_reporter = GherkinTerminalReporter(config) gherkin_reporter = GherkinTerminalReporter(config)
config.pluginmanager.unregister(current_reporter) config.pluginmanager.unregister(current_reporter)

View File

@ -10,14 +10,12 @@ from dataclasses import dataclass, field
from .exceptions import StepError from .exceptions import StepError
from .gherkin_parser import Background as GherkinBackground from .gherkin_parser import Background as GherkinBackground
from .gherkin_parser import DataTable from .gherkin_parser import DataTable, GherkinDocument, get_gherkin_document
from .gherkin_parser import Feature as GherkinFeature from .gherkin_parser import Feature as GherkinFeature
from .gherkin_parser import GherkinDocument
from .gherkin_parser import Rule as GherkinRule from .gherkin_parser import Rule as GherkinRule
from .gherkin_parser import Scenario as GherkinScenario from .gherkin_parser import Scenario as GherkinScenario
from .gherkin_parser import Step as GherkinStep from .gherkin_parser import Step as GherkinStep
from .gherkin_parser import Tag as GherkinTag from .gherkin_parser import Tag as GherkinTag
from .gherkin_parser import get_gherkin_document
from .types import STEP_TYPE_BY_PARSER_KEYWORD from .types import STEP_TYPE_BY_PARSER_KEYWORD
PARAM_RE = re.compile(r"<(.+?)>") PARAM_RE = re.compile(r"<(.+?)>")

View File

@ -384,7 +384,7 @@ def scenario(
scenario = feature.scenarios[scenario_name] scenario = feature.scenarios[scenario_name]
except KeyError: except KeyError:
feature_name = feature.name or "[Empty]" feature_name = feature.name or "[Empty]"
raise exceptions.ScenarioNotFound( raise exceptions.ScenarioNotFound( # noqa: B904
f'Scenario "{scenario_name}" in feature "{feature_name}" in {feature.filename} is not found.' f'Scenario "{scenario_name}" in feature "{feature_name}" in {feature.filename} is not found.'
) )

View File

@ -59,12 +59,10 @@ def test_feature_path_by_param_ok(pytester, base_dir):
def prepare_testdir(pytester, ini_base_dir): def prepare_testdir(pytester, ini_base_dir):
pytester.makeini( pytester.makeini(
""" f"""
[pytest] [pytest]
bdd_features_base_dir={} bdd_features_base_dir={ini_base_dir}
""".format( """
ini_base_dir
)
) )
feature_file = pytester.mkdir("features").joinpath("steps.feature") feature_file = pytester.mkdir("features").joinpath("steps.feature")
@ -77,7 +75,7 @@ def prepare_testdir(pytester, ini_base_dir):
) )
pytester.makepyfile( pytester.makepyfile(
""" f"""
import os.path import os.path
import pytest import pytest
@ -103,7 +101,7 @@ def prepare_testdir(pytester, ini_base_dir):
scenarios(FEATURE) scenarios(FEATURE)
else: else:
scenario(FEATURE, scenario_name) scenario(FEATURE, scenario_name)
assert os.path.abspath(os.path.join('{}', FEATURE)) in str(exc.value) assert os.path.abspath(os.path.join('{ini_base_dir}', FEATURE)) in str(exc.value)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -145,7 +143,5 @@ def prepare_testdir(pytester, ini_base_dir):
else: else:
scenario(FEATURE, scenario_name, features_base_dir='features') scenario(FEATURE, scenario_name, features_base_dir='features')
""".format( """
ini_base_dir
)
) )