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
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
@@ -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
@@ -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)
19 changes: 13 additions & 6 deletions astroid/brain/brain_typing.py
Original file line number Diff line number Diff line change
@@ -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,
@@ -78,7 +78,7 @@
"typing.MutableMapping",
"typing.Sequence",
"typing.MutableSequence",
"typing.ByteString",
"typing.ByteString", # removed in 3.14
"typing.Tuple",
"typing.List",
"typing.Deque",
@@ -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
@@ -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

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:
2 changes: 2 additions & 0 deletions astroid/const.py
Original file line number Diff line number Diff line change
@@ -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"

6 changes: 5 additions & 1 deletion tests/brain/test_brain.py
Original file line number Diff line number Diff line change
@@ -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,
@@ -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)"""
@@ -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)"""
6 changes: 3 additions & 3 deletions tests/brain/test_pathlib.py
Original file line number Diff line number Diff line change
@@ -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


@@ -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"
@@ -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"
10 changes: 7 additions & 3 deletions tests/test_inference.py
Original file line number Diff line number Diff line change
@@ -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,
@@ -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)