Skip to content

Commit b5a45a8

Browse files
committed
updated suggestion message based on python version and typing-extensions setting
1 parent 7dbbaa0 commit b5a45a8

5 files changed

+65
-14
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,19 @@ mod tests {
202202
Ok(())
203203
}
204204

205+
#[test]
206+
fn class_dict_annotations_py314() -> Result<()> {
207+
let diagnostics = test_path(
208+
Path::new("ruff/RUF063.py"),
209+
&LinterSettings {
210+
unresolved_target_version: PythonVersion::PY314.into(),
211+
..LinterSettings::for_rule(Rule::ClassDictAnnotations)
212+
},
213+
)?;
214+
assert_messages!(diagnostics);
215+
Ok(())
216+
}
217+
205218
#[test]
206219
fn confusables() -> Result<()> {
207220
let diagnostics = test_path(

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,25 +71,33 @@ use ruff_text_size::Ranged;
7171
/// ## References
7272
/// - [Python Annotations Best Practices](https://docs.python.org/3.14/howto/annotations.html)
7373
#[derive(ViolationMetadata)]
74-
pub(crate) struct ClassDictAnnotations;
74+
pub(crate) struct ClassDictAnnotations {
75+
python_version: PythonVersion,
76+
}
7577

7678
impl Violation for ClassDictAnnotations {
7779
const FIX_AVAILABILITY: FixAvailability = FixAvailability::None;
7880

7981
#[derive_message_formats]
8082
fn message(&self) -> String {
81-
"Use `annotationlib.get_annotations` (Py3.14+), \
82-
`inspect.get_annotations` (Py3.10+), or \
83-
`typing_extensions.get_annotations` (Py<3.10 w/ `typing-extensions`) \
84-
instead of `__dict__.get('__annotations__')`"
85-
.to_string()
83+
let suggestion = if self.python_version >= PythonVersion::PY314 {
84+
"Use `annotationlib.get_annotations`"
85+
} else if self.python_version >= PythonVersion::PY310 {
86+
"Use `inspect.get_annotations`"
87+
} else {
88+
"Use `typing_extensions.get_annotations`"
89+
};
90+
format!("{suggestion} instead of `__dict__.get('__annotations__')`")
8691
}
8792
}
8893

8994
/// RUF063
9095
pub(crate) fn class_dict_annotations(checker: &Checker, call: &ExprCall) {
96+
let python_version = checker.target_version();
97+
let typing_extensions = checker.settings.typing_extensions;
98+
9199
// Only apply this rule for Python 3.10 and newer unless `typing-extensions` is enabled.
92-
if checker.target_version() < PythonVersion::PY310 && !checker.settings.typing_extensions {
100+
if python_version < PythonVersion::PY310 && !typing_extensions {
93101
return;
94102
}
95103

@@ -128,7 +136,7 @@ pub(crate) fn class_dict_annotations(checker: &Checker, call: &ExprCall) {
128136
.is_some_and(|s| s.value.to_str() == "__annotations__");
129137

130138
if is_first_arg_correct {
131-
checker.report_diagnostic(ClassDictAnnotations, call.range());
139+
checker.report_diagnostic(ClassDictAnnotations { python_version }, call.range());
132140
}
133141
}
134142
}

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__class_dict_annotations_py310.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
source: crates/ruff_linter/src/rules/ruff/mod.rs
33
---
4-
RUF063.py:4:1: RUF063 Use `annotationlib.get_annotations` (Py3.14+), `inspect.get_annotations` (Py3.10+), or `typing_extensions.get_annotations` (Py<3.10 w/ `typing-extensions`) instead of `__dict__.get('__annotations__')`
4+
RUF063.py:4:1: RUF063 Use `inspect.get_annotations` instead of `__dict__.get('__annotations__')`
55
|
66
2 | # Cases that should trigger the violation
77
3 |
@@ -11,15 +11,15 @@ RUF063.py:4:1: RUF063 Use `annotationlib.get_annotations` (Py3.14+), `inspect.ge
1111
6 | foo.__dict__.get("__annotations__", {}) # RUF063
1212
|
1313

14-
RUF063.py:5:1: RUF063 Use `annotationlib.get_annotations` (Py3.14+), `inspect.get_annotations` (Py3.10+), or `typing_extensions.get_annotations` (Py<3.10 w/ `typing-extensions`) instead of `__dict__.get('__annotations__')`
14+
RUF063.py:5:1: RUF063 Use `inspect.get_annotations` instead of `__dict__.get('__annotations__')`
1515
|
1616
4 | foo.__dict__.get("__annotations__") # RUF063
1717
5 | foo.__dict__.get("__annotations__", None) # RUF063
1818
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF063
1919
6 | foo.__dict__.get("__annotations__", {}) # RUF063
2020
|
2121

22-
RUF063.py:6:1: RUF063 Use `annotationlib.get_annotations` (Py3.14+), `inspect.get_annotations` (Py3.10+), or `typing_extensions.get_annotations` (Py<3.10 w/ `typing-extensions`) instead of `__dict__.get('__annotations__')`
22+
RUF063.py:6:1: RUF063 Use `inspect.get_annotations` instead of `__dict__.get('__annotations__')`
2323
|
2424
4 | foo.__dict__.get("__annotations__") # RUF063
2525
5 | foo.__dict__.get("__annotations__", None) # RUF063
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
source: crates/ruff_linter/src/rules/ruff/mod.rs
3+
---
4+
RUF063.py:4:1: RUF063 Use `annotationlib.get_annotations` instead of `__dict__.get('__annotations__')`
5+
|
6+
2 | # Cases that should trigger the violation
7+
3 |
8+
4 | foo.__dict__.get("__annotations__") # RUF063
9+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF063
10+
5 | foo.__dict__.get("__annotations__", None) # RUF063
11+
6 | foo.__dict__.get("__annotations__", {}) # RUF063
12+
|
13+
14+
RUF063.py:5:1: RUF063 Use `annotationlib.get_annotations` instead of `__dict__.get('__annotations__')`
15+
|
16+
4 | foo.__dict__.get("__annotations__") # RUF063
17+
5 | foo.__dict__.get("__annotations__", None) # RUF063
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF063
19+
6 | foo.__dict__.get("__annotations__", {}) # RUF063
20+
|
21+
22+
RUF063.py:6:1: RUF063 Use `annotationlib.get_annotations` instead of `__dict__.get('__annotations__')`
23+
|
24+
4 | foo.__dict__.get("__annotations__") # RUF063
25+
5 | foo.__dict__.get("__annotations__", None) # RUF063
26+
6 | foo.__dict__.get("__annotations__", {}) # RUF063
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF063
28+
7 |
29+
8 | # Cases that should NOT trigger the violation
30+
|

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__class_dict_annotations_py39_with_typing_extensions.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
source: crates/ruff_linter/src/rules/ruff/mod.rs
33
---
4-
RUF063.py:4:1: RUF063 Use `annotationlib.get_annotations` (Py3.14+), `inspect.get_annotations` (Py3.10+), or `typing_extensions.get_annotations` (Py<3.10 w/ `typing-extensions`) instead of `__dict__.get('__annotations__')`
4+
RUF063.py:4:1: RUF063 Use `typing_extensions.get_annotations` instead of `__dict__.get('__annotations__')`
55
|
66
2 | # Cases that should trigger the violation
77
3 |
@@ -11,15 +11,15 @@ RUF063.py:4:1: RUF063 Use `annotationlib.get_annotations` (Py3.14+), `inspect.ge
1111
6 | foo.__dict__.get("__annotations__", {}) # RUF063
1212
|
1313

14-
RUF063.py:5:1: RUF063 Use `annotationlib.get_annotations` (Py3.14+), `inspect.get_annotations` (Py3.10+), or `typing_extensions.get_annotations` (Py<3.10 w/ `typing-extensions`) instead of `__dict__.get('__annotations__')`
14+
RUF063.py:5:1: RUF063 Use `typing_extensions.get_annotations` instead of `__dict__.get('__annotations__')`
1515
|
1616
4 | foo.__dict__.get("__annotations__") # RUF063
1717
5 | foo.__dict__.get("__annotations__", None) # RUF063
1818
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF063
1919
6 | foo.__dict__.get("__annotations__", {}) # RUF063
2020
|
2121

22-
RUF063.py:6:1: RUF063 Use `annotationlib.get_annotations` (Py3.14+), `inspect.get_annotations` (Py3.10+), or `typing_extensions.get_annotations` (Py<3.10 w/ `typing-extensions`) instead of `__dict__.get('__annotations__')`
22+
RUF063.py:6:1: RUF063 Use `typing_extensions.get_annotations` instead of `__dict__.get('__annotations__')`
2323
|
2424
4 | foo.__dict__.get("__annotations__") # RUF063
2525
5 | foo.__dict__.get("__annotations__", None) # RUF063

0 commit comments

Comments
 (0)