Skip to content
Merged
Changes from 1 commit
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
100 changes: 69 additions & 31 deletions src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
import typing
import warnings

if sys.version_info >= (3, 14):
# Breakpoint: https://github.com/python/cpython/pull/119891
if sys.version_info >= (3, 14, 0, "alpha", 1):
import annotationlib

__all__ = [
Expand Down Expand Up @@ -151,6 +152,7 @@
# for backward compatibility
PEP_560 = True
GenericMeta = type
# Breakpoint: https://github.com/python/cpython/pull/116129
_PEP_696_IMPLEMENTED = sys.version_info >= (3, 13, 0, "beta")

# Added with bpo-45166 to 3.10.1+ and some 3.9 versions
Expand All @@ -168,7 +170,8 @@ def __repr__(self):
_marker = _Sentinel()


if sys.version_info >= (3, 10):
# Breakpoint: https://github.com/python/cpython/pull/27342
if sys.version_info >= (3, 10, 0, "candidate"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the comments you're adding to link to the CPython PRs, but I'd leave the sys.version_info conditions as they are unless we know of an actual problem that needs to be fixed here. This kind of change has caused significant breakage for users in the past in ways that were hard for us to anticipate ahead of time; it doesn't seem worth it to me to change anything here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but I’m not quite sure what kind of breakages could occur in this case, especially for sys.version_info checks before importing attributes. I’m having trouble imagining how this change might cause issues. Could you elaborate or give an example?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, sorry for being vague! In #145, for example, I made it so that typing_extensions.Literal was no longer the same object as typing.Literal on Python <=3.9.0 (previously it had been the same object as typing.Literal on all Python versions >=3.8). Pydantic had internal code that incorrectly assumed that typing_extensions.Literal would always be the same object as typing.Literal on Python 3.8+, so this broke pydantic, causing a lot of disruption across the ecosystem and meaning we had to do a hotfix release of typing_extensions:

I don't think it's very likely that the specific changes you proposed here would cause that kind of breakage! But over the years of maintaining typing_extensions, I've come to realise that you really can't predict what kind of assumptions people are making about things like this -- I had no idea that change would break pydantic! So it's better not to make changes like this unless they're actually fixing something :-)

def _should_collect_from_parameters(t):
return isinstance(
t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType)
Expand All @@ -189,7 +192,8 @@ def _should_collect_from_parameters(t):
T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant.


if sys.version_info >= (3, 11):
# Breakpoint: https://github.com/python/cpython/pull/31841
if sys.version_info >= (3, 11, 0, "alpha", 7):
from typing import Any
else:

Expand Down Expand Up @@ -277,7 +281,8 @@ def __repr__(self):

Final = typing.Final

if sys.version_info >= (3, 11):
# Breakpoint: https://github.com/python/cpython/pull/30530
if sys.version_info >= (3, 11, 0, "alpha", 4):
final = typing.final
else:
# @final exists in 3.8+, but we backport it for all versions
Expand Down Expand Up @@ -320,6 +325,7 @@ def IntVar(name):


# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8
# Breakpoint: https://github.com/python/cpython/pull/29334
if sys.version_info >= (3, 10, 1):
Literal = typing.Literal
else:
Expand Down Expand Up @@ -480,6 +486,7 @@ def clear_overloads():
TYPE_CHECKING = typing.TYPE_CHECKING


# Breakpoint: https://github.com/python/cpython/pull/118681
if sys.version_info >= (3, 13, 0, "beta"):
from typing import AsyncContextManager, AsyncGenerator, ContextManager, Generator
else:
Expand Down Expand Up @@ -590,7 +597,8 @@ def _caller(depth=1, default='__main__'):

# `__match_args__` attribute was removed from protocol members in 3.13,
# we want to backport this change to older Python versions.
if sys.version_info >= (3, 13):
# Breakpoint: https://github.com/python/cpython/pull/110683
if sys.version_info >= (3, 13, 0, "alpha", 1):
Protocol = typing.Protocol
else:
def _allow_reckless_class_checks(depth=2):
Expand Down Expand Up @@ -770,7 +778,8 @@ def __init_subclass__(cls, *args, **kwargs):
cls.__init__ = _no_init


if sys.version_info >= (3, 13):
# Breakpoint: https://github.com/python/cpython/pull/113401
if sys.version_info >= (3, 13, 0, "alpha", 3):
runtime_checkable = typing.runtime_checkable
else:
def runtime_checkable(cls):
Expand Down Expand Up @@ -830,7 +839,8 @@ def close(self): ...


# Our version of runtime-checkable protocols is faster on Python <=3.11
if sys.version_info >= (3, 12):
# Breakpoint: https://github.com/python/cpython/pull/112717
if sys.version_info >= (3, 12, 0, "alpha", 3):
SupportsInt = typing.SupportsInt
SupportsFloat = typing.SupportsFloat
SupportsComplex = typing.SupportsComplex
Expand Down Expand Up @@ -1159,7 +1169,8 @@ def __new__(cls, name, bases, ns, *, total=True, closed=None,
mutable_keys.add(annotation_key)
readonly_keys.discard(annotation_key)

if sys.version_info >= (3, 14):
# Breakpoint: https://github.com/python/cpython/pull/119891
if sys.version_info >= (3, 14, 0, "alpha", 1):
def __annotate__(format):
annos = {}
for base in bases:
Expand Down Expand Up @@ -1249,7 +1260,8 @@ def _create_typeddict(
raise TypeError("TypedDict takes either a dict or keyword arguments,"
" but not both")
if kwargs:
if sys.version_info >= (3, 13):
# Breakpoint: https://github.com/python/cpython/pull/104891
if sys.version_info >= (3, 13, 0, "alpha", 1):
raise TypeError("TypedDict takes no keyword arguments")
warnings.warn(
"The kwargs-based syntax for TypedDict definitions is deprecated "
Expand Down Expand Up @@ -1458,7 +1470,8 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
hint = typing.get_type_hints(
obj, globalns=globalns, localns=localns, include_extras=True
)
if sys.version_info < (3, 11):
# Breakpoint: https://github.com/python/cpython/pull/30304
if sys.version_info < (3, 11, 0, "alpha", 6):
_clean_optional(obj, hint, globalns, localns)
if include_extras:
return hint
Expand Down Expand Up @@ -1530,7 +1543,8 @@ def _clean_optional(obj, hints, globalns=None, localns=None):

# Python 3.9 has get_origin() and get_args() but those implementations don't support
# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do.
if sys.version_info[:2] >= (3, 10):
# Breakpoint: https://github.com/python/cpython/pull/25298
if sys.version_info >= (3, 10, 0, "beta"):
get_origin = typing.get_origin
get_args = typing.get_args
# 3.9
Expand Down Expand Up @@ -2096,7 +2110,8 @@ def _concatenate_getitem(self, parameters):


# 3.11+; Concatenate does not accept ellipsis in 3.10
if sys.version_info >= (3, 11):
# Breakpoint: https://github.com/python/cpython/pull/30969
if sys.version_info >= (3, 11, 0, "beta"):
Concatenate = typing.Concatenate
# <=3.10
else:
Expand Down Expand Up @@ -2432,7 +2447,9 @@ def foo(**kwargs: Unpack[Movie]): ...
"""


if sys.version_info >= (3, 12): # PEP 692 changed the repr of Unpack[]
# PEP 692 changed the repr of Unpack[]
# Breakpoint: https://github.com/python/cpython/pull/104048
if sys.version_info >= (3, 12, 0, "beta"):
Unpack = typing.Unpack

def _is_unpack(obj):
Expand Down Expand Up @@ -2695,8 +2712,9 @@ def int_or_str(arg: int | str) -> None:
raise AssertionError(f"Expected code to be unreachable, but got: {value}")


if sys.version_info >= (3, 12): # 3.12+
# dataclass_transform exists in 3.11 but lacks the frozen_default parameter
# dataclass_transform exists in 3.11 but lacks the frozen_default parameter
# Breakpoint: https://github.com/python/cpython/pull/99958
if sys.version_info >= (3, 12, 0, "alpha", 3): # 3.12+
dataclass_transform = typing.dataclass_transform
else: # <=3.11
def dataclass_transform(
Expand Down Expand Up @@ -2827,6 +2845,7 @@ def method(self) -> None:


# Python 3.13.3+ contains a fix for the wrapped __new__
# Breakpoint: https://github.com/python/cpython/pull/132160
if sys.version_info >= (3, 13, 3):
deprecated = warnings.deprecated
else:
Expand Down Expand Up @@ -2956,7 +2975,8 @@ def wrapper(*args, **kwargs):
return arg(*args, **kwargs)

if asyncio.coroutines.iscoroutinefunction(arg):
if sys.version_info >= (3, 12):
# Breakpoint: https://github.com/python/cpython/pull/99247
if sys.version_info >= (3, 12, 0 , "alpha", 4):
wrapper = inspect.markcoroutinefunction(wrapper)
else:
wrapper._is_coroutine = asyncio.coroutines._is_coroutine
Expand All @@ -2969,12 +2989,8 @@ def wrapper(*args, **kwargs):
f"a class or callable, not {arg!r}"
)

if sys.version_info < (3, 10):
def _is_param_expr(arg):
return arg is ... or isinstance(
arg, (tuple, list, ParamSpec, _ConcatenateGenericAlias)
)
else:
# Breakpoint: https://github.com/python/cpython/pull/23702
if sys.version_info >= (3, 10, 0, "alpha", 4):
def _is_param_expr(arg):
return arg is ... or isinstance(
arg,
Expand All @@ -2986,6 +3002,11 @@ def _is_param_expr(arg):
typing._ConcatenateGenericAlias,
),
)
else:
def _is_param_expr(arg):
return arg is ... or isinstance(
arg, (tuple, list, ParamSpec, _ConcatenateGenericAlias)
)


# We have to do some monkey patching to deal with the dual nature of
Expand Down Expand Up @@ -3045,7 +3066,12 @@ def _check_generic(cls, parameters, elen=_marker):

expect_val = f"at least {elen}"

things = "arguments" if sys.version_info >= (3, 10) else "parameters"
# Breakpoint: https://github.com/python/cpython/pull/27515
things = (
"arguments"
if sys.version_info >= (3, 10, 0, "candidate")
else "parameters"
)
raise TypeError(f"Too {'many' if alen > elen else 'few'} {things}"
f" for {cls}; actual {alen}, expected {expect_val}")
else:
Expand Down Expand Up @@ -3238,6 +3264,7 @@ def _collect_parameters(args):
# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8.
# On 3.12, we added __orig_bases__ to call-based NamedTuples
# On 3.13, we deprecated kwargs-based NamedTuples
# Breakpoint: https://github.com/python/cpython/pull/105609
if sys.version_info >= (3, 13):
NamedTuple = typing.NamedTuple
else:
Expand Down Expand Up @@ -3313,7 +3340,8 @@ def __new__(cls, typename, bases, ns):
# using add_note() until py312.
# Making sure exceptions are raised in the same way
# as in "normal" classes seems most important here.
if sys.version_info >= (3, 12):
# Breakpoint: https://github.com/python/cpython/pull/95915
if sys.version_info >= (3, 12, 0, "alpha", 1):
e.add_note(msg)
raise
else:
Expand Down Expand Up @@ -3461,7 +3489,8 @@ class Baz(list[str]): ...

# NewType is a class on Python 3.10+, making it pickleable
# The error message for subclassing instances of NewType was improved on 3.11+
if sys.version_info >= (3, 11):
# Breakpoint: https://github.com/python/cpython/pull/30268
if sys.version_info >= (3, 11, 0, "alpha", 7):
NewType = typing.NewType
else:
class NewType:
Expand Down Expand Up @@ -3513,7 +3542,8 @@ def __repr__(self):
def __reduce__(self):
return self.__qualname__

if sys.version_info >= (3, 10):
# Breakpoint: https://github.com/python/cpython/pull/21515
if sys.version_info >= (3, 10, 0, "alpha", 1):
# PEP 604 methods
# It doesn't make sense to have these methods on Python <3.10

Expand All @@ -3524,11 +3554,13 @@ def __ror__(self, other):
return typing.Union[other, self]


if sys.version_info >= (3, 14):
# Breakpoint: https://github.com/python/cpython/pull/124795
if sys.version_info >= (3, 14, 0, "alpha", 1):
TypeAliasType = typing.TypeAliasType
# <=3.13
else:
if sys.version_info >= (3, 12):
# Breakpoint: https://github.com/python/cpython/pull/103764
if sys.version_info >= (3, 12, 0, "beta"):
# 3.12-3.13
def _is_unionable(obj):
"""Corresponds to is_unionable() in unionobject.c in CPython."""
Expand Down Expand Up @@ -3723,7 +3755,8 @@ def __init_subclass__(cls, *args, **kwargs):
def __call__(self):
raise TypeError("Type alias is not callable")

if sys.version_info >= (3, 10):
# Breakpoint: https://github.com/python/cpython/pull/21515
if sys.version_info >= (3, 10, 0, "alpha", 1):
def __or__(self, right):
# For forward compatibility with 3.12, reject Unions
# that are not accepted by the built-in Union.
Expand Down Expand Up @@ -3835,15 +3868,19 @@ def __eq__(self, other: object) -> bool:
__all__.append("CapsuleType")


if sys.version_info >= (3,14):
if sys.version_info >= (3, 14, 0, "alpha", 3):
from annotationlib import Format, get_annotations
else:
# Available since Python 3.14.0a3
# PR: https://github.com/python/cpython/pull/124415
class Format(enum.IntEnum):
VALUE = 1
VALUE_WITH_FAKE_GLOBALS = 2
FORWARDREF = 3
STRING = 4

# Available since Python 3.14.0a1
# PR: https://github.com/python/cpython/pull/119891
def get_annotations(obj, *, globals=None, locals=None, eval_str=False,
format=Format.VALUE):
"""Compute the annotations dict for an object.
Expand Down Expand Up @@ -4181,7 +4218,8 @@ def __repr__(self):
def __call__(self, *args, **kwargs):
raise TypeError(f"{type(self).__name__!r} object is not callable")

if sys.version_info >= (3, 10):
# Breakpoint: https://github.com/python/cpython/pull/21515
if sys.version_info >= (3, 10, 0, "alpha", 1):
def __or__(self, other):
return typing.Union[self, other]

Expand Down
Loading