Skip to content

Commit 04d5381

Browse files
wookie184charliermarshdylwil3MichaReiser
authored
Add all PEP-585 names to UP006 rule (#5454)
Co-authored-by: Charlie Marsh <[email protected]> Co-authored-by: dylwil3 <[email protected]> Co-authored-by: Micha Reiser <[email protected]>
1 parent 0b15f17 commit 04d5381

File tree

10 files changed

+585
-19
lines changed

10 files changed

+585
-19
lines changed

crates/ruff_linter/resources/test/fixtures/pyupgrade/UP006_0.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,22 @@ def f(x: typing.Deque[str]) -> None:
6464

6565
def f(x: typing.DefaultDict[str, str]) -> None:
6666
...
67+
68+
69+
def f(x: typing.AbstractSet[str]) -> None:
70+
...
71+
72+
73+
def f(x: typing.Pattern[str]) -> None:
74+
...
75+
76+
77+
def f(x: typing.Sequence[str]) -> None:
78+
...
79+
80+
81+
from typing import Collection
82+
83+
84+
def f(x: typing.Collection[str]) -> None:
85+
...

crates/ruff_linter/resources/test/fixtures/pyupgrade/UP006_1.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,19 @@
88

99
def f(x: typing.DefaultDict[str, str]) -> None:
1010
...
11+
12+
13+
from collections.abc import Set
14+
from typing_extensions import Awaitable
15+
16+
17+
def f(x: typing.AbstractSet[str]) -> None:
18+
...
19+
20+
21+
def f(x: Set) -> None:
22+
...
23+
24+
25+
def f(x: Awaitable) -> None:
26+
...

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,21 @@ mod tests {
111111
Ok(())
112112
}
113113

114+
#[test_case(Rule::NonPEP585Annotation, Path::new("UP006_0.py"))]
115+
#[test_case(Rule::NonPEP585Annotation, Path::new("UP006_1.py"))]
116+
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
117+
let snapshot = format!("preview__{}", path.to_string_lossy());
118+
let diagnostics = test_path(
119+
Path::new("pyupgrade").join(path).as_path(),
120+
&settings::LinterSettings {
121+
preview: PreviewMode::Enabled,
122+
..settings::LinterSettings::for_rule(rule_code)
123+
},
124+
)?;
125+
assert_messages!(snapshot, diagnostics);
126+
Ok(())
127+
}
128+
114129
#[test]
115130
fn async_timeout_error_alias_not_applied_py310() -> Result<()> {
116131
let diagnostics = test_path(

crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ use crate::settings::types::PythonVersion;
1414
/// Checks for the use of generics that can be replaced with standard library
1515
/// variants based on [PEP 585].
1616
///
17+
/// Under [preview mode](https://docs.astral.sh/ruff/preview),
18+
/// this rule triggers for all replacements listed
19+
/// in [PEP 585]. Otherwise, this rule only triggers for the following
20+
/// commonly occurring instances of modules present in the
21+
/// `typing` or `typing_extensions` package:
22+
///
23+
/// - `Dict`
24+
/// - `FrozenSet`
25+
/// - `List`
26+
/// - `Set`
27+
/// - `Tuple`
28+
/// - `Type`
29+
/// - `Deque`
30+
/// - `DefaultDict`
31+
///
1732
/// ## Why is this bad?
1833
/// [PEP 585] enabled collections in the Python standard library (like `list`)
1934
/// to be used as generics directly, instead of importing analogous members
@@ -81,6 +96,9 @@ pub(crate) fn use_pep585_annotation(
8196
expr: &Expr,
8297
replacement: &ModuleMember,
8398
) {
99+
if !checker.settings.preview.is_enabled() && !is_restricted_pep585_generic(replacement) {
100+
return;
101+
}
84102
let Some(from) = UnqualifiedName::from_expr(expr) else {
85103
return;
86104
};
@@ -138,3 +156,11 @@ pub(crate) fn use_pep585_annotation(
138156
}
139157
checker.diagnostics.push(diagnostic);
140158
}
159+
160+
fn is_restricted_pep585_generic(module_member: &ModuleMember) -> bool {
161+
matches!(
162+
module_member,
163+
ModuleMember::BuiltIn("dict" | "frozenset" | "list" | "set" | "tuple" | "type")
164+
| ModuleMember::Member("collections", "deque" | "defaultdict")
165+
)
166+
}

crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP006_0.py.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,5 @@ UP006_0.py:65:10: UP006 [*] Use `collections.defaultdict` instead of `typing.Def
281281
65 |-def f(x: typing.DefaultDict[str, str]) -> None:
282282
66 |+def f(x: defaultdict[str, str]) -> None:
283283
66 67 | ...
284+
67 68 |
285+
68 69 |

crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP006_1.py.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ UP006_1.py:9:10: UP006 [*] Use `collections.defaultdict` instead of `typing.Defa
1717
9 |-def f(x: typing.DefaultDict[str, str]) -> None:
1818
9 |+def f(x: defaultdict[str, str]) -> None:
1919
10 10 | ...
20+
11 11 |
21+
12 12 |

0 commit comments

Comments
 (0)