Skip to content

Initial fixes for Python 3.14 #2747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions astroid/brain/brain_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from astroid import bases, context, nodes
from astroid.builder import _extract_single_node
from astroid.const import PY313_PLUS
from astroid.const import PY313
from astroid.exceptions import InferenceError, UseInferenceDefault
from astroid.inference_tip import inference_tip
from astroid.manager import AstroidManager
Expand All @@ -29,7 +29,7 @@ def _looks_like_parents_subscript(node: nodes.Subscript) -> bool:
value = next(node.value.infer())
except (InferenceError, StopIteration):
return False
parents = "builtins.tuple" if PY313_PLUS else "pathlib._PathParents"
parents = "builtins.tuple" if PY313 else "pathlib._PathParents"
return (
isinstance(value, bases.Instance)
and isinstance(value._proxied, nodes.ClassDef)
Expand Down
19 changes: 13 additions & 6 deletions astroid/brain/brain_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from astroid import context
from astroid.brain.helpers import register_module_extender
from astroid.builder import AstroidBuilder, _extract_single_node, extract_node
from astroid.const import PY312_PLUS, PY313_PLUS
from astroid.const import PY312_PLUS, PY313_PLUS, PY314_PLUS
from astroid.exceptions import (
AstroidSyntaxError,
AttributeInferenceError,
Expand Down Expand Up @@ -78,7 +78,7 @@
"typing.MutableMapping",
"typing.Sequence",
"typing.MutableSequence",
"typing.ByteString",
"typing.ByteString", # removed in 3.14
"typing.Tuple",
"typing.List",
"typing.Deque",
Expand Down Expand Up @@ -431,9 +431,8 @@


def _typing_transform():
return AstroidBuilder(AstroidManager()).string_build(
textwrap.dedent(
"""
code = textwrap.dedent(
"""
class Generic:
@classmethod
def __class_getitem__(cls, item): return cls
Expand Down Expand Up @@ -467,8 +466,16 @@
@classmethod
def __class_getitem__(cls, item): return cls
"""
)
)
if PY314_PLUS:
code += textwrap.dedent(

Check warning on line 471 in astroid/brain/brain_typing.py

View check run for this annotation

Codecov / codecov/patch

astroid/brain/brain_typing.py#L471

Added line #L471 was not covered by tests
"""
class Union:
@classmethod
def __class_getitem__(cls, item): return cls
"""
)
return AstroidBuilder(AstroidManager()).string_build(code)


def register(manager: AstroidManager) -> None:
Expand Down
2 changes: 2 additions & 0 deletions astroid/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
PY310_PLUS = sys.version_info >= (3, 10)
PY311_PLUS = sys.version_info >= (3, 11)
PY312_PLUS = sys.version_info >= (3, 12)
PY313 = sys.version_info[:2] == (3, 13)
PY313_PLUS = sys.version_info >= (3, 13)
PY314_PLUS = sys.version_info >= (3, 14)

WIN32 = sys.platform == "win32"

Expand Down
6 changes: 5 additions & 1 deletion tests/brain/test_brain.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from astroid import MANAGER, builder, nodes, objects, test_utils, util
from astroid.bases import Instance
from astroid.brain.brain_namedtuple_enum import _get_namedtuple_fields
from astroid.const import PY312_PLUS, PY313_PLUS
from astroid.const import PY312_PLUS, PY313_PLUS, PY314_PLUS
from astroid.exceptions import (
AttributeInferenceError,
InferenceError,
Expand Down Expand Up @@ -335,6 +335,9 @@ def test_collections_object_not_yet_subscriptable_2(self):
with self.assertRaises(InferenceError):
next(node.infer())

@pytest.mark.skipif(
PY314_PLUS, reason="collections.abc.ByteString was removed in 3.14"
)
def test_collections_object_subscriptable_3(self):
"""With Python 3.9 the ByteString class of the collections module is subscriptable
(but not the same class from typing module)"""
Expand Down Expand Up @@ -918,6 +921,7 @@ class Derived(typing.Hashable, typing.Iterator[int]):
],
)

@pytest.mark.skipif(PY314_PLUS, reason="typing.ByteString was removed in 3.14")
def test_typing_object_notsubscriptable_3(self):
"""Until python39 ByteString class of the typing module is not
subscriptable (whereas it is in the collections' module)"""
Expand Down
6 changes: 3 additions & 3 deletions tests/brain/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import astroid
from astroid import bases
from astroid.const import PY310_PLUS, PY313_PLUS
from astroid.const import PY310_PLUS, PY313
from astroid.util import Uninferable


Expand All @@ -23,7 +23,7 @@ def test_inference_parents() -> None:
inferred = name_node.inferred()
assert len(inferred) == 1
assert isinstance(inferred[0], bases.Instance)
if PY313_PLUS:
if PY313:
assert inferred[0].qname() == "builtins.tuple"
else:
assert inferred[0].qname() == "pathlib._PathParents"
Expand All @@ -43,7 +43,7 @@ def test_inference_parents_subscript_index() -> None:
inferred = path.inferred()
assert len(inferred) == 1
assert isinstance(inferred[0], bases.Instance)
if PY313_PLUS:
if PY313:
assert inferred[0].qname() == "pathlib._local.Path"
else:
assert inferred[0].qname() == "pathlib.Path"
Expand Down
10 changes: 7 additions & 3 deletions tests/test_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from astroid.arguments import CallSite
from astroid.bases import BoundMethod, Generator, Instance, UnboundMethod, UnionType
from astroid.builder import AstroidBuilder, _extract_single_node, extract_node, parse
from astroid.const import IS_PYPY, PY310_PLUS, PY312_PLUS
from astroid.const import IS_PYPY, PY310_PLUS, PY312_PLUS, PY314_PLUS
from astroid.context import CallContext, InferenceContext
from astroid.exceptions import (
AstroidTypeError,
Expand Down Expand Up @@ -1308,8 +1308,12 @@ class B: ...
assert i0.bool_value() is True
assert i0.pytype() == "types.UnionType"
assert i0.display_type() == "UnionType"
assert str(i0) == "UnionType(UnionType)"
assert repr(i0) == f"<UnionType(UnionType) l.0 at 0x{id(i0)}>"
if PY314_PLUS:
assert str(i0) == "UnionType(Union)"
assert repr(i0) == f"<UnionType(Union) l.0 at 0x{id(i0)}>"
else:
assert str(i0) == "UnionType(UnionType)"
assert repr(i0) == f"<UnionType(UnionType) l.0 at 0x{id(i0)}>"

i1 = ast_nodes[1].inferred()[0]
assert isinstance(i1, UnionType)
Expand Down