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
Next Next commit
Update typing.py from CPython 3.13.5
  • Loading branch information
youknowone committed Jun 30, 2025
commit d5946d496d92e6e91090e8eac4971d4b513b82ae
128 changes: 85 additions & 43 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ def _should_unflatten_callable_args(typ, args):
>>> P = ParamSpec('P')
>>> collections.abc.Callable[[int, int], str].__args__ == (int, int, str)
True
>>> collections.abc.Callable[P, str].__args__ == (P, str)
True

As a result, if we need to reconstruct the Callable from its __args__,
we need to unflatten it.
Expand Down Expand Up @@ -263,6 +265,8 @@ def _collect_type_parameters(args, *, enforce_default_ordering: bool = True):

>>> P = ParamSpec('P')
>>> T = TypeVar('T')
>>> _collect_type_parameters((T, Callable[P, T]))
(~T, ~P)
"""
# required type parameter cannot appear after parameter with default
default_encountered = False
Expand Down Expand Up @@ -2090,11 +2094,11 @@ def __subclasscheck__(cls, other):
and cls.__dict__.get("__subclasshook__") is _proto_hook
):
_type_check_issubclass_arg_1(other)
# non_method_attrs = sorted(cls.__non_callable_proto_members__)
# raise TypeError(
# "Protocols with non-method members don't support issubclass()."
# f" Non-method members: {str(non_method_attrs)[1:-1]}."
# )
non_method_attrs = sorted(cls.__non_callable_proto_members__)
raise TypeError(
"Protocols with non-method members don't support issubclass()."
f" Non-method members: {str(non_method_attrs)[1:-1]}."
)
return _abc_subclasscheck(cls, other)

def __instancecheck__(cls, instance):
Expand Down Expand Up @@ -2526,6 +2530,18 @@ def get_origin(tp):

This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar,
Annotated, and others. Return None for unsupported types.

Examples::

>>> P = ParamSpec('P')
>>> assert get_origin(Literal[42]) is Literal
>>> assert get_origin(int) is None
>>> assert get_origin(ClassVar[int]) is ClassVar
>>> assert get_origin(Generic) is Generic
>>> assert get_origin(Generic[T]) is Generic
>>> assert get_origin(Union[T, int]) is Union
>>> assert get_origin(List[Tuple[T, T]][int]) is list
>>> assert get_origin(P.args) is P
"""
if isinstance(tp, _AnnotatedAlias):
return Annotated
Expand All @@ -2548,6 +2564,10 @@ def get_args(tp):

>>> T = TypeVar('T')
>>> assert get_args(Dict[str, int]) == (str, int)
>>> assert get_args(int) == ()
>>> assert get_args(Union[int, Union[T, int], str][int]) == (int, str)
>>> assert get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
>>> assert get_args(Callable[[], T][int]) == ([], int)
"""
if isinstance(tp, _AnnotatedAlias):
return (tp.__origin__,) + tp.__metadata__
Expand Down Expand Up @@ -3225,6 +3245,18 @@ def TypedDict(typename, fields=_sentinel, /, *, total=True):
associated with a value of a consistent type. This expectation
is not checked at runtime.

Usage::

>>> class Point2D(TypedDict):
... x: int
... y: int
... label: str
...
>>> a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK
>>> b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check
>>> Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
True

The type info can be accessed via the Point2D.__annotations__ dict, and
the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets.
TypedDict supports an additional equivalent form::
Expand Down Expand Up @@ -3680,44 +3712,43 @@ def decorator(cls_or_fn):
return cls_or_fn
return decorator

# TODO: RUSTPYTHON

# type _Func = Callable[..., Any]


# def override[F: _Func](method: F, /) -> F:
# """Indicate that a method is intended to override a method in a base class.
#
# Usage::
#
# class Base:
# def method(self) -> None:
# pass
#
# class Child(Base):
# @override
# def method(self) -> None:
# super().method()
#
# When this decorator is applied to a method, the type checker will
# validate that it overrides a method or attribute with the same name on a
# base class. This helps prevent bugs that may occur when a base class is
# changed without an equivalent change to a child class.
#
# There is no runtime checking of this property. The decorator attempts to
# set the ``__override__`` attribute to ``True`` on the decorated object to
# allow runtime introspection.
#
# See PEP 698 for details.
# """
# try:
# method.__override__ = True
# except (AttributeError, TypeError):
# # Skip the attribute silently if it is not writable.
# # AttributeError happens if the object has __slots__ or a
# # read-only property, TypeError if it's a builtin class.
# pass
# return method

type _Func = Callable[..., Any]


def override[F: _Func](method: F, /) -> F:
"""Indicate that a method is intended to override a method in a base class.

Usage::

class Base:
def method(self) -> None:
pass

class Child(Base):
@override
def method(self) -> None:
super().method()

When this decorator is applied to a method, the type checker will
validate that it overrides a method or attribute with the same name on a
base class. This helps prevent bugs that may occur when a base class is
changed without an equivalent change to a child class.

There is no runtime checking of this property. The decorator attempts to
set the ``__override__`` attribute to ``True`` on the decorated object to
allow runtime introspection.

See PEP 698 for details.
"""
try:
method.__override__ = True
except (AttributeError, TypeError):
# Skip the attribute silently if it is not writable.
# AttributeError happens if the object has __slots__ or a
# read-only property, TypeError if it's a builtin class.
pass
return method


def is_protocol(tp: type, /) -> bool:
Expand All @@ -3740,8 +3771,19 @@ def is_protocol(tp: type, /) -> bool:
and tp != Protocol
)


def get_protocol_members(tp: type, /) -> frozenset[str]:
"""Return the set of members defined in a Protocol.

Example::

>>> from typing import Protocol, get_protocol_members
>>> class P(Protocol):
... def a(self) -> str: ...
... b: int
>>> get_protocol_members(P) == frozenset({'a', 'b'})
True

Raise a TypeError for arguments that are not Protocols.
"""
if not is_protocol(tp):
Expand Down