Skip to content

Commit fa7af0e

Browse files
committed
type.__type_params__
1 parent e25c285 commit fa7af0e

File tree

5 files changed

+57
-38
lines changed

5 files changed

+57
-38
lines changed

Lib/test/test_dataclasses.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3246,8 +3246,6 @@ def test_classvar_module_level_import(self):
32463246
# won't exist on the instance.
32473247
self.assertNotIn('not_iv4', c.__dict__)
32483248

3249-
# TODO: RUSTPYTHON
3250-
@unittest.expectedFailure
32513249
def test_text_annotations(self):
32523250
from test import dataclass_textanno
32533251

Lib/test/test_typing.py

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,8 +1605,6 @@ class D(Generic[Unpack[Ts]]): pass
16051605
self.assertIs(D[T].__origin__, D)
16061606
self.assertIs(D[Unpack[Ts]].__origin__, D)
16071607

1608-
# TODO: RUSTPYTHON
1609-
@unittest.expectedFailure
16101608
def test_get_type_hints_on_unpack_args(self):
16111609
Ts = TypeVarTuple('Ts')
16121610

@@ -1809,8 +1807,6 @@ class F(Generic[Unpack[Ts], T1, T2]): pass
18091807
F[int, str, float]
18101808
F[int, str, float, bool]
18111809

1812-
# TODO: RUSTPYTHON
1813-
@unittest.expectedFailure
18141810
def test_variadic_args_annotations_are_correct(self):
18151811
Ts = TypeVarTuple('Ts')
18161812

@@ -2494,7 +2490,6 @@ def test_var_substitution(self):
24942490
self.assertEqual(C5[int, str, float],
24952491
Callable[[typing.List[int], tuple[str, int], float], int])
24962492

2497-
@unittest.skip("TODO: RUSTPYTHON")
24982493
def test_type_subst_error(self):
24992494
Callable = self.Callable
25002495
P = ParamSpec('P')
@@ -3859,8 +3854,6 @@ def barfoo(x: AT): ...
38593854
def barfoo2(x: CT): ...
38603855
self.assertIs(get_type_hints(barfoo2, globals(), locals())['x'], CT)
38613856

3862-
# TODO: RUSTPYTHON
3863-
@unittest.expectedFailure
38643857
def test_generic_pep585_forward_ref(self):
38653858
# See https://bugs.python.org/issue41370
38663859

@@ -5189,8 +5182,6 @@ def cmp(o1, o2):
51895182
self.assertIsNot(r1, r2)
51905183
self.assertRaises(RecursionError, cmp, r1, r2)
51915184

5192-
# TODO: RUSTPYTHON
5193-
@unittest.expectedFailure
51945185
def test_union_forward_recursion(self):
51955186
ValueList = List['Value']
51965187
Value = Union[str, ValueList]
@@ -5239,8 +5230,6 @@ def foo(a: 'Callable[..., T]'):
52395230
self.assertEqual(get_type_hints(foo, globals(), locals()),
52405231
{'a': Callable[..., T]})
52415232

5242-
# TODO: RUSTPYTHON
5243-
@unittest.expectedFailure
52445233
def test_special_forms_forward(self):
52455234

52465235
class C:
@@ -5323,8 +5312,6 @@ def foo(self, x: int): ...
53235312

53245313
self.assertEqual(get_type_hints(Child.foo), {'x': int})
53255314

5326-
# TODO: RUSTPYTHON
5327-
@unittest.expectedFailure
53285315
def test_no_type_check_nested_types(self):
53295316
# See https://bugs.python.org/issue46571
53305317
class Other:
@@ -5409,8 +5396,6 @@ def test_no_type_check_TypeError(self):
54095396
# `TypeError: can't set attributes of built-in/extension type 'dict'`
54105397
no_type_check(dict)
54115398

5412-
# TODO: RUSTPYTHON
5413-
@unittest.expectedFailure
54145399
def test_no_type_check_forward_ref_as_string(self):
54155400
class C:
54165401
foo: typing.ClassVar[int] = 7
@@ -5465,8 +5450,6 @@ def test_default_globals(self):
54655450
hints = get_type_hints(ns['C'].foo)
54665451
self.assertEqual(hints, {'a': ns['C'], 'return': ns['D']})
54675452

5468-
# TODO: RUSTPYTHON
5469-
@unittest.expectedFailure
54705453
def test_final_forward_ref(self):
54715454
self.assertEqual(gth(Loop, globals())['attr'], Final[Loop])
54725455
self.assertNotEqual(gth(Loop, globals())['attr'], Final[int])
@@ -5832,8 +5815,6 @@ def test_get_type_hints_classes(self):
58325815
'my_inner_a2': mod_generics_cache.B.A,
58335816
'my_outer_a': mod_generics_cache.A})
58345817

5835-
# TODO: RUSTPYTHON
5836-
@unittest.expectedFailure
58375818
def test_get_type_hints_classes_no_implicit_optional(self):
58385819
class WithNoneDefault:
58395820
field: int = None # most type-checkers won't be happy with it
@@ -5878,8 +5859,6 @@ class B: ...
58785859
b.__annotations__ = {'x': 'A'}
58795860
self.assertEqual(gth(b, locals()), {'x': A})
58805861

5881-
# TODO: RUSTPYTHON
5882-
@unittest.expectedFailure
58835862
def test_get_type_hints_ClassVar(self):
58845863
self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__),
58855864
{'var': typing.ClassVar[ann_module2.CV]})
@@ -6006,8 +5985,6 @@ def annotated_with_none_default(x: Annotated[int, 'data'] = None): ...
60065985
{'x': Annotated[int, 'data']},
60075986
)
60085987

6009-
# TODO: RUSTPYTHON
6010-
@unittest.expectedFailure
60115988
def test_get_type_hints_classes_str_annotations(self):
60125989
class Foo:
60135990
y = str
@@ -6023,8 +6000,6 @@ class BadModule:
60236000
self.assertNotIn('bad', sys.modules)
60246001
self.assertEqual(get_type_hints(BadModule), {})
60256002

6026-
# TODO: RUSTPYTHON
6027-
@unittest.expectedFailure
60286003
def test_get_type_hints_annotated_bad_module(self):
60296004
# See https://bugs.python.org/issue44468
60306005
class BadBase:
@@ -6035,8 +6010,6 @@ class BadType(BadBase):
60356010
self.assertNotIn('bad', sys.modules)
60366011
self.assertEqual(get_type_hints(BadType), {'foo': tuple, 'bar': list})
60376012

6038-
# TODO: RUSTPYTHON
6039-
@unittest.expectedFailure
60406013
def test_forward_ref_and_final(self):
60416014
# https://bugs.python.org/issue45166
60426015
hints = get_type_hints(ann_module5)
@@ -8274,8 +8247,6 @@ class C:
82748247
A.x = 5
82758248
self.assertEqual(C.x, 5)
82768249

8277-
# TODO: RUSTPYTHON
8278-
@unittest.expectedFailure
82798250
def test_special_form_containment(self):
82808251
class C:
82818252
classvar: Annotated[ClassVar[int], "a decoration"] = 4
@@ -8284,8 +8255,6 @@ class C:
82848255
self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int])
82858256
self.assertEqual(get_type_hints(C, globals())['const'], Final[int])
82868257

8287-
# TODO: RUSTPYTHON
8288-
@unittest.expectedFailure
82898258
def test_special_forms_nesting(self):
82908259
# These are uncommon types and are to ensure runtime
82918260
# is lax on validation. See gh-89547 for more context.
@@ -8563,8 +8532,6 @@ def test_no_isinstance(self):
85638532
with self.assertRaises(TypeError):
85648533
isinstance(42, TypeAlias)
85658534

8566-
# TODO: RUSTPYTHON
8567-
@unittest.expectedFailure
85688535
def test_stringized_usage(self):
85698536
class A:
85708537
a: "TypeAlias"
@@ -8652,8 +8619,6 @@ def test_args_kwargs(self):
86528619
self.assertEqual(repr(P.kwargs), "P.kwargs")
86538620

86548621

8655-
# TODO: RUSTPYTHON
8656-
@unittest.expectedFailure
86578622
def test_stringized(self):
86588623
P = ParamSpec('P')
86598624
class C(Generic[P]):

compiler/codegen/src/compile.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2901,7 +2901,20 @@ impl Compiler<'_> {
29012901
} else {
29022902
let was_in_annotation = self.in_annotation;
29032903
self.in_annotation = true;
2904-
let result = self.compile_expression(annotation);
2904+
2905+
// Special handling for starred annotations (*Ts -> Unpack[Ts])
2906+
let result = match annotation {
2907+
Expr::Starred(ExprStarred { value, .. }) => {
2908+
// Following CPython's approach:
2909+
// *args: *Ts (where Ts is a TypeVarTuple).
2910+
// Do [annotation_value] = [*Ts].
2911+
self.compile_expression(value)?;
2912+
emit!(self, Instruction::UnpackSequence { size: 1 });
2913+
Ok(())
2914+
}
2915+
_ => self.compile_expression(annotation),
2916+
};
2917+
29052918
self.in_annotation = was_in_annotation;
29062919
result?;
29072920
}

vm/src/builtins/type.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,48 @@ impl PyType {
849849
.and_then(|doc| get_text_signature_from_internal_doc(&self.name(), doc))
850850
.map(|signature| signature.to_string())
851851
}
852+
853+
#[pygetset]
854+
fn __type_params__(&self, vm: &VirtualMachine) -> PyTupleRef {
855+
let attrs = self.attributes.read();
856+
let key = identifier!(vm, __type_params__);
857+
if let Some(params) = attrs.get(&key) {
858+
if let Ok(tuple) = params.clone().downcast::<PyTuple>() {
859+
return tuple;
860+
}
861+
}
862+
// Return empty tuple if not found or not a tuple
863+
vm.ctx.empty_tuple.clone()
864+
}
865+
866+
#[pygetset(setter)]
867+
fn set___type_params__(
868+
&self,
869+
value: PySetterValue<PyTupleRef>,
870+
vm: &VirtualMachine,
871+
) -> PyResult<()> {
872+
match value {
873+
PySetterValue::Assign(ref val) => {
874+
let key = identifier!(vm, __type_params__);
875+
self.check_set_special_type_attr(val.as_ref(), key, vm)?;
876+
let mut attrs = self.attributes.write();
877+
attrs.insert(key, val.clone().into());
878+
}
879+
PySetterValue::Delete => {
880+
// For delete, we still need to check if the type is immutable
881+
if self.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
882+
return Err(vm.new_type_error(format!(
883+
"cannot delete '__type_params__' attribute of immutable type '{}'",
884+
self.slot_name()
885+
)));
886+
}
887+
let mut attrs = self.attributes.write();
888+
let key = identifier!(vm, __type_params__);
889+
attrs.shift_remove(&key);
890+
}
891+
}
892+
Ok(())
893+
}
852894
}
853895

854896
impl Constructor for PyType {

vm/src/vm/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ declare_const_name! {
223223
__sizeof__,
224224
__truediv__,
225225
__trunc__,
226+
__type_params__,
226227
__typing_subst__,
227228
__typing_is_unpacked_typevartuple__,
228229
__typing_prepare_subst__,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy