Merge pull request #5850 from youknowone/typing

Upgrade typing to 3.13.5
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2025-07-01 02:31:58 +09:00
commit e7c18f19ab
4 files changed
+112 -68

No files matched your search

-10
View File
@@ -3351,8 +3351,6 @@ class ProtocolTests(BaseTestCase):
self.assertNotIsSubclass(C, Protocol)
self.assertNotIsInstance(C(), Protocol)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_protocols_issubclass_non_callable(self):
class C:
x = 1
@@ -3412,8 +3410,6 @@ class ProtocolTests(BaseTestCase):
):
issubclass(Eggs, Spam)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_no_weird_caching_with_issubclass_after_isinstance_2(self):
@runtime_checkable
class Spam(Protocol):
@@ -3434,8 +3430,6 @@ class ProtocolTests(BaseTestCase):
):
issubclass(Eggs, Spam)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_no_weird_caching_with_issubclass_after_isinstance_3(self):
@runtime_checkable
class Spam(Protocol):
@@ -4091,8 +4085,6 @@ class GenericTests(BaseTestCase):
self.assertIs(MyChain[int]().__class__, MyChain)
self.assertEqual(MyChain[int]().__orig_class__, MyChain[int])
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_all_repr_eq_any(self):
objs = (getattr(typing, el) for el in typing.__all__)
for obj in objs:
@@ -9591,8 +9583,6 @@ class AllTests(BaseTestCase):
self.assertIn('SupportsBytes', a)
self.assertIn('SupportsComplex', a)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_all_exported_names(self):
# ensure all dynamically created objects are actualised
for name in typing.__all__:
+84 -41
View File
@@ -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.
@@ -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
@@ -1983,7 +1987,8 @@ def _allow_reckless_class_checks(depth=2):
The abc and functools modules indiscriminately call isinstance() and
issubclass() on the whole MRO of a user class, which may contain protocols.
"""
return _caller(depth) in {'abc', 'functools', None}
# XXX: RUSTPYTHON; https://github.com/python/cpython/pull/136115
return _caller(depth) in {'abc', '_py_abc', 'functools', None}
_PROTO_ALLOWLIST = {
@@ -2090,11 +2095,11 @@ class _ProtocolMeta(ABCMeta):
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):
@@ -2526,6 +2531,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
@@ -2548,6 +2565,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__
@@ -3225,6 +3246,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::
@@ -3680,44 +3713,43 @@ def dataclass_transform(
return cls_or_fn
return decorator
# TODO: RUSTPYTHON
# type _Func = Callable[..., Any]
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 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:
@@ -3740,8 +3772,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):
+24 -16
View File
@@ -535,9 +535,14 @@ impl PyObject {
derived.recursive_issubclass(cls, vm)
}
// _PyObject_RealIsInstance
pub(crate) fn real_is_instance(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
self.object_isinstance(cls, vm)
}
/// Real isinstance check without going through __instancecheck__
/// This is equivalent to CPython's _PyObject_RealIsInstance/object_isinstance
pub fn real_is_instance(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
fn object_isinstance(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
if let Ok(cls) = cls.try_to_ref::<PyType>(vm) {
// PyType_Check(cls) - cls is a type object
let mut retval = self.class().is_subtype(cls);
@@ -576,8 +581,12 @@ impl PyObject {
/// Determines if `self` is an instance of `cls`, either directly, indirectly or virtually via
/// the __instancecheck__ magic method.
// This is object_recursive_isinstance from CPython's Objects/abstract.c
pub fn is_instance(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
self.object_recursive_isinstance(cls, vm)
}
// This is object_recursive_isinstance from CPython's Objects/abstract.c
fn object_recursive_isinstance(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
// PyObject_TypeCheck(inst, (PyTypeObject *)cls)
// This is an exact check of the type
if self.class().is(cls) {
@@ -586,29 +595,28 @@ impl PyObject {
// PyType_CheckExact(cls) optimization
if cls.class().is(vm.ctx.types.type_type) {
// When cls is exactly a type (not a subclass), use real_is_instance
// When cls is exactly a type (not a subclass), use object_isinstance
// to avoid going through __instancecheck__ (matches CPython behavior)
return self.real_is_instance(cls, vm);
return self.object_isinstance(cls, vm);
}
// Check for Union type (e.g., int | str) - CPython checks this before tuple
if cls.class().is(vm.ctx.types.union_type) {
let cls = if cls.class().is(vm.ctx.types.union_type) {
// Match CPython's _Py_union_args which directly accesses the args field
let union = cls
.try_to_ref::<crate::builtins::PyUnion>(vm)
.expect("checked by is");
let tuple = union.args();
for typ in tuple.iter() {
if vm.with_recursion("in __instancecheck__", || self.is_instance(typ, vm))? {
return Ok(true);
}
}
}
union.args().as_object()
} else {
cls
};
// Check if cls is a tuple
if let Ok(tuple) = cls.try_to_ref::<PyTuple>(vm) {
for typ in tuple {
if vm.with_recursion("in __instancecheck__", || self.is_instance(typ, vm))? {
if let Some(tuple) = cls.downcast_ref::<PyTuple>() {
for item in tuple {
if vm.with_recursion("in __instancecheck__", || {
self.object_recursive_isinstance(item, vm)
})? {
return Ok(true);
}
}
@@ -624,7 +632,7 @@ impl PyObject {
}
// Fall back to object_isinstance (without going through __instancecheck__ again)
self.real_is_instance(cls, vm)
self.object_isinstance(cls, vm)
}
pub fn hash(&self, vm: &VirtualMachine) -> PyResult<PyHash> {
+4 -1
View File
@@ -48,7 +48,10 @@ pub(crate) mod decl {
#[pyfunction(name = "override")]
pub(crate) fn r#override(func: PyObjectRef, vm: &VirtualMachine) -> PyResult {
// Set __override__ attribute to True
func.set_attr("__override__", vm.ctx.true_value.clone(), vm)?;
// 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.
let _ = func.set_attr("__override__", vm.ctx.true_value.clone(), vm);
Ok(func)
}