mirror of https://github.com/astral-sh/ruff
Avoid treating `dataclasses.KW_ONLY` as typing-only (#12863)
## Summary Closes https://github.com/astral-sh/ruff/issues/12859.
This commit is contained in:
parent
d0ac38f9d3
commit
e05953a991
|
|
@ -0,0 +1,18 @@
|
||||||
|
"""Test: avoid marking a `KW_ONLY` annotation as typing-only."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import KW_ONLY, dataclass, Field
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Test1:
|
||||||
|
a: int
|
||||||
|
_: KW_ONLY
|
||||||
|
b: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Test2:
|
||||||
|
a: int
|
||||||
|
b: Field
|
||||||
|
|
@ -125,12 +125,14 @@ pub(crate) fn is_dataclass_meta_annotation(annotation: &Expr, semantic: &Semanti
|
||||||
matches!(qualified_name.segments(), ["dataclasses", "dataclass"])
|
matches!(qualified_name.segments(), ["dataclasses", "dataclass"])
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
// Determine whether the annotation is `typing.ClassVar` or `dataclasses.InitVar`.
|
// Determine whether the annotation is `typing.ClassVar`, `dataclasses.InitVar`, or `dataclasses.KW_ONLY`.
|
||||||
return semantic
|
return semantic
|
||||||
.resolve_qualified_name(map_subscript(annotation))
|
.resolve_qualified_name(map_subscript(annotation))
|
||||||
.is_some_and(|qualified_name| {
|
.is_some_and(|qualified_name| {
|
||||||
matches!(qualified_name.segments(), ["dataclasses", "InitVar"])
|
matches!(
|
||||||
|| semantic.match_typing_qualified_name(&qualified_name, "ClassVar")
|
qualified_name.segments(),
|
||||||
|
["dataclasses", "InitVar" | "KW_ONLY"]
|
||||||
|
) || semantic.match_typing_qualified_name(&qualified_name, "ClassVar")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ mod tests {
|
||||||
#[test_case(Rule::TypingOnlyFirstPartyImport, Path::new("TCH001.py"))]
|
#[test_case(Rule::TypingOnlyFirstPartyImport, Path::new("TCH001.py"))]
|
||||||
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("TCH003.py"))]
|
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("TCH003.py"))]
|
||||||
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("init_var.py"))]
|
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("init_var.py"))]
|
||||||
|
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("kw_only.py"))]
|
||||||
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("snapshot.py"))]
|
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("snapshot.py"))]
|
||||||
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("TCH002.py"))]
|
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("TCH002.py"))]
|
||||||
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("quote.py"))]
|
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("quote.py"))]
|
||||||
|
|
@ -77,6 +78,7 @@ mod tests {
|
||||||
|
|
||||||
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("strict.py"))]
|
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("strict.py"))]
|
||||||
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("init_var.py"))]
|
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("init_var.py"))]
|
||||||
|
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("kw_only.py"))]
|
||||||
fn strict(rule_code: Rule, path: &Path) -> Result<()> {
|
fn strict(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
let snapshot = format!("strict_{}_{}", rule_code.as_ref(), path.to_string_lossy());
|
let snapshot = format!("strict_{}_{}", rule_code.as_ref(), path.to_string_lossy());
|
||||||
let diagnostics = test_path(
|
let diagnostics = test_path(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
kw_only.py:5:45: TCH003 [*] Move standard library import `dataclasses.Field` into a type-checking block
|
||||||
|
|
|
||||||
|
3 | from __future__ import annotations
|
||||||
|
4 |
|
||||||
|
5 | from dataclasses import KW_ONLY, dataclass, Field
|
||||||
|
| ^^^^^ TCH003
|
||||||
|
|
|
||||||
|
= help: Move into type-checking block
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
2 2 |
|
||||||
|
3 3 | from __future__ import annotations
|
||||||
|
4 4 |
|
||||||
|
5 |-from dataclasses import KW_ONLY, dataclass, Field
|
||||||
|
5 |+from dataclasses import KW_ONLY, dataclass
|
||||||
|
6 |+from typing import TYPE_CHECKING
|
||||||
|
7 |+
|
||||||
|
8 |+if TYPE_CHECKING:
|
||||||
|
9 |+ from dataclasses import Field
|
||||||
|
6 10 |
|
||||||
|
7 11 |
|
||||||
|
8 12 | @dataclass
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
|
||||||
|
---
|
||||||
|
|
||||||
Loading…
Reference in New Issue