Skip to content

Commit d2f661f

Browse files
RUF009 should behave similar to B008 and ignore attributes with immutable types (#16048)
This PR resolved #15772 Before PR: ``` def _( this_is_fine: int = f(), # No error this_is_not: list[int] = f() # B008: Do not perform function call `f` in argument defaults ): ... @DataClass class _: this_is_not_fine: list[int] = f() # RUF009: Do not perform function call `f` in dataclass defaults this_is_also_not: int = f() # RUF009: Do not perform function call `f` in dataclass defaults ``` After PR: ``` def _( this_is_fine: int = f(), # No error this_is_not: list[int] = f() # B008: Do not perform function call `f` in argument defaults ): ... @DataClass class _: this_is_not_fine: list[int] = f() # RUF009: Do not perform function call `f` in dataclass defaults this_is_fine: int = f() ```
1 parent 07cf885 commit d2f661f

File tree

4 files changed

+29
-107
lines changed

4 files changed

+29
-107
lines changed

crates/ruff_linter/resources/test/fixtures/ruff/RUF009.py

+13
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,16 @@ class DataclassWithNewTypeFields:
9797
# No errors
9898
e: SpecialString = SpecialString("Lorem ipsum")
9999
f: NegativeInteger = NegativeInteger(-110)
100+
101+
102+
# Test for:
103+
# https://github.com/astral-sh/ruff/issues/15772
104+
def f() -> int:
105+
return 0
106+
107+
@dataclass
108+
class ShouldMatchB008RuleOfImmutableTypeAnnotationIgnored:
109+
this_is_not_fine: list[int] = default_function()
110+
# ignored
111+
this_is_fine: int = f()
112+

crates/ruff_linter/src/rules/ruff/rules/function_call_in_dataclass_default.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use ruff_python_ast::{self as ast, Expr, Stmt};
33
use ruff_diagnostics::{Diagnostic, Violation};
44
use ruff_macros::{derive_message_formats, ViolationMetadata};
55
use ruff_python_ast::name::{QualifiedName, UnqualifiedName};
6-
use ruff_python_semantic::analyze::typing::{is_immutable_func, is_immutable_newtype_call};
6+
use ruff_python_semantic::analyze::typing::{
7+
is_immutable_annotation, is_immutable_func, is_immutable_newtype_call,
8+
};
79
use ruff_text_size::Ranged;
810

911
use crate::checkers::ast::Checker;
@@ -134,6 +136,7 @@ pub(crate) fn function_call_in_dataclass_default(checker: &Checker, class_def: &
134136
}
135137

136138
if is_field
139+
|| is_immutable_annotation(annotation, checker.semantic(), &extend_immutable_calls)
137140
|| is_class_var_annotation(annotation, checker.semantic())
138141
|| is_immutable_func(func, checker.semantic(), &extend_immutable_calls)
139142
|| is_descriptor_class(func, checker.semantic())

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF009_RUF009.py.snap

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
source: crates/ruff_linter/src/rules/ruff/mod.rs
3+
snapshot_kind: text
34
---
45
RUF009.py:20:41: RUF009 Do not perform function call `default_function` in dataclass defaults
56
|
@@ -89,3 +90,13 @@ RUF009.py:95:19: RUF009 Do not perform function call `Invalid3` in dataclass def
8990
96 |
9091
97 | # No errors
9192
|
93+
94+
RUF009.py:109:35: RUF009 Do not perform function call `default_function` in dataclass defaults
95+
|
96+
107 | @dataclass
97+
108 | class ShouldMatchB008RuleOfImmutableTypeAnnotationIgnored:
98+
109 | this_is_not_fine: list[int] = default_function()
99+
| ^^^^^^^^^^^^^^^^^^ RUF009
100+
110 | # ignored
101+
111 | this_is_fine: int = f()
102+
|
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,5 @@
11
---
22
source: crates/ruff_linter/src/rules/ruff/mod.rs
3+
snapshot_kind: text
34
---
4-
RUF009_attrs_auto_attribs.py:12:14: RUF009 Do not perform function call `foo` in dataclass defaults
5-
|
6-
10 | a: str = 0
7-
11 | b = field()
8-
12 | c: int = foo()
9-
| ^^^^^ RUF009
10-
13 | d = list()
11-
|
125

13-
RUF009_attrs_auto_attribs.py:20:14: RUF009 Do not perform function call `foo` in dataclass defaults
14-
|
15-
18 | a: str = 0
16-
19 | b = field()
17-
20 | c: int = foo()
18-
| ^^^^^ RUF009
19-
21 | d = list()
20-
|
21-
22-
RUF009_attrs_auto_attribs.py:28:14: RUF009 Do not perform function call `foo` in dataclass defaults
23-
|
24-
26 | a: str = 0
25-
27 | b = field()
26-
28 | c: int = foo()
27-
| ^^^^^ RUF009
28-
29 | d = list()
29-
|
30-
31-
RUF009_attrs_auto_attribs.py:36:14: RUF009 Do not perform function call `foo` in dataclass defaults
32-
|
33-
34 | a: str = 0
34-
35 | b = field()
35-
36 | c: int = foo()
36-
| ^^^^^ RUF009
37-
37 | d = list()
38-
|
39-
40-
RUF009_attrs_auto_attribs.py:44:14: RUF009 Do not perform function call `foo` in dataclass defaults
41-
|
42-
42 | a: str = 0
43-
43 | b = field()
44-
44 | c: int = foo()
45-
| ^^^^^ RUF009
46-
45 | d = list()
47-
|
48-
49-
RUF009_attrs_auto_attribs.py:52:14: RUF009 Do not perform function call `foo` in dataclass defaults
50-
|
51-
50 | a: str = 0
52-
51 | b = field()
53-
52 | c: int = foo()
54-
| ^^^^^ RUF009
55-
53 | d = list()
56-
|
57-
58-
RUF009_attrs_auto_attribs.py:60:14: RUF009 Do not perform function call `foo` in dataclass defaults
59-
|
60-
58 | a: str = 0
61-
59 | b = field()
62-
60 | c: int = foo()
63-
| ^^^^^ RUF009
64-
61 | d = list()
65-
|
66-
67-
RUF009_attrs_auto_attribs.py:68:14: RUF009 Do not perform function call `foo` in dataclass defaults
68-
|
69-
66 | a: str = 0
70-
67 | b = field()
71-
68 | c: int = foo()
72-
| ^^^^^ RUF009
73-
69 | d = list()
74-
|
75-
76-
RUF009_attrs_auto_attribs.py:76:14: RUF009 Do not perform function call `foo` in dataclass defaults
77-
|
78-
74 | a: str = 0
79-
75 | b = field()
80-
76 | c: int = foo()
81-
| ^^^^^ RUF009
82-
77 | d = list()
83-
|
84-
85-
RUF009_attrs_auto_attribs.py:92:14: RUF009 Do not perform function call `foo` in dataclass defaults
86-
|
87-
90 | a: str = 0
88-
91 | b = field()
89-
92 | c: int = foo()
90-
| ^^^^^ RUF009
91-
93 | d = list()
92-
|
93-
94-
RUF009_attrs_auto_attribs.py:100:14: RUF009 Do not perform function call `foo` in dataclass defaults
95-
|
96-
98 | a: str = 0
97-
99 | b = field()
98-
100 | c: int = foo()
99-
| ^^^^^ RUF009
100-
101 | d = list()
101-
|
102-
103-
RUF009_attrs_auto_attribs.py:116:14: RUF009 Do not perform function call `foo` in dataclass defaults
104-
|
105-
114 | a: str = 0
106-
115 | b = field()
107-
116 | c: int = foo()
108-
| ^^^^^ RUF009
109-
117 | d = list()
110-
|

0 commit comments

Comments
 (0)