mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Merge pull request #5850 from youknowone/typing
Upgrade typing to 3.13.5
This commit is contained in:
4 files changed
+112
-68
No files matched your search
Vendored
-10
@@ -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__:
|
||||
|
||||
Vendored
+84
-41
@@ -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
@@ -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> {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user