mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +00:00
Enforce pytest
import for decorators (#18779)
This commit is contained in:
parent
65b288b45b
commit
4c8d612120
6 changed files with 147 additions and 141 deletions
|
@ -1,3 +1,8 @@
|
|||
@pytest.mark.foo(scope="module")
|
||||
def ok_due_to_missing_import():
|
||||
pass
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
|
|
|
@ -896,7 +896,7 @@ fn check_fixture_addfinalizer(checker: &Checker, parameters: &Parameters, body:
|
|||
|
||||
/// PT024, PT025
|
||||
fn check_fixture_marks(checker: &Checker, decorators: &[Decorator]) {
|
||||
for (expr, marker) in get_mark_decorators(decorators) {
|
||||
for (expr, marker) in get_mark_decorators(decorators, checker.semantic()) {
|
||||
if checker.enabled(Rule::PytestUnnecessaryAsyncioMarkOnFixture) {
|
||||
if marker == "asyncio" {
|
||||
let mut diagnostic =
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
use crate::checkers::ast::Checker;
|
||||
use std::fmt;
|
||||
|
||||
use ruff_python_ast::helpers::map_callable;
|
||||
use ruff_python_ast::name::UnqualifiedName;
|
||||
use ruff_python_ast::{self as ast, Decorator, Expr, ExprCall, Keyword, Stmt, StmtFunctionDef};
|
||||
use ruff_python_semantic::analyze::visibility;
|
||||
use ruff_python_semantic::{ScopeKind, SemanticModel};
|
||||
use ruff_python_trivia::PythonWhitespace;
|
||||
use std::fmt;
|
||||
|
||||
pub(super) fn get_mark_decorators(
|
||||
decorators: &[Decorator],
|
||||
) -> impl Iterator<Item = (&Decorator, &str)> {
|
||||
decorators.iter().filter_map(|decorator| {
|
||||
let name = UnqualifiedName::from_expr(map_callable(&decorator.expression))?;
|
||||
let ["pytest", "mark", marker] = name.segments() else {
|
||||
return None;
|
||||
};
|
||||
Some((decorator, *marker))
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
pub(super) fn get_mark_decorators<'a>(
|
||||
decorators: &'a [Decorator],
|
||||
semantic: &'a SemanticModel,
|
||||
) -> impl Iterator<Item = (&'a Decorator, &'a str)> + 'a {
|
||||
decorators.iter().filter_map(move |decorator| {
|
||||
let expr = map_callable(&decorator.expression);
|
||||
let qualified_name = semantic.resolve_qualified_name(expr)?;
|
||||
match qualified_name.segments() {
|
||||
["pytest", "mark", marker] => Some((decorator, *marker)),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@ pub(crate) fn marks(checker: &Checker, decorators: &[Decorator]) {
|
|||
let enforce_parentheses = checker.enabled(Rule::PytestIncorrectMarkParenthesesStyle);
|
||||
let enforce_useless_usefixtures = checker.enabled(Rule::PytestUseFixturesWithoutParameters);
|
||||
|
||||
for (decorator, marker) in get_mark_decorators(decorators) {
|
||||
for (decorator, marker) in get_mark_decorators(decorators, checker.semantic()) {
|
||||
if enforce_parentheses {
|
||||
check_mark_parentheses(checker, decorator, marker);
|
||||
}
|
||||
|
|
|
@ -1,101 +1,100 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PT023.py:46:1: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
46 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
47 | def test_something():
|
||||
48 | pass
|
||||
|
|
||||
= help: Remove parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
43 43 | # With parentheses
|
||||
44 44 |
|
||||
45 45 |
|
||||
46 |-@pytest.mark.foo()
|
||||
46 |+@pytest.mark.foo
|
||||
47 47 | def test_something():
|
||||
48 48 | pass
|
||||
49 49 |
|
||||
|
||||
PT023.py:51:1: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
51 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
52 | class TestClass:
|
||||
53 | def test_something():
|
||||
52 | def test_something():
|
||||
53 | pass
|
||||
|
|
||||
= help: Remove parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
48 48 | pass
|
||||
48 48 | # With parentheses
|
||||
49 49 |
|
||||
50 50 |
|
||||
51 |-@pytest.mark.foo()
|
||||
51 |+@pytest.mark.foo
|
||||
52 52 | class TestClass:
|
||||
53 53 | def test_something():
|
||||
54 54 | pass
|
||||
52 52 | def test_something():
|
||||
53 53 | pass
|
||||
54 54 |
|
||||
|
||||
PT023.py:58:5: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
PT023.py:56:1: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
56 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
57 | class TestClass:
|
||||
58 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
59 | def test_something():
|
||||
60 | pass
|
||||
58 | def test_something():
|
||||
|
|
||||
= help: Remove parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
53 53 | pass
|
||||
54 54 |
|
||||
55 55 |
|
||||
56 56 |
|
||||
56 |-@pytest.mark.foo()
|
||||
56 |+@pytest.mark.foo
|
||||
57 57 | class TestClass:
|
||||
58 |- @pytest.mark.foo()
|
||||
58 |+ @pytest.mark.foo
|
||||
59 59 | def test_something():
|
||||
60 60 | pass
|
||||
61 61 |
|
||||
58 58 | def test_something():
|
||||
59 59 | pass
|
||||
|
||||
PT023.py:64:5: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
PT023.py:63:5: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
63 | class TestClass:
|
||||
64 | @pytest.mark.foo()
|
||||
62 | class TestClass:
|
||||
63 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
65 | class TestNestedClass:
|
||||
66 | def test_something():
|
||||
64 | def test_something():
|
||||
65 | pass
|
||||
|
|
||||
= help: Remove parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
60 60 |
|
||||
61 61 |
|
||||
62 62 |
|
||||
63 63 | class TestClass:
|
||||
64 |- @pytest.mark.foo()
|
||||
64 |+ @pytest.mark.foo
|
||||
65 65 | class TestNestedClass:
|
||||
66 66 | def test_something():
|
||||
67 67 | pass
|
||||
62 62 | class TestClass:
|
||||
63 |- @pytest.mark.foo()
|
||||
63 |+ @pytest.mark.foo
|
||||
64 64 | def test_something():
|
||||
65 65 | pass
|
||||
66 66 |
|
||||
|
||||
PT023.py:72:9: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
PT023.py:69:5: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
70 | class TestClass:
|
||||
71 | class TestNestedClass:
|
||||
72 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
73 | def test_something():
|
||||
74 | pass
|
||||
68 | class TestClass:
|
||||
69 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
70 | class TestNestedClass:
|
||||
71 | def test_something():
|
||||
|
|
||||
= help: Remove parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
69 69 |
|
||||
70 70 | class TestClass:
|
||||
71 71 | class TestNestedClass:
|
||||
72 |- @pytest.mark.foo()
|
||||
72 |+ @pytest.mark.foo
|
||||
73 73 | def test_something():
|
||||
74 74 | pass
|
||||
66 66 |
|
||||
67 67 |
|
||||
68 68 | class TestClass:
|
||||
69 |- @pytest.mark.foo()
|
||||
69 |+ @pytest.mark.foo
|
||||
70 70 | class TestNestedClass:
|
||||
71 71 | def test_something():
|
||||
72 72 | pass
|
||||
|
||||
PT023.py:77:9: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
75 | class TestClass:
|
||||
76 | class TestNestedClass:
|
||||
77 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
78 | def test_something():
|
||||
79 | pass
|
||||
|
|
||||
= help: Remove parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
74 74 |
|
||||
75 75 | class TestClass:
|
||||
76 76 | class TestNestedClass:
|
||||
77 |- @pytest.mark.foo()
|
||||
77 |+ @pytest.mark.foo
|
||||
78 78 | def test_something():
|
||||
79 79 | pass
|
||||
|
|
|
@ -1,102 +1,101 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
PT023.py:12:1: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
12 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
13 | def test_something():
|
||||
14 | pass
|
||||
|
|
||||
= help: Add parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
9 9 | # Without parentheses
|
||||
10 10 |
|
||||
11 11 |
|
||||
12 |-@pytest.mark.foo
|
||||
12 |+@pytest.mark.foo()
|
||||
13 13 | def test_something():
|
||||
14 14 | pass
|
||||
15 15 |
|
||||
|
||||
PT023.py:17:1: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
17 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
18 | class TestClass:
|
||||
19 | def test_something():
|
||||
18 | def test_something():
|
||||
19 | pass
|
||||
|
|
||||
= help: Add parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
14 14 | pass
|
||||
14 14 | # Without parentheses
|
||||
15 15 |
|
||||
16 16 |
|
||||
17 |-@pytest.mark.foo
|
||||
17 |+@pytest.mark.foo()
|
||||
18 18 | class TestClass:
|
||||
19 19 | def test_something():
|
||||
20 20 | pass
|
||||
18 18 | def test_something():
|
||||
19 19 | pass
|
||||
20 20 |
|
||||
|
||||
PT023.py:24:5: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
PT023.py:22:1: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
22 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
23 | class TestClass:
|
||||
24 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
25 | def test_something():
|
||||
26 | pass
|
||||
24 | def test_something():
|
||||
|
|
||||
= help: Add parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
19 19 | pass
|
||||
20 20 |
|
||||
21 21 |
|
||||
22 22 |
|
||||
22 |-@pytest.mark.foo
|
||||
22 |+@pytest.mark.foo()
|
||||
23 23 | class TestClass:
|
||||
24 |- @pytest.mark.foo
|
||||
24 |+ @pytest.mark.foo()
|
||||
25 25 | def test_something():
|
||||
26 26 | pass
|
||||
27 27 |
|
||||
24 24 | def test_something():
|
||||
25 25 | pass
|
||||
|
||||
PT023.py:30:5: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
PT023.py:29:5: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
29 | class TestClass:
|
||||
30 | @pytest.mark.foo
|
||||
28 | class TestClass:
|
||||
29 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
31 | class TestNestedClass:
|
||||
32 | def test_something():
|
||||
30 | def test_something():
|
||||
31 | pass
|
||||
|
|
||||
= help: Add parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
26 26 |
|
||||
27 27 |
|
||||
28 28 |
|
||||
29 29 | class TestClass:
|
||||
30 |- @pytest.mark.foo
|
||||
30 |+ @pytest.mark.foo()
|
||||
31 31 | class TestNestedClass:
|
||||
32 32 | def test_something():
|
||||
33 33 | pass
|
||||
28 28 | class TestClass:
|
||||
29 |- @pytest.mark.foo
|
||||
29 |+ @pytest.mark.foo()
|
||||
30 30 | def test_something():
|
||||
31 31 | pass
|
||||
32 32 |
|
||||
|
||||
PT023.py:38:9: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
PT023.py:35:5: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
36 | class TestClass:
|
||||
37 | class TestNestedClass:
|
||||
38 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
39 | def test_something():
|
||||
40 | pass
|
||||
34 | class TestClass:
|
||||
35 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
36 | class TestNestedClass:
|
||||
37 | def test_something():
|
||||
|
|
||||
= help: Add parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
35 35 |
|
||||
36 36 | class TestClass:
|
||||
37 37 | class TestNestedClass:
|
||||
38 |- @pytest.mark.foo
|
||||
38 |+ @pytest.mark.foo()
|
||||
39 39 | def test_something():
|
||||
40 40 | pass
|
||||
41 41 |
|
||||
32 32 |
|
||||
33 33 |
|
||||
34 34 | class TestClass:
|
||||
35 |- @pytest.mark.foo
|
||||
35 |+ @pytest.mark.foo()
|
||||
36 36 | class TestNestedClass:
|
||||
37 37 | def test_something():
|
||||
38 38 | pass
|
||||
|
||||
PT023.py:43:9: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
41 | class TestClass:
|
||||
42 | class TestNestedClass:
|
||||
43 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
44 | def test_something():
|
||||
45 | pass
|
||||
|
|
||||
= help: Add parentheses
|
||||
|
||||
ℹ Safe fix
|
||||
40 40 |
|
||||
41 41 | class TestClass:
|
||||
42 42 | class TestNestedClass:
|
||||
43 |- @pytest.mark.foo
|
||||
43 |+ @pytest.mark.foo()
|
||||
44 44 | def test_something():
|
||||
45 45 | pass
|
||||
46 46 |
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue