diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index 71ef8f561..948f22759 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -146,8 +146,6 @@ class PyPicklerTests(AbstractPickleTests, unittest.TestCase): def test_py_methods(self): # TODO: RUSTPYTHON, remove when this passes super().test_py_methods() # TODO: RUSTPYTHON, remove when this passes - # TODO: RUSTPYTHON, AttributeError: attribute '__qualname__' of 'type' objects is not writable - @unittest.expectedFailure def test_recursive_nested_names(self): # TODO: RUSTPYTHON, remove when this passes super().test_recursive_nested_names() # TODO: RUSTPYTHON, remove when this passes @@ -251,8 +249,6 @@ class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests, def test_py_methods(self): # TODO: RUSTPYTHON, remove when this passes super().test_py_methods() # TODO: RUSTPYTHON, remove when this passes - # TODO: RUSTPYTHON, AttributeError: attribute '__qualname__' of 'type' objects is not writable - @unittest.expectedFailure def test_recursive_nested_names(self): # TODO: RUSTPYTHON, remove when this passes super().test_recursive_nested_names() # TODO: RUSTPYTHON, remove when this passes diff --git a/Lib/test/test_pickletools.py b/Lib/test/test_pickletools.py index 44cd485f4..24ec8e0b8 100644 --- a/Lib/test/test_pickletools.py +++ b/Lib/test/test_pickletools.py @@ -68,8 +68,6 @@ class OptimizedPickleTests(AbstractPickleTests, unittest.TestCase): def test_py_methods(self): # TODO: RUSTPYTHON, remove when this passes super().test_py_methods() - # TODO: RUSTPYTHON, AttributeError: attribute '__qualname__' of 'type' objects is not writable - @unittest.expectedFailure def test_recursive_nested_names(self): # TODO: RUSTPYTHON, remove when this passes super().test_recursive_nested_names() diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 7cb4d3243..052598741 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4283,8 +4283,6 @@ class NamedTupleTests(BaseTestCase): with self.assertRaises(TypeError): NamedTuple('Emp', fields=[('name', str), ('id', int)]) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_copy_and_pickle(self): global Emp # pickle wants to reference the class by name Emp = NamedTuple('Emp', [('name', str), ('cool', int)]) diff --git a/Lib/typing.py b/Lib/typing.py index a101b5c65..086d0f3f9 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2283,10 +2283,6 @@ class NamedTupleMeta(type): if key in _prohibited: raise AttributeError("Cannot overwrite NamedTuple attribute " + key) elif key not in _special and key not in nm_tpl._fields: - # TODO: RUSTPYTHON - # Special handling for __qualname__ not to trigger RustPython bug - if key == '__qualname__': - continue setattr(nm_tpl, key, ns[key]) return nm_tpl diff --git a/extra_tests/snippets/builtin_type.py b/extra_tests/snippets/builtin_type.py index d9cd39b3a..68ef65efd 100644 --- a/extra_tests/snippets/builtin_type.py +++ b/extra_tests/snippets/builtin_type.py @@ -99,6 +99,16 @@ assert C.__qualname__ == 'C' assert D.__module__ == 'd' assert D.__qualname__ == 'DD' +A.__qualname__ = 'AA' +B.__qualname__ = 'b' +assert A.__qualname__ == 'AA' +assert B.__qualname__ == 'b' +with assert_raises(TypeError): + del D.__qualname__ +with assert_raises(TypeError): + C.__qualname__ = 123 +with assert_raises(TypeError): + del int.__qualname__ from testutils import assert_raises diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index e4aeb44ce..f1f0300f1 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -405,6 +405,34 @@ impl PyType { .unwrap_or_else(|| vm.ctx.new_str(self.name().deref()).into()) } + #[pyproperty(magic, setter)] + fn set_qualname(&self, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> { + // TODO: we should replace heaptype flag check to immutable flag check + if !self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) { + return Err(vm.new_type_error(format!( + "cannot set '__qualname__' attribute of immutable type '{}'", + self.name() + ))); + }; + let value = value.ok_or_else(|| { + vm.new_type_error(format!( + "cannot delete '__qualname__' attribute of immutable type '{}'", + self.name() + )) + })?; + if !value.class().fast_issubclass(vm.ctx.types.str_type) { + return Err(vm.new_type_error(format!( + "can only assign string to {}.__qualname__, not '{}'", + self.name(), + value.class().name() + ))); + } + self.attributes + .write() + .insert(identifier!(vm, __qualname__), value); + Ok(()) + } + #[pyproperty(magic)] pub fn module(&self, vm: &VirtualMachine) -> PyObjectRef { self.attributes