From 51a30872c449ce551a17c95277dda67e51e4b401 Mon Sep 17 00:00:00 2001 From: Kieran Ryan Date: Mon, 30 Dec 2024 00:17:26 +0000 Subject: [PATCH] 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 --- .pre-commit-config.yaml | 39 ++++++--------------- pyproject.toml | 30 +++++++++------- src/pytest_bdd/gherkin_terminal_reporter.py | 7 ++-- src/pytest_bdd/parser.py | 4 +-- src/pytest_bdd/scenario.py | 2 +- tests/feature/test_feature_base_dir.py | 16 ++++----- 6 files changed, 39 insertions(+), 59 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa159eb..96b4e35 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,33 +1,16 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: -- repo: https://github.com/psf/black - # If you update the version here, also update it in tox.ini (py*-pytestlatest-linters) - rev: 24.10.0 + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0 hooks: - - id: black -- repo: https://github.com/pycqa/isort - rev: 5.13.2 + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: f0b5944bef86f50d875305821a0ab0d8c601e465 # frozen: v0.8.4 hooks: - - id: isort - name: isort (python) -- repo: https://github.com/pre-commit/pre-commit-hooks - 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", - ] + - id: ruff + args: [ --fix ] + - id: ruff-format diff --git a/pyproject.toml b/pyproject.toml index f196671..c06e081 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,21 +57,25 @@ sphinx-autobuild = "*" requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" -[tool.black] +[tool.ruff] 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] -# E1: indentation: already covered by `black` -# E2: whitespace: already covered by `black` -# 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.ruff.lint.per-file-ignores] +# Lint `I002` (required imports) for `from __future__ import annotations` in `src/` +"!src/**.py" = ["I002"] [tool.coverage.report] exclude_lines = [ diff --git a/src/pytest_bdd/gherkin_terminal_reporter.py b/src/pytest_bdd/gherkin_terminal_reporter.py index 264aea2..e18719c 100644 --- a/src/pytest_bdd/gherkin_terminal_reporter.py +++ b/src/pytest_bdd/gherkin_terminal_reporter.py @@ -31,10 +31,9 @@ def configure(config: Config) -> None: raise Exception( "gherkin-terminal-reporter is not compatible with any other terminal reporter." "You can use only one terminal reporter." - "Currently '{0}' is used." - "Please decide to use one by deactivating {0} or gherkin-terminal-reporter.".format( - current_reporter.__class__ - ) + f"Currently '{current_reporter.__class__}' is used." + f"Please decide to use one by deactivating {current_reporter.__class__} " + "or gherkin-terminal-reporter." ) gherkin_reporter = GherkinTerminalReporter(config) config.pluginmanager.unregister(current_reporter) diff --git a/src/pytest_bdd/parser.py b/src/pytest_bdd/parser.py index a1b6eb2..3ae4671 100644 --- a/src/pytest_bdd/parser.py +++ b/src/pytest_bdd/parser.py @@ -10,14 +10,12 @@ from dataclasses import dataclass, field from .exceptions import StepError 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 GherkinDocument from .gherkin_parser import Rule as GherkinRule from .gherkin_parser import Scenario as GherkinScenario from .gherkin_parser import Step as GherkinStep from .gherkin_parser import Tag as GherkinTag -from .gherkin_parser import get_gherkin_document from .types import STEP_TYPE_BY_PARSER_KEYWORD PARAM_RE = re.compile(r"<(.+?)>") diff --git a/src/pytest_bdd/scenario.py b/src/pytest_bdd/scenario.py index e8e8427..687a1d7 100644 --- a/src/pytest_bdd/scenario.py +++ b/src/pytest_bdd/scenario.py @@ -384,7 +384,7 @@ def scenario( scenario = feature.scenarios[scenario_name] except KeyError: 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.' ) diff --git a/tests/feature/test_feature_base_dir.py b/tests/feature/test_feature_base_dir.py index 669571c..f6d8360 100644 --- a/tests/feature/test_feature_base_dir.py +++ b/tests/feature/test_feature_base_dir.py @@ -59,12 +59,10 @@ def test_feature_path_by_param_ok(pytester, base_dir): def prepare_testdir(pytester, ini_base_dir): pytester.makeini( - """ + f""" [pytest] - bdd_features_base_dir={} - """.format( - ini_base_dir - ) + bdd_features_base_dir={ini_base_dir} + """ ) feature_file = pytester.mkdir("features").joinpath("steps.feature") @@ -77,7 +75,7 @@ def prepare_testdir(pytester, ini_base_dir): ) pytester.makepyfile( - """ + f""" import os.path import pytest @@ -103,7 +101,7 @@ def prepare_testdir(pytester, ini_base_dir): scenarios(FEATURE) else: 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( @@ -145,7 +143,5 @@ def prepare_testdir(pytester, ini_base_dir): else: scenario(FEATURE, scenario_name, features_base_dir='features') - """.format( - ini_base_dir - ) + """ )