From 7ec7853cec243ad4ca5ed22f91cfbe7ba475b5f0 Mon Sep 17 00:00:00 2001 From: Dan Parizher <105245560+danparizher@users.noreply.github.com> Date: Mon, 23 Jun 2025 07:46:15 -0400 Subject: [PATCH] [`flake8-pytest-style`] PT001/PT023 fix makes syntax error on parenthesized decorator (#18782) Co-authored-by: Micha Reiser --- .../fixtures/flake8_pytest_style/PT001.py | 10 +++++ .../fixtures/flake8_pytest_style/PT023.py | 11 +++++ .../flake8_pytest_style/rules/fixture.rs | 9 ++--- .../rules/flake8_pytest_style/rules/marks.rs | 23 ++++------- ...e8_pytest_style__tests__PT001_default.snap | 39 ++++++++++++++++++ ...e8_pytest_style__tests__PT023_default.snap | 40 +++++++++++++++++++ 6 files changed, 110 insertions(+), 22 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT001.py b/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT001.py index 1160090d20..fd98ced71b 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT001.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT001.py @@ -83,3 +83,13 @@ def aliased_parentheses_no_params_multiline(): # scope="module" ) def my_fixture(): ... + + +@(pytest.fixture()) +def outer_paren_fixture_no_params(): + return 42 + + +@(fixture()) +def outer_paren_imported_fixture_no_params(): + return 42 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT023.py b/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT023.py index 682e78d80a..042dbcb393 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT023.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pytest_style/PT023.py @@ -88,3 +88,14 @@ class TestClass: # ), ) def test_bar(param1, param2): ... + + +@(pytest.mark.foo()) +def test_outer_paren_mark_function(): + pass + + +class TestClass: + @(pytest.mark.foo()) + def test_method_outer_paren(): + pass diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/fixture.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/fixture.rs index 70a6b8f56a..128b3b06e3 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/fixture.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/fixture.rs @@ -708,7 +708,7 @@ fn pytest_fixture_parentheses( fn check_fixture_decorator(checker: &Checker, func_name: &str, decorator: &Decorator) { match &decorator.expression { Expr::Call(ast::ExprCall { - func, + func: _, arguments, range: _, node_index: _, @@ -719,11 +719,8 @@ fn check_fixture_decorator(checker: &Checker, func_name: &str, decorator: &Decor && arguments.keywords.is_empty() { let fix = Fix::applicable_edit( - Edit::deletion(func.end(), decorator.end()), - if checker - .comment_ranges() - .intersects(TextRange::new(func.end(), decorator.end())) - { + Edit::range_deletion(arguments.range()), + if checker.comment_ranges().intersects(arguments.range()) { Applicability::Unsafe } else { Applicability::Safe diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/marks.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/marks.rs index 02351b39d7..96dcfc2aa7 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/marks.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/marks.rs @@ -2,7 +2,7 @@ use ruff_diagnostics::Applicability; use ruff_python_ast::{self as ast, Arguments, Decorator, Expr}; use ruff_macros::{ViolationMetadata, derive_message_formats}; -use ruff_text_size::{Ranged, TextRange}; +use ruff_text_size::Ranged; use crate::checkers::ast::Checker; use crate::registry::Rule; @@ -154,27 +154,18 @@ fn pytest_mark_parentheses( fn check_mark_parentheses(checker: &Checker, decorator: &Decorator, marker: &str) { match &decorator.expression { Expr::Call(ast::ExprCall { - func, - arguments: - Arguments { - args, - keywords, - range: _, - node_index: _, - }, + func: _, + arguments, range: _, node_index: _, }) => { if !checker.settings().flake8_pytest_style.mark_parentheses - && args.is_empty() - && keywords.is_empty() + && arguments.args.is_empty() + && arguments.keywords.is_empty() { let fix = Fix::applicable_edit( - Edit::deletion(func.end(), decorator.end()), - if checker - .comment_ranges() - .intersects(TextRange::new(func.end(), decorator.end())) - { + Edit::range_deletion(arguments.range()), + if checker.comment_ranges().intersects(arguments.range()) { Applicability::Unsafe } else { Applicability::Safe diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT001_default.snap b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT001_default.snap index 5ad98a5079..659e307c74 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT001_default.snap +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT001_default.snap @@ -149,3 +149,42 @@ PT001.py:81:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()` 84 |-) 81 |+@pytest.fixture 85 82 | def my_fixture(): ... +86 83 | +87 84 | + +PT001.py:88:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()` + | +88 | @(pytest.fixture()) + | ^^^^^^^^^^^^^^^^^^^ PT001 +89 | def outer_paren_fixture_no_params(): +90 | return 42 + | + = help: Remove parentheses + +ℹ Safe fix +85 85 | def my_fixture(): ... +86 86 | +87 87 | +88 |-@(pytest.fixture()) + 88 |+@(pytest.fixture) +89 89 | def outer_paren_fixture_no_params(): +90 90 | return 42 +91 91 | + +PT001.py:93:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()` + | +93 | @(fixture()) + | ^^^^^^^^^^^^ PT001 +94 | def outer_paren_imported_fixture_no_params(): +95 | return 42 + | + = help: Remove parentheses + +ℹ Safe fix +90 90 | return 42 +91 91 | +92 92 | +93 |-@(fixture()) + 93 |+@(fixture) +94 94 | def outer_paren_imported_fixture_no_params(): +95 95 | return 42 diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT023_default.snap b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT023_default.snap index df12e9c4bc..b28b6da126 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT023_default.snap +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/snapshots/ruff_linter__rules__flake8_pytest_style__tests__PT023_default.snap @@ -130,3 +130,43 @@ PT023.py:82:1: PT023 [*] Use `@pytest.mark.parametrize` over `@pytest.mark.param 89 |-) 82 |+@pytest.mark.parametrize 90 83 | def test_bar(param1, param2): ... +91 84 | +92 85 | + +PT023.py:93:1: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()` + | +93 | @(pytest.mark.foo()) + | ^^^^^^^^^^^^^^^^^^^^ PT023 +94 | def test_outer_paren_mark_function(): +95 | pass + | + = help: Remove parentheses + +ℹ Safe fix +90 90 | def test_bar(param1, param2): ... +91 91 | +92 92 | +93 |-@(pytest.mark.foo()) + 93 |+@(pytest.mark.foo) +94 94 | def test_outer_paren_mark_function(): +95 95 | pass +96 96 | + +PT023.py:99:5: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()` + | + 98 | class TestClass: + 99 | @(pytest.mark.foo()) + | ^^^^^^^^^^^^^^^^^^^^ PT023 +100 | def test_method_outer_paren(): +101 | pass + | + = help: Remove parentheses + +ℹ Safe fix +96 96 | +97 97 | +98 98 | class TestClass: +99 |- @(pytest.mark.foo()) + 99 |+ @(pytest.mark.foo) +100 100 | def test_method_outer_paren(): +101 101 | pass