Skip to content

Commit

Permalink
Update UP035 for Python 3.13 and the latest version of typing_extensi…
Browse files Browse the repository at this point in the history
…ons (#11693)
  • Loading branch information
AlexWaygood authored Jun 2, 2024
1 parent 0ea2519 commit 94a3c53
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 16 deletions.
15 changes: 12 additions & 3 deletions crates/ruff_linter/resources/test/fixtures/pyupgrade/UP035.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@
# OK
from a import b

# OK: `typing_extensions` contains backported improvements.
# UP035 on py312+ only
from typing_extensions import SupportsIndex

# OK: `typing_extensions` contains backported improvements.
# UP035 on py312+ only
from typing_extensions import NamedTuple

# OK: `typing_extensions` supports `frozen_default` (backported from 3.12).
# UP035 on py312+ only: `typing_extensions` supports `frozen_default` (backported from 3.12).
from typing_extensions import dataclass_transform

# UP035
Expand All @@ -100,3 +100,12 @@

# UP035
from typing_extensions import get_original_bases

# UP035 on py313+ only
from typing_extensions import TypeVar

# UP035 on py313+ only
from typing_extensions import CapsuleType

# UP035 on py313+ only
from typing_extensions import deprecated
75 changes: 64 additions & 11 deletions crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,10 @@ const TYPING_EXTENSIONS_TO_TYPING: &[&str] = &[
"ClassVar",
"Collection",
"Container",
"ContextManager",
"Coroutine",
"DefaultDict",
"Dict",
"FrozenSet",
"Generator",
"Generic",
"Hashable",
"IO",
Expand Down Expand Up @@ -193,6 +191,8 @@ const TYPING_EXTENSIONS_TO_TYPING: &[&str] = &[
// Introduced in Python 3.5.2, but `typing_extensions` contains backported bugfixes and
// optimizations,
// "NewType",
// "Generator",
// "ContextManager",
];

// Python 3.7+
Expand All @@ -202,13 +202,16 @@ const MYPY_EXTENSIONS_TO_TYPING_37: &[&str] = &["NoReturn"];

// Members of `typing_extensions` that were moved to `typing`.
const TYPING_EXTENSIONS_TO_TYPING_37: &[&str] = &[
"AsyncContextManager",
"AsyncGenerator",
"ChainMap",
"Counter",
"Deque",
"ForwardRef",
"NoReturn",
// Introduced in Python <=3.7, but `typing_extensions` backports some features
// from Python 3.12/3.13
// "AsyncContextManager",
// "AsyncGenerator",
// "NamedTuple",
];

// Python 3.8+
Expand All @@ -220,12 +223,13 @@ const MYPY_EXTENSIONS_TO_TYPING_38: &[&str] = &["TypedDict"];
const TYPING_EXTENSIONS_TO_TYPING_38: &[&str] = &[
"Final",
"OrderedDict",
"runtime_checkable",
// Introduced in Python 3.8, but `typing_extensions` contains backported bugfixes and
// optimizations.
// "Literal",
// "Protocol",
// "SupportsIndex",
// "runtime_checkable",
// "TypedDict",
];

// Python 3.9+
Expand Down Expand Up @@ -332,23 +336,20 @@ const BACKPORTS_STR_ENUM_TO_ENUM_311: &[&str] = &["StrEnum"];

// Members of `typing_extensions` that were moved to `typing`.
const TYPING_EXTENSIONS_TO_TYPING_312: &[&str] = &[
// Introduced in Python 3.12, but `typing_extensions` backports some bug fixes.
// "NamedTuple",

// Introduced in Python 3.12, but `typing_extensions` backports support for PEP 705.
// "TypedDict",

// Introduced in Python 3.8, but `typing_extensions` backports a ton of optimizations that were
// added in Python 3.12.
"Protocol",
"SupportsAbs",
"SupportsBytes",
"SupportsComplex",
"SupportsFloat",
"SupportsIndex",
"SupportsInt",
"SupportsRound",
"TypeAliasType",
"Unpack",
// Introduced in Python 3.6, but `typing_extensions` backports bugfixes and features
"NamedTuple",
// Introduced in Python 3.11, but `typing_extensions` backports the `frozen_default` argument,
// which was introduced in Python 3.12.
"dataclass_transform",
Expand All @@ -361,6 +362,41 @@ const TYPING_EXTENSIONS_TO_COLLECTIONS_ABC_312: &[&str] = &["Buffer"];
// Members of `typing_extensions` that were moved to `types`.
const TYPING_EXTENSIONS_TO_TYPES_312: &[&str] = &["get_original_bases"];

// Python 3.13+

// Members of `typing_extensions` that were moved to `typing`.
const TYPING_EXTENSIONS_TO_TYPING_313: &[&str] = &[
"get_protocol_members",
"is_protocol",
"NoDefault",
"ReadOnly",
"TypeIs",
// Introduced in Python 3.6,
// but typing_extensions backports features from py313:
"ContextManager",
"Generator",
// Introduced in Python 3.7,
// but typing_extensions backports features from py313:
"AsyncContextManager",
"AsyncGenerator",
// Introduced in Python 3.8, but typing_extensions
// backports features and bugfixes from py313:
"Protocol",
"TypedDict",
"runtime_checkable",
// Introduced in earlier Python versions,
// but typing_extensions backports PEP-696:
"ParamSpec",
"TypeVar",
"TypevarTuple",
];

// Members of `typing_extensions` that were moved to `types`.
const TYPING_EXTENSIONS_TO_TYPES_313: &[&str] = &["CapsuleType"];

// Members of typing_extensions that were moved to `warnings`
const TYPING_EXTENSIONS_TO_WARNINGS_313: &[&str] = &["deprecated"];

struct ImportReplacer<'a> {
stmt: &'a Stmt,
module: &'a str,
Expand Down Expand Up @@ -441,11 +477,25 @@ impl<'a> ImportReplacer<'a> {
operations.push(operation);
}

// `typing_extensions` to `warnings`
let mut typing_extensions_to_warnings = vec![];
if self.version >= PythonVersion::Py313 {
typing_extensions_to_warnings.extend(TYPING_EXTENSIONS_TO_WARNINGS_313);
}
if let Some(operation) =
self.try_replace(&typing_extensions_to_warnings, "warnings")
{
operations.push(operation);
}

// `typing_extensions` to `types`
let mut typing_extensions_to_types = vec![];
if self.version >= PythonVersion::Py312 {
typing_extensions_to_types.extend(TYPING_EXTENSIONS_TO_TYPES_312);
}
if self.version >= PythonVersion::Py313 {
typing_extensions_to_types.extend(TYPING_EXTENSIONS_TO_TYPES_313);
}
if let Some(operation) = self.try_replace(&typing_extensions_to_types, "types") {
operations.push(operation);
}
Expand All @@ -470,6 +520,9 @@ impl<'a> ImportReplacer<'a> {
if self.version >= PythonVersion::Py312 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_312);
}
if self.version >= PythonVersion::Py313 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_313);
}
if let Some(operation) = self.try_replace(&typing_extensions_to_typing, "typing") {
operations.push(operation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -995,9 +995,49 @@ UP035.py:77:1: UP035 [*] Import from `collections.abc` instead: `Callable`
79 79 |
80 80 | # OK

UP035.py:84:1: UP035 [*] Import from `typing` instead: `SupportsIndex`
|
83 | # UP035 on py312+ only
84 | from typing_extensions import SupportsIndex
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP035
85 |
86 | # UP035 on py312+ only
|
= help: Import from `typing`

Safe fix
81 81 | from a import b
82 82 |
83 83 | # UP035 on py312+ only
84 |-from typing_extensions import SupportsIndex
84 |+from typing import SupportsIndex
85 85 |
86 86 | # UP035 on py312+ only
87 87 | from typing_extensions import NamedTuple

UP035.py:87:1: UP035 [*] Import from `typing` instead: `NamedTuple`
|
86 | # UP035 on py312+ only
87 | from typing_extensions import NamedTuple
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP035
88 |
89 | # UP035 on py312+ only: `typing_extensions` supports `frozen_default` (backported from 3.12).
|
= help: Import from `typing`

Safe fix
84 84 | from typing_extensions import SupportsIndex
85 85 |
86 86 | # UP035 on py312+ only
87 |-from typing_extensions import NamedTuple
87 |+from typing import NamedTuple
88 88 |
89 89 | # UP035 on py312+ only: `typing_extensions` supports `frozen_default` (backported from 3.12).
90 90 | from typing_extensions import dataclass_transform

UP035.py:90:1: UP035 [*] Import from `typing` instead: `dataclass_transform`
|
89 | # OK: `typing_extensions` supports `frozen_default` (backported from 3.12).
89 | # UP035 on py312+ only: `typing_extensions` supports `frozen_default` (backported from 3.12).
90 | from typing_extensions import dataclass_transform
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP035
91 |
Expand All @@ -1008,7 +1048,7 @@ UP035.py:90:1: UP035 [*] Import from `typing` instead: `dataclass_transform`
Safe fix
87 87 | from typing_extensions import NamedTuple
88 88 |
89 89 | # OK: `typing_extensions` supports `frozen_default` (backported from 3.12).
89 89 | # UP035 on py312+ only: `typing_extensions` supports `frozen_default` (backported from 3.12).
90 |-from typing_extensions import dataclass_transform
90 |+from typing import dataclass_transform
91 91 |
Expand Down Expand Up @@ -1080,6 +1120,8 @@ UP035.py:102:1: UP035 [*] Import from `types` instead: `get_original_bases`
101 | # UP035
102 | from typing_extensions import get_original_bases
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP035
103 |
104 | # UP035 on py313+ only
|
= help: Import from `types`

Expand All @@ -1089,5 +1131,61 @@ UP035.py:102:1: UP035 [*] Import from `types` instead: `get_original_bases`
101 101 | # UP035
102 |-from typing_extensions import get_original_bases
102 |+from types import get_original_bases
103 103 |
104 104 | # UP035 on py313+ only
105 105 | from typing_extensions import TypeVar

UP035.py:105:1: UP035 [*] Import from `typing` instead: `TypeVar`
|
104 | # UP035 on py313+ only
105 | from typing_extensions import TypeVar
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP035
106 |
107 | # UP035 on py313+ only
|
= help: Import from `typing`

ℹ Safe fix
102 102 | from typing_extensions import get_original_bases
103 103 |
104 104 | # UP035 on py313+ only
105 |-from typing_extensions import TypeVar
105 |+from typing import TypeVar
106 106 |
107 107 | # UP035 on py313+ only
108 108 | from typing_extensions import CapsuleType

UP035.py:108:1: UP035 [*] Import from `types` instead: `CapsuleType`
|
107 | # UP035 on py313+ only
108 | from typing_extensions import CapsuleType
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP035
109 |
110 | # UP035 on py313+ only
|
= help: Import from `types`

ℹ Safe fix
105 105 | from typing_extensions import TypeVar
106 106 |
107 107 | # UP035 on py313+ only
108 |-from typing_extensions import CapsuleType
108 |+from types import CapsuleType
109 109 |
110 110 | # UP035 on py313+ only
111 111 | from typing_extensions import deprecated

UP035.py:111:1: UP035 [*] Import from `warnings` instead: `deprecated`
|
110 | # UP035 on py313+ only
111 | from typing_extensions import deprecated
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP035
|
= help: Import from `warnings`

ℹ Safe fix
108 108 | from typing_extensions import CapsuleType
109 109 |
110 110 | # UP035 on py313+ only
111 |-from typing_extensions import deprecated
111 |+from warnings import deprecated

0 comments on commit 94a3c53

Please sign in to comment.