mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Fix genericalias parameters (#5841)
* genericalias * Fix attr_exceptions list * impl TypeVarTuple iter * Update _collections_abc.py to Python 3.13 * genericalias.__unpack__
This commit is contained in:
7
Lib/_collections_abc.py
vendored
7
Lib/_collections_abc.py
vendored
@@ -85,6 +85,10 @@ dict_values = type({}.values())
|
||||
dict_items = type({}.items())
|
||||
## misc ##
|
||||
mappingproxy = type(type.__dict__)
|
||||
def _get_framelocalsproxy():
|
||||
return type(sys._getframe().f_locals)
|
||||
framelocalsproxy = _get_framelocalsproxy()
|
||||
del _get_framelocalsproxy
|
||||
generator = type((lambda: (yield))())
|
||||
## coroutine ##
|
||||
async def _coro(): pass
|
||||
@@ -836,6 +840,7 @@ class Mapping(Collection):
|
||||
__reversed__ = None
|
||||
|
||||
Mapping.register(mappingproxy)
|
||||
Mapping.register(framelocalsproxy)
|
||||
|
||||
|
||||
class MappingView(Sized):
|
||||
@@ -973,7 +978,7 @@ class MutableMapping(Mapping):
|
||||
|
||||
def update(self, other=(), /, **kwds):
|
||||
''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F.
|
||||
If E present and has a .keys() method, does: for k in E: D[k] = E[k]
|
||||
If E present and has a .keys() method, does: for k in E.keys(): D[k] = E[k]
|
||||
If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v
|
||||
In either case, this is followed by: for k, v in F.items(): D[k] = v
|
||||
'''
|
||||
|
||||
2
Lib/test/test_dataclasses.py
vendored
2
Lib/test/test_dataclasses.py
vendored
@@ -1906,8 +1906,6 @@ class TestCase(unittest.TestCase):
|
||||
c = Alias(10, 1.0)
|
||||
self.assertEqual(c.new_method(), 1.0)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_generic_dynamic(self):
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
2
Lib/test/test_exception_group.py
vendored
2
Lib/test/test_exception_group.py
vendored
@@ -15,6 +15,8 @@ class TestExceptionGroupTypeHierarchy(unittest.TestCase):
|
||||
with self.assertRaisesRegex(TypeError, 'Exception'):
|
||||
Exception[OSError]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_exception_group_is_generic_type(self):
|
||||
E = OSError
|
||||
self.assertIsInstance(ExceptionGroup[E], types.GenericAlias)
|
||||
|
||||
6
Lib/test/test_functools.py
vendored
6
Lib/test/test_functools.py
vendored
@@ -2897,8 +2897,6 @@ class TestSingleDispatch(unittest.TestCase):
|
||||
self.assertEqual(types_union(1), "types.UnionType")
|
||||
self.assertEqual(types_union(None), "types.UnionType")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_register_genericalias(self):
|
||||
@functools.singledispatch
|
||||
def f(arg):
|
||||
@@ -2918,8 +2916,6 @@ class TestSingleDispatch(unittest.TestCase):
|
||||
self.assertEqual(f(""), "default")
|
||||
self.assertEqual(f(b""), "default")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_register_genericalias_decorator(self):
|
||||
@functools.singledispatch
|
||||
def f(arg):
|
||||
@@ -2934,8 +2930,6 @@ class TestSingleDispatch(unittest.TestCase):
|
||||
with self.assertRaisesRegex(TypeError, "Invalid first argument to "):
|
||||
f.register(typing.List[int] | str)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_register_genericalias_annotation(self):
|
||||
@functools.singledispatch
|
||||
def f(arg):
|
||||
|
||||
6
Lib/test/test_genericalias.py
vendored
6
Lib/test/test_genericalias.py
vendored
@@ -173,8 +173,6 @@ class BaseTest(unittest.TestCase):
|
||||
self.assertEqual(a.__args__, (int,))
|
||||
self.assertEqual(a.__parameters__, ())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_parameters(self):
|
||||
from typing import List, Dict, Callable
|
||||
D0 = dict[str, int]
|
||||
@@ -214,8 +212,6 @@ class BaseTest(unittest.TestCase):
|
||||
self.assertEqual(L5.__args__, (Callable[[K, V], K],))
|
||||
self.assertEqual(L5.__parameters__, (K, V))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_parameter_chaining(self):
|
||||
from typing import List, Dict, Union, Callable
|
||||
self.assertEqual(list[T][int], list[int])
|
||||
@@ -307,8 +303,6 @@ class BaseTest(unittest.TestCase):
|
||||
self.assertEqual(a.__args__, (list[int], list[str]))
|
||||
self.assertEqual(a.__parameters__, ())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_union_generic(self):
|
||||
a = typing.Union[list[T], tuple[T, ...]]
|
||||
self.assertEqual(a.__args__, (list[T], tuple[T, ...]))
|
||||
|
||||
2
Lib/test/test_types.py
vendored
2
Lib/test/test_types.py
vendored
@@ -825,8 +825,6 @@ class UnionTests(unittest.TestCase):
|
||||
check(x | None, (x, type(None)))
|
||||
check(None | x, (type(None), x))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_union_parameter_chaining(self):
|
||||
T = typing.TypeVar("T")
|
||||
S = typing.TypeVar("S")
|
||||
|
||||
132
Lib/test/test_typing.py
vendored
132
Lib/test/test_typing.py
vendored
@@ -538,8 +538,6 @@ class TypeVarTests(BaseTestCase):
|
||||
self.assertEqual(subst(int|str), int|str)
|
||||
self.assertEqual(subst(Union[int, str]), Union[int, str])
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_bad_var_substitution(self):
|
||||
T = TypeVar('T')
|
||||
bad_args = (
|
||||
@@ -717,8 +715,6 @@ class TypeParameterDefaultsTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
class Y(Generic[*Ts_default, T]): ...
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_allow_default_after_non_default_in_alias(self):
|
||||
T_default = TypeVar('T_default', default=int)
|
||||
T = TypeVar('T')
|
||||
@@ -736,8 +732,6 @@ class TypeParameterDefaultsTests(BaseTestCase):
|
||||
a4 = Callable[*Ts, T]
|
||||
self.assertEqual(a4.__args__, (*Ts, T))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_paramspec_specialization(self):
|
||||
T = TypeVar("T")
|
||||
P = ParamSpec('P', default=[str, int])
|
||||
@@ -785,8 +779,6 @@ class TypeParameterDefaultsTests(BaseTestCase):
|
||||
self.assertIs(Ts.__default__, NoDefault)
|
||||
self.assertFalse(Ts.has_default())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_no_default_after_non_default(self):
|
||||
DefaultStrT = TypeVar('DefaultStrT', default=str)
|
||||
T = TypeVar('T')
|
||||
@@ -796,8 +788,6 @@ class TypeParameterDefaultsTests(BaseTestCase):
|
||||
):
|
||||
Test = Generic[DefaultStrT, T]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_need_more_params(self):
|
||||
DefaultStrT = TypeVar('DefaultStrT', default=str)
|
||||
T = TypeVar('T')
|
||||
@@ -1241,9 +1231,8 @@ class UnpackTests(BaseTestCase):
|
||||
def test_builtin_tuple(self):
|
||||
Ts = TypeVarTuple("Ts")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
# class Old(Generic[*Ts]): ...
|
||||
# class New[*Ts]: ...
|
||||
class Old(Generic[*Ts]): ...
|
||||
class New[*Ts]: ...
|
||||
|
||||
PartOld = Old[int, *Ts]
|
||||
self.assertEqual(PartOld[str].__args__, (int, str))
|
||||
@@ -1307,8 +1296,6 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
Ts()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_unpacked_typevartuple_is_equal_to_itself(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
self.assertEqual((*Ts,)[0], (*Ts,)[0])
|
||||
@@ -1319,8 +1306,6 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
# self.assertEqual(tuple[*Ts], tuple[*Ts])
|
||||
self.assertEqual(Tuple[Unpack[Ts]], Tuple[Unpack[Ts]])
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def tests_tuple_arg_ordering_matters(self):
|
||||
Ts1 = TypeVarTuple('Ts1')
|
||||
Ts2 = TypeVarTuple('Ts2')
|
||||
@@ -1639,7 +1624,7 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
def test_variadic_class_origin_is_correct(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
|
||||
# class C(Generic[*Ts]): pass
|
||||
class C(Generic[*Ts]): pass
|
||||
self.assertIs(C[int].__origin__, C)
|
||||
self.assertIs(C[T].__origin__, C)
|
||||
self.assertIs(C[Unpack[Ts]].__origin__, C)
|
||||
@@ -1682,8 +1667,6 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
# {'args': Unpack[CustomVariadic[int, str]]})
|
||||
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_tuple_args_are_correct(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
|
||||
@@ -1704,8 +1687,6 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
self.assertEqual(tuple[*Ts, int].__args__, (*Ts, int))
|
||||
self.assertEqual(Tuple[Unpack[Ts]].__args__, (Unpack[Ts],))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_callable_args_are_correct(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
Ts1 = TypeVarTuple('Ts1')
|
||||
@@ -1767,8 +1748,6 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
self.assertEqual(s.__args__, (*Ts1, *Ts2))
|
||||
self.assertEqual(u.__args__, (Unpack[Ts1], Unpack[Ts2]))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_variadic_class_with_duplicate_typevartuples_fails(self):
|
||||
Ts1 = TypeVarTuple('Ts1')
|
||||
Ts2 = TypeVarTuple('Ts2')
|
||||
@@ -1783,8 +1762,6 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
class F(Generic[Unpack[Ts1], Unpack[Ts2], Unpack[Ts1]]): pass
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_type_concatenation_in_variadic_class_argument_list_succeeds(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
class C(Generic[Unpack[Ts]]): pass
|
||||
@@ -1801,8 +1778,6 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
C[int, bool, *Ts, float, str]
|
||||
C[int, bool, Unpack[Ts], float, str]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_type_concatenation_in_tuple_argument_list_succeeds(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
|
||||
@@ -1816,15 +1791,11 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
Tuple[int, Unpack[Ts], str]
|
||||
Tuple[int, bool, Unpack[Ts], float, str]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_variadic_class_definition_using_packed_typevartuple_fails(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
with self.assertRaises(TypeError):
|
||||
class C(Generic[Ts]): pass
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_variadic_class_definition_using_concrete_types_fails(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
with self.assertRaises(TypeError):
|
||||
@@ -1832,8 +1803,6 @@ class TypeVarTupleTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
class E(Generic[Unpack[Ts], int]): pass
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_variadic_class_with_2_typevars_accepts_2_or_more_args(self):
|
||||
Ts = TypeVarTuple('Ts')
|
||||
T1 = TypeVar('T1')
|
||||
@@ -2037,8 +2006,6 @@ class TypeVarTuplePicklingTests(BaseTestCase):
|
||||
global_Ts2 = pickle.loads(pickle.dumps(global_Ts1, proto))
|
||||
self.assertIs(global_Ts1, global_Ts2)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@all_pickle_protocols
|
||||
def test_pickling_then_unpickling_unpacked_results_in_same_identity(self, proto):
|
||||
global global_Ts # See explanation at start of class.
|
||||
@@ -2052,8 +2019,6 @@ class TypeVarTuplePicklingTests(BaseTestCase):
|
||||
unpacked4 = pickle.loads(pickle.dumps(unpacked3, proto))
|
||||
self.assertIs(unpacked3, unpacked4)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@all_pickle_protocols
|
||||
def test_pickling_then_unpickling_tuple_with_typevartuple_equality(
|
||||
self, proto
|
||||
@@ -2221,8 +2186,6 @@ class UnionTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
hash(union3)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_repr(self):
|
||||
self.assertEqual(repr(Union), 'typing.Union')
|
||||
u = Union[Employee, int]
|
||||
@@ -2390,8 +2353,6 @@ class TupleTests(BaseTestCase):
|
||||
isinstance((0, 0), Tuple[int, int])
|
||||
self.assertIsInstance((0, 0), Tuple)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_repr(self):
|
||||
self.assertEqual(repr(Tuple), 'typing.Tuple')
|
||||
self.assertEqual(repr(Tuple[()]), 'typing.Tuple[()]')
|
||||
@@ -2473,8 +2434,6 @@ class BaseCallableTests:
|
||||
with self.assertRaises(TypeError):
|
||||
isinstance(None, Callable[[], Any])
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_repr(self):
|
||||
Callable = self.Callable
|
||||
fullname = f'{Callable.__module__}.Callable'
|
||||
@@ -2487,7 +2446,6 @@ class BaseCallableTests:
|
||||
ct3 = Callable[[str, float], list[int]]
|
||||
self.assertEqual(repr(ct3), f'{fullname}[[str, float], list[int]]')
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON")
|
||||
def test_callable_with_ellipsis(self):
|
||||
Callable = self.Callable
|
||||
def foo(a: Callable[..., T]):
|
||||
@@ -2520,8 +2478,6 @@ class BaseCallableTests:
|
||||
alias = Callable[[int, str], float]
|
||||
self.assertEqual(weakref.ref(alias)(), alias)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_pickle(self):
|
||||
global T_pickle, P_pickle, TS_pickle # needed for pickling
|
||||
Callable = self.Callable
|
||||
@@ -2547,8 +2503,6 @@ class BaseCallableTests:
|
||||
|
||||
del T_pickle, P_pickle, TS_pickle # cleaning up global state
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_var_substitution(self):
|
||||
Callable = self.Callable
|
||||
fullname = f"{Callable.__module__}.Callable"
|
||||
@@ -3202,8 +3156,6 @@ class ProtocolTests(BaseTestCase):
|
||||
self.assertIsInstance(C(), P)
|
||||
self.assertIsSubclass(C, P)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_protocols_issubclass(self):
|
||||
T = TypeVar('T')
|
||||
|
||||
@@ -3552,8 +3504,6 @@ class ProtocolTests(BaseTestCase):
|
||||
|
||||
class GenericTests(BaseTestCase):
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_basics(self):
|
||||
X = SimpleMapping[str, Any]
|
||||
self.assertEqual(X.__parameters__, ())
|
||||
@@ -3573,8 +3523,6 @@ class GenericTests(BaseTestCase):
|
||||
T = TypeVar("T")
|
||||
self.assertEqual(List[list[T] | float].__parameters__, (T,))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_generic_errors(self):
|
||||
T = TypeVar('T')
|
||||
S = TypeVar('S')
|
||||
@@ -3600,8 +3548,6 @@ class GenericTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
D[()]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_generic_subclass_checks(self):
|
||||
for typ in [list[int], List[int],
|
||||
tuple[int, str], Tuple[int, str],
|
||||
@@ -3618,8 +3564,6 @@ class GenericTests(BaseTestCase):
|
||||
# but, not when the right arg is also a generic:
|
||||
self.assertRaises(TypeError, isinstance, typ, typ)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_init(self):
|
||||
T = TypeVar('T')
|
||||
S = TypeVar('S')
|
||||
@@ -3740,8 +3684,6 @@ class GenericTests(BaseTestCase):
|
||||
# returned by the `Immutable[int]()` call
|
||||
self.assertIsInstance(Immutable[int](), Immutable)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_subscripted_generics_as_proxies(self):
|
||||
T = TypeVar('T')
|
||||
class C(Generic[T]):
|
||||
@@ -3851,8 +3793,6 @@ class GenericTests(BaseTestCase):
|
||||
self.assertTrue(naive_list_base_check([1, 2, 3], C))
|
||||
self.assertFalse(naive_list_base_check(['a', 'b'], C))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_multi_subscr_base(self):
|
||||
T = TypeVar('T')
|
||||
U = TypeVar('U')
|
||||
@@ -3948,8 +3888,6 @@ class GenericTests(BaseTestCase):
|
||||
self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''),
|
||||
'Callable[[], List[int]]')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_generic_forward_ref(self):
|
||||
def foobar(x: List[List['CC']]): ...
|
||||
def foobar2(x: list[list[ForwardRef('CC')]]): ...
|
||||
@@ -4046,8 +3984,6 @@ class GenericTests(BaseTestCase):
|
||||
set(ann_module695.C.__type_params__)
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_pep_695_generic_function_with_future_annotations(self):
|
||||
hints_for_generic_function = get_type_hints(ann_module695.generic_function)
|
||||
func_t_params = ann_module695.generic_function.__type_params__
|
||||
@@ -4109,8 +4045,6 @@ class GenericTests(BaseTestCase):
|
||||
set(results.generic_func.__type_params__)
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_extended_generic_rules_subclassing(self):
|
||||
class T1(Tuple[T, KT]): ...
|
||||
class T2(Tuple[T, ...]): ...
|
||||
@@ -4148,8 +4082,6 @@ class GenericTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
List[ClassVar[int]]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_fail_with_bare_generic(self):
|
||||
T = TypeVar('T')
|
||||
with self.assertRaises(TypeError):
|
||||
@@ -4354,8 +4286,6 @@ class GenericTests(BaseTestCase):
|
||||
with self.assertRaises(AttributeError):
|
||||
d_int.foobar = 'no'
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_errors(self):
|
||||
with self.assertRaises(TypeError):
|
||||
B = SimpleMapping[XK, Any]
|
||||
@@ -4513,8 +4443,6 @@ class GenericTests(BaseTestCase):
|
||||
(A, collections.abc.Sized, Generic, list, object),
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_multiple_inheritance_with_genericalias_2(self):
|
||||
T = TypeVar("T")
|
||||
|
||||
@@ -4611,8 +4539,6 @@ class GenericTests(BaseTestCase):
|
||||
|
||||
foo(42)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_implicit_any(self):
|
||||
T = TypeVar('T')
|
||||
|
||||
@@ -4838,8 +4764,6 @@ class FinalTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
Optional[Final[int]]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_repr(self):
|
||||
self.assertEqual(repr(Final), 'typing.Final')
|
||||
cv = Final[int]
|
||||
@@ -5138,8 +5062,6 @@ class NoTypeCheck_WithFunction:
|
||||
|
||||
|
||||
class ForwardRefTests(BaseTestCase):
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_basics(self):
|
||||
|
||||
class Node(Generic[T]):
|
||||
@@ -5270,8 +5192,6 @@ class ForwardRefTests(BaseTestCase):
|
||||
self.assertEqual(repr(List[ForwardRef('int', module='mod')]),
|
||||
"typing.List[ForwardRef('int', module='mod')]")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_union_forward(self):
|
||||
|
||||
def foo(a: Union['T']):
|
||||
@@ -5286,8 +5206,6 @@ class ForwardRefTests(BaseTestCase):
|
||||
self.assertEqual(get_type_hints(foo, globals(), locals()),
|
||||
{'a': tuple[T] | int})
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_tuple_forward(self):
|
||||
|
||||
def foo(a: Tuple['T']):
|
||||
@@ -5404,8 +5322,6 @@ class ForwardRefTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
get_type_hints(CF, globals()),
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_syntax_error(self):
|
||||
|
||||
with self.assertRaises(SyntaxError):
|
||||
@@ -5627,8 +5543,6 @@ class ForwardRefTests(BaseTestCase):
|
||||
|
||||
|
||||
class InternalsTests(BaseTestCase):
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_deprecation_for_no_type_params_passed_to__evaluate(self):
|
||||
with self.assertWarnsRegex(
|
||||
DeprecationWarning,
|
||||
@@ -6044,8 +5958,6 @@ class GetTypeHintTests(BaseTestCase):
|
||||
self.assertEqual(gth(ForRefExample.func), expects)
|
||||
self.assertEqual(gth(ForRefExample.nested), expects)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_get_type_hints_annotated(self):
|
||||
def foobar(x: List['X']): ...
|
||||
X = Annotated[int, (1, 10)]
|
||||
@@ -6109,8 +6021,6 @@ class GetTypeHintTests(BaseTestCase):
|
||||
{"x": typing.Annotated[int | float, "const"]}
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_get_type_hints_annotated_in_union(self): # bpo-46603
|
||||
def with_union(x: int | list[Annotated[str, 'meta']]): ...
|
||||
|
||||
@@ -6120,8 +6030,6 @@ class GetTypeHintTests(BaseTestCase):
|
||||
{'x': int | list[Annotated[str, 'meta']]},
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_get_type_hints_annotated_refs(self):
|
||||
|
||||
Const = Annotated[T, "Const"]
|
||||
@@ -6251,8 +6159,6 @@ class GetTypeHintTests(BaseTestCase):
|
||||
"year": NotRequired[Annotated[int, 2000]]
|
||||
})
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_get_type_hints_collections_abc_callable(self):
|
||||
# https://github.com/python/cpython/issues/91621
|
||||
P = ParamSpec('P')
|
||||
@@ -6267,8 +6173,6 @@ class GetTypeHintTests(BaseTestCase):
|
||||
|
||||
|
||||
class GetUtilitiesTestCase(TestCase):
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_get_origin(self):
|
||||
T = TypeVar('T')
|
||||
Ts = TypeVarTuple('Ts')
|
||||
@@ -6498,8 +6402,6 @@ class CollectionsAbcTests(BaseTestCase):
|
||||
def test_dict(self):
|
||||
self.assertIsSubclass(dict, typing.Dict)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_dict_subscribe(self):
|
||||
K = TypeVar('K')
|
||||
V = TypeVar('V')
|
||||
@@ -6704,8 +6606,6 @@ class CollectionsAbcTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
typing.AsyncGenerator[int, int]()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_subclassing(self):
|
||||
|
||||
class MMA(typing.MutableMapping):
|
||||
@@ -7124,8 +7024,6 @@ class NamedTupleTests(BaseTestCase):
|
||||
class C(NamedTuple, B):
|
||||
y: str
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_generic(self):
|
||||
class X(NamedTuple, Generic[T]):
|
||||
x: T
|
||||
@@ -7734,8 +7632,6 @@ class TypedDictTests(BaseTestCase):
|
||||
class Wrong(*bases):
|
||||
pass
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_is_typeddict(self):
|
||||
self.assertIs(is_typeddict(Point2D), True)
|
||||
self.assertIs(is_typeddict(Union[str, int]), False)
|
||||
@@ -7882,8 +7778,6 @@ class TypedDictTests(BaseTestCase):
|
||||
class Point3D(Point2DGeneric[T], Generic[KT]):
|
||||
c: KT
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_implicit_any_inheritance(self):
|
||||
class A(TypedDict, Generic[T]):
|
||||
a: T
|
||||
@@ -8165,8 +8059,6 @@ class NotRequiredTests(BaseTestCase):
|
||||
|
||||
class IOTests(BaseTestCase):
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_io(self):
|
||||
|
||||
def stuff(a: IO) -> AnyStr:
|
||||
@@ -8175,8 +8067,6 @@ class IOTests(BaseTestCase):
|
||||
a = stuff.__annotations__['a']
|
||||
self.assertEqual(a.__parameters__, (AnyStr,))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_textio(self):
|
||||
|
||||
def stuff(a: TextIO) -> str:
|
||||
@@ -8185,8 +8075,6 @@ class IOTests(BaseTestCase):
|
||||
a = stuff.__annotations__['a']
|
||||
self.assertEqual(a.__parameters__, ())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_binaryio(self):
|
||||
|
||||
def stuff(a: BinaryIO) -> bytes:
|
||||
@@ -8506,8 +8394,6 @@ class AnnotatedTests(BaseTestCase):
|
||||
with self.assertRaisesRegex(TypeError, 'at least two arguments'):
|
||||
Annotated[int]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_pickle(self):
|
||||
samples = [typing.Any, typing.Union[int, str],
|
||||
typing.Optional[str], Tuple[int, ...],
|
||||
@@ -8792,8 +8678,6 @@ class ParamSpecTests(BaseTestCase):
|
||||
self.assertEqual(P.__name__, 'P')
|
||||
self.assertIs(P.__module__, None)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_valid_uses(self):
|
||||
P = ParamSpec('P')
|
||||
T = TypeVar('T')
|
||||
@@ -8847,8 +8731,6 @@ class ParamSpecTests(BaseTestCase):
|
||||
gth(C.foo, globals(), locals()), {"args": P.args, "kwargs": P.kwargs}
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_user_generics(self):
|
||||
T = TypeVar("T")
|
||||
P = ParamSpec("P")
|
||||
@@ -8903,8 +8785,6 @@ class ParamSpecTests(BaseTestCase):
|
||||
with self.assertRaisesRegex(TypeError, "many arguments for"):
|
||||
Z[P_2, bool]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_multiple_paramspecs_in_user_generics(self):
|
||||
P = ParamSpec("P")
|
||||
P2 = ParamSpec("P2")
|
||||
@@ -9270,8 +9150,6 @@ class TypeGuardTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
TypeGuard[int, str]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_repr(self):
|
||||
self.assertEqual(repr(TypeGuard), 'typing.TypeGuard')
|
||||
cv = TypeGuard[int]
|
||||
@@ -9322,8 +9200,6 @@ class TypeIsTests(BaseTestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
TypeIs[int, str]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_repr(self):
|
||||
self.assertEqual(repr(TypeIs), 'typing.TypeIs')
|
||||
cv = TypeIs[int]
|
||||
@@ -9553,8 +9429,6 @@ class SpecialAttrsTests(BaseTestCase):
|
||||
loaded = pickle.loads(s)
|
||||
self.assertIs(SpecialAttrsP, loaded)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_genericalias_dir(self):
|
||||
class Foo(Generic[T]):
|
||||
def bar(self):
|
||||
|
||||
@@ -17,10 +17,15 @@ use crate::{
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
static ATTR_EXCEPTIONS: [&str; 8] = [
|
||||
// attr_exceptions
|
||||
static ATTR_EXCEPTIONS: [&str; 12] = [
|
||||
"__class__",
|
||||
"__bases__",
|
||||
"__origin__",
|
||||
"__args__",
|
||||
"__unpacked__",
|
||||
"__parameters__",
|
||||
"__typing_unpacked_tuple_args__",
|
||||
"__mro_entries__",
|
||||
"__reduce_ex__", // needed so we don't look up object.__reduce_ex__
|
||||
"__reduce__",
|
||||
@@ -33,6 +38,7 @@ pub struct PyGenericAlias {
|
||||
origin: PyTypeRef,
|
||||
args: PyTupleRef,
|
||||
parameters: PyTupleRef,
|
||||
starred: bool, // for __unpacked__ attribute
|
||||
}
|
||||
|
||||
impl fmt::Debug for PyGenericAlias {
|
||||
@@ -87,6 +93,7 @@ impl PyGenericAlias {
|
||||
origin,
|
||||
args,
|
||||
parameters,
|
||||
starred: false, // default to false, will be set to true for Unpack[...]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +158,11 @@ impl PyGenericAlias {
|
||||
self.origin.clone().into()
|
||||
}
|
||||
|
||||
#[pygetset(magic)]
|
||||
fn unpacked(&self) -> bool {
|
||||
self.starred
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let new_args = subs_parameters(
|
||||
@@ -212,40 +224,55 @@ impl PyGenericAlias {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool {
|
||||
let class = obj.class();
|
||||
"TypeVar" == &*class.slot_name()
|
||||
&& class
|
||||
.get_attr(identifier!(vm, __module__))
|
||||
.and_then(|o| o.downcast_ref::<PyStr>().map(|s| s.as_str() == "typing"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub(crate) fn make_parameters(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len());
|
||||
let mut iparam = 0;
|
||||
|
||||
for arg in args {
|
||||
if is_typevar(arg, vm) {
|
||||
if !parameters.iter().any(|param| param.is(arg)) {
|
||||
parameters.push(arg.clone());
|
||||
// We don't want __parameters__ descriptor of a bare Python class.
|
||||
if arg.class().is(vm.ctx.types.type_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for __typing_subst__ attribute (like CPython)
|
||||
if arg.get_attr(identifier!(vm, __typing_subst__), vm).is_ok() {
|
||||
// Use tuple_add equivalent logic
|
||||
if tuple_index(¶meters, arg).is_none() {
|
||||
if iparam >= parameters.len() {
|
||||
parameters.resize(iparam + 1, vm.ctx.none());
|
||||
}
|
||||
parameters[iparam] = arg.clone();
|
||||
iparam += 1;
|
||||
}
|
||||
} else if let Ok(obj) = arg.get_attr(identifier!(vm, __parameters__), vm) {
|
||||
if let Ok(sub_params) = obj.try_to_ref::<PyTuple>(vm) {
|
||||
} else if let Ok(subparams) = arg.get_attr(identifier!(vm, __parameters__), vm) {
|
||||
if let Ok(sub_params) = subparams.try_to_ref::<PyTuple>(vm) {
|
||||
let len2 = sub_params.len();
|
||||
// Resize if needed
|
||||
if iparam + len2 > parameters.len() {
|
||||
parameters.resize(iparam + len2, vm.ctx.none());
|
||||
}
|
||||
for sub_param in sub_params {
|
||||
if !parameters.iter().any(|param| param.is(sub_param)) {
|
||||
parameters.push(sub_param.clone());
|
||||
// Use tuple_add equivalent logic
|
||||
if tuple_index(¶meters[..iparam], sub_param).is_none() {
|
||||
if iparam >= parameters.len() {
|
||||
parameters.resize(iparam + 1, vm.ctx.none());
|
||||
}
|
||||
parameters[iparam] = sub_param.clone();
|
||||
iparam += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parameters.shrink_to_fit();
|
||||
|
||||
// Resize to actual size
|
||||
parameters.truncate(iparam);
|
||||
PyTuple::new_ref(parameters, &vm.ctx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn tuple_index(tuple: &PyTupleRef, item: &PyObjectRef) -> Option<usize> {
|
||||
tuple.iter().position(|element| element.is(item))
|
||||
fn tuple_index(vec: &[PyObjectRef], item: &PyObjectRef) -> Option<usize> {
|
||||
vec.iter().position(|element| element.is(item))
|
||||
}
|
||||
|
||||
fn subs_tvars(
|
||||
@@ -261,16 +288,32 @@ fn subs_tvars(
|
||||
.ok()
|
||||
.filter(|sub_params| !sub_params.is_empty())
|
||||
.map(|sub_params| {
|
||||
let sub_args = sub_params
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if let Some(idx) = tuple_index(params, arg) {
|
||||
arg_items[idx].clone()
|
||||
} else {
|
||||
arg.clone()
|
||||
let mut sub_args = Vec::new();
|
||||
|
||||
for arg in sub_params.iter() {
|
||||
if let Some(idx) = tuple_index(params.as_slice(), arg) {
|
||||
let param = ¶ms[idx];
|
||||
let substituted_arg = &arg_items[idx];
|
||||
|
||||
// Check if this is a TypeVarTuple (has tp_iter)
|
||||
if param.class().slots.iter.load().is_some()
|
||||
&& substituted_arg.try_to_ref::<PyTuple>(vm).is_ok()
|
||||
{
|
||||
// TypeVarTuple case - extend with tuple elements
|
||||
if let Ok(tuple) = substituted_arg.try_to_ref::<PyTuple>(vm) {
|
||||
for elem in tuple.iter() {
|
||||
sub_args.push(elem.clone());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
sub_args.push(substituted_arg.clone());
|
||||
} else {
|
||||
sub_args.push(arg.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let sub_args: PyObjectRef = PyTuple::new_ref(sub_args, &vm.ctx).into();
|
||||
obj.get_item(&*sub_args, vm)
|
||||
})
|
||||
@@ -278,6 +321,7 @@ fn subs_tvars(
|
||||
.unwrap_or(Ok(obj))
|
||||
}
|
||||
|
||||
// _Py_subs_parameters
|
||||
pub fn subs_parameters<F: Fn(&VirtualMachine) -> PyResult<String>>(
|
||||
repr: F,
|
||||
args: PyTupleRef,
|
||||
@@ -297,26 +341,62 @@ pub fn subs_parameters<F: Fn(&VirtualMachine) -> PyResult<String>>(
|
||||
};
|
||||
|
||||
let num_items = arg_items.len();
|
||||
if num_params != num_items {
|
||||
let plural = if num_items > num_params {
|
||||
"many"
|
||||
} else {
|
||||
"few"
|
||||
};
|
||||
return Err(vm.new_type_error(format!("Too {} arguments for {}", plural, repr(vm)?)));
|
||||
|
||||
// Check if we need to apply default values
|
||||
if num_items < num_params {
|
||||
// Count how many parameters have defaults
|
||||
let mut params_with_defaults = 0;
|
||||
for param in parameters.iter().rev() {
|
||||
if let Ok(has_default) = vm.call_method(param, "has_default", ()) {
|
||||
if has_default.try_to_bool(vm)? {
|
||||
params_with_defaults += 1;
|
||||
} else {
|
||||
break; // No more defaults from this point backwards
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let min_required = num_params - params_with_defaults;
|
||||
if num_items < min_required {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"Too few arguments for {}; actual {}, expected at least {}",
|
||||
repr(vm)?,
|
||||
num_items,
|
||||
min_required
|
||||
)));
|
||||
}
|
||||
} else if num_items > num_params {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"Too many arguments for {}; actual {}, expected {}",
|
||||
repr(vm)?,
|
||||
num_items,
|
||||
num_params
|
||||
)));
|
||||
}
|
||||
|
||||
let new_args = args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if is_typevar(arg, vm) {
|
||||
let idx = tuple_index(¶meters, arg).unwrap();
|
||||
Ok(arg_items[idx].clone())
|
||||
let mut new_args = Vec::new();
|
||||
|
||||
for arg in args.iter() {
|
||||
// Check for __typing_subst__ attribute directly (like CPython)
|
||||
if let Ok(subst) = arg.get_attr(identifier!(vm, __typing_subst__), vm) {
|
||||
let idx = tuple_index(parameters.as_slice(), arg).unwrap();
|
||||
if idx < num_items {
|
||||
// Call __typing_subst__ with the argument
|
||||
let substituted = subst.call((arg_items[idx].clone(),), vm)?;
|
||||
new_args.push(substituted);
|
||||
} else {
|
||||
subs_tvars(arg.clone(), ¶meters, arg_items, vm)
|
||||
// CPython doesn't support default values in this context
|
||||
return Err(vm.new_type_error(format!(
|
||||
"No argument provided for parameter at index {}",
|
||||
idx
|
||||
)));
|
||||
}
|
||||
})
|
||||
.collect::<PyResult<Vec<_>>>()?;
|
||||
} else {
|
||||
new_args.push(subs_tvars(arg.clone(), ¶meters, arg_items, vm)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PyTuple::new_ref(new_args, &vm.ctx))
|
||||
}
|
||||
|
||||
@@ -104,6 +104,8 @@ impl PyObject {
|
||||
self.get_attr(attr_name, vm).map(|o| !vm.is_none(&o))
|
||||
}
|
||||
|
||||
/// Get an attribute by name.
|
||||
/// `attr_name` can be a `&str`, `String`, or `PyStrRef`.
|
||||
pub fn get_attr<'a>(&self, attr_name: impl AsPyStr<'a>, vm: &VirtualMachine) -> PyResult {
|
||||
let attr_name = attr_name.as_pystr(&vm.ctx);
|
||||
self.get_attr_inner(attr_name, vm)
|
||||
|
||||
@@ -13,11 +13,11 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
|
||||
#[pymodule(name = "_typing")]
|
||||
pub(crate) mod decl {
|
||||
use crate::{
|
||||
AsObject, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
builtins::{PyGenericAlias, PyTupleRef, PyTypeRef, pystr::AsPyStr},
|
||||
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
builtins::{PyTupleRef, PyTypeRef, pystr::AsPyStr},
|
||||
function::{FuncArgs, IntoFuncArgs, PyComparisonValue},
|
||||
protocol::PyNumberMethods,
|
||||
types::{AsNumber, Comparable, Constructor, PyComparisonOp, Representable},
|
||||
types::{AsNumber, Comparable, Constructor, Iterable, PyComparisonOp, Representable},
|
||||
};
|
||||
|
||||
pub(crate) fn _call_typing_func_object<'a>(
|
||||
@@ -607,7 +607,7 @@ pub(crate) mod decl {
|
||||
default_value: parking_lot::Mutex<PyObjectRef>,
|
||||
evaluate_default: PyObjectRef,
|
||||
}
|
||||
#[pyclass(flags(HAS_DICT), with(Constructor, Representable))]
|
||||
#[pyclass(flags(HAS_DICT), with(Constructor, Representable, Iterable))]
|
||||
impl TypeVarTuple {
|
||||
#[pygetset(magic)]
|
||||
fn name(&self) -> PyObjectRef {
|
||||
@@ -667,6 +667,20 @@ pub(crate) mod decl {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for TypeVarTuple {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
// When unpacking TypeVarTuple with *, return [Unpack[self]]
|
||||
// This is how CPython handles Generic[*Ts]
|
||||
let typing = vm.import("typing", 0)?;
|
||||
let unpack = typing.get_attr("Unpack", vm)?;
|
||||
let zelf_obj: PyObjectRef = zelf.into();
|
||||
let unpacked = vm.call_method(&unpack, "__getitem__", (zelf_obj,))?;
|
||||
let list = vm.ctx.new_list(vec![unpacked]);
|
||||
let list_obj: PyObjectRef = list.into();
|
||||
vm.call_method(&list_obj, "__iter__", ())
|
||||
}
|
||||
}
|
||||
|
||||
impl Constructor for TypeVarTuple {
|
||||
type Args = FuncArgs;
|
||||
|
||||
@@ -920,6 +934,30 @@ pub(crate) mod decl {
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to call typing module functions with cls as first argument
|
||||
/// Similar to CPython's call_typing_args_kwargs
|
||||
fn call_typing_args_kwargs(
|
||||
name: &'static str,
|
||||
cls: PyTypeRef,
|
||||
args: FuncArgs,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let typing = vm.import("typing", 0)?;
|
||||
let func = typing.get_attr(name, vm)?;
|
||||
|
||||
// Prepare arguments: (cls, *args)
|
||||
let mut call_args = vec![cls.into()];
|
||||
call_args.extend(args.args);
|
||||
|
||||
// Call with prepared args and original kwargs
|
||||
let func_args = FuncArgs {
|
||||
args: call_args,
|
||||
kwargs: args.kwargs,
|
||||
};
|
||||
|
||||
func.call(func_args, vm)
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
#[pyclass(name)]
|
||||
#[derive(Debug, PyPayload)]
|
||||
@@ -930,8 +968,18 @@ pub(crate) mod decl {
|
||||
#[pyclass(flags(BASETYPE))]
|
||||
impl Generic {
|
||||
#[pyclassmethod(magic)]
|
||||
fn class_getitem(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
|
||||
PyGenericAlias::new(cls, args, vm)
|
||||
fn class_getitem(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
// Convert single arg to FuncArgs
|
||||
let func_args = FuncArgs {
|
||||
args: vec![args],
|
||||
kwargs: Default::default(),
|
||||
};
|
||||
call_typing_args_kwargs("_generic_class_getitem", cls, func_args, vm)
|
||||
}
|
||||
|
||||
#[pyclassmethod(magic)]
|
||||
fn init_subclass(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
call_typing_args_kwargs("_generic_init_subclass", cls, args, vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -223,6 +223,7 @@ declare_const_name! {
|
||||
__sizeof__,
|
||||
__truediv__,
|
||||
__trunc__,
|
||||
__typing_subst__,
|
||||
__xor__,
|
||||
|
||||
// common names
|
||||
|
||||
Reference in New Issue
Block a user