Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
],
"ignorePaths": [
"**/__pycache__/**",
"target/**",
"Lib/**"
],
// words - list of words to be always considered correct
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -3246,8 +3246,6 @@ def test_classvar_module_level_import(self):
# won't exist on the instance.
self.assertNotIn('not_iv4', c.__dict__)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_text_annotations(self):
from test import dataclass_textanno

Expand Down
35 changes: 0 additions & 35 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1605,8 +1605,6 @@ class D(Generic[Unpack[Ts]]): pass
self.assertIs(D[T].__origin__, D)
self.assertIs(D[Unpack[Ts]].__origin__, D)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_get_type_hints_on_unpack_args(self):
Ts = TypeVarTuple('Ts')

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

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_variadic_args_annotations_are_correct(self):
Ts = TypeVarTuple('Ts')

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

@unittest.skip("TODO: RUSTPYTHON")
def test_type_subst_error(self):
Callable = self.Callable
P = ParamSpec('P')
Expand Down Expand Up @@ -3859,8 +3854,6 @@ def barfoo(x: AT): ...
def barfoo2(x: CT): ...
self.assertIs(get_type_hints(barfoo2, globals(), locals())['x'], CT)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_generic_pep585_forward_ref(self):
# See https://bugs.python.org/issue41370

Expand Down Expand Up @@ -5189,8 +5182,6 @@ def cmp(o1, o2):
self.assertIsNot(r1, r2)
self.assertRaises(RecursionError, cmp, r1, r2)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_union_forward_recursion(self):
ValueList = List['Value']
Value = Union[str, ValueList]
Expand Down Expand Up @@ -5239,8 +5230,6 @@ def foo(a: 'Callable[..., T]'):
self.assertEqual(get_type_hints(foo, globals(), locals()),
{'a': Callable[..., T]})

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_special_forms_forward(self):

class C:
Expand Down Expand Up @@ -5323,8 +5312,6 @@ def foo(self, x: int): ...

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

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

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_no_type_check_forward_ref_as_string(self):
class C:
foo: typing.ClassVar[int] = 7
Expand Down Expand Up @@ -5465,8 +5450,6 @@ def test_default_globals(self):
hints = get_type_hints(ns['C'].foo)
self.assertEqual(hints, {'a': ns['C'], 'return': ns['D']})

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_final_forward_ref(self):
self.assertEqual(gth(Loop, globals())['attr'], Final[Loop])
self.assertNotEqual(gth(Loop, globals())['attr'], Final[int])
Expand Down Expand Up @@ -5832,8 +5815,6 @@ def test_get_type_hints_classes(self):
'my_inner_a2': mod_generics_cache.B.A,
'my_outer_a': mod_generics_cache.A})

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

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_get_type_hints_ClassVar(self):
self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__),
{'var': typing.ClassVar[ann_module2.CV]})
Expand Down Expand Up @@ -6006,8 +5985,6 @@ def annotated_with_none_default(x: Annotated[int, 'data'] = None): ...
{'x': Annotated[int, 'data']},
)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_get_type_hints_classes_str_annotations(self):
class Foo:
y = str
Expand All @@ -6023,8 +6000,6 @@ class BadModule:
self.assertNotIn('bad', sys.modules)
self.assertEqual(get_type_hints(BadModule), {})

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

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_forward_ref_and_final(self):
# https://bugs.python.org/issue45166
hints = get_type_hints(ann_module5)
Expand Down Expand Up @@ -8274,8 +8247,6 @@ class C:
A.x = 5
self.assertEqual(C.x, 5)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_special_form_containment(self):
class C:
classvar: Annotated[ClassVar[int], "a decoration"] = 4
Expand All @@ -8284,8 +8255,6 @@ class C:
self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int])
self.assertEqual(get_type_hints(C, globals())['const'], Final[int])

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

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_stringized_usage(self):
class A:
a: "TypeAlias"
Expand Down Expand Up @@ -8652,8 +8619,6 @@ def test_args_kwargs(self):
self.assertEqual(repr(P.kwargs), "P.kwargs")


# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_stringized(self):
P = ParamSpec('P')
class C(Generic[P]):
Expand Down
15 changes: 14 additions & 1 deletion compiler/codegen/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2901,7 +2901,20 @@ impl Compiler<'_> {
} else {
let was_in_annotation = self.in_annotation;
self.in_annotation = true;
let result = self.compile_expression(annotation);

// Special handling for starred annotations (*Ts -> Unpack[Ts])
let result = match annotation {
Expr::Starred(ExprStarred { value, .. }) => {
// Following CPython's approach:
// *args: *Ts (where Ts is a TypeVarTuple).
// Do [annotation_value] = [*Ts].
self.compile_expression(value)?;
emit!(self, Instruction::UnpackSequence { size: 1 });
Ok(())
}
_ => self.compile_expression(annotation),
};

self.in_annotation = was_in_annotation;
result?;
}
Expand Down
42 changes: 42 additions & 0 deletions vm/src/builtins/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,48 @@ impl PyType {
.and_then(|doc| get_text_signature_from_internal_doc(&self.name(), doc))
.map(|signature| signature.to_string())
}

#[pygetset]
fn __type_params__(&self, vm: &VirtualMachine) -> PyTupleRef {
let attrs = self.attributes.read();
let key = identifier!(vm, __type_params__);
if let Some(params) = attrs.get(&key) {
if let Ok(tuple) = params.clone().downcast::<PyTuple>() {
return tuple;
}
}
// Return empty tuple if not found or not a tuple
vm.ctx.empty_tuple.clone()
}

#[pygetset(setter)]
fn set___type_params__(
&self,
value: PySetterValue<PyTupleRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
match value {
PySetterValue::Assign(ref val) => {
let key = identifier!(vm, __type_params__);
self.check_set_special_type_attr(val.as_ref(), key, vm)?;
let mut attrs = self.attributes.write();
attrs.insert(key, val.clone().into());
}
PySetterValue::Delete => {
// For delete, we still need to check if the type is immutable
if self.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
return Err(vm.new_type_error(format!(
"cannot delete '__type_params__' attribute of immutable type '{}'",
self.slot_name()
)));
}
let mut attrs = self.attributes.write();
let key = identifier!(vm, __type_params__);
attrs.shift_remove(&key);
}
}
Ok(())
}
}

impl Constructor for PyType {
Expand Down
1 change: 1 addition & 0 deletions vm/src/vm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ declare_const_name! {
__sizeof__,
__truediv__,
__trunc__,
__type_params__,
__typing_subst__,
__typing_is_unpacked_typevartuple__,
__typing_prepare_subst__,
Expand Down
Loading