mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
heaptype __qualname__ (#5848)
This commit is contained in:
4
Lib/test/test_descr.py
vendored
4
Lib/test/test_descr.py
vendored
@@ -4987,8 +4987,6 @@ order (MRO) for bases """
|
||||
self.assertIn("__dict__", Base.__dict__)
|
||||
self.assertNotIn("__dict__", Sub.__dict__)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_bound_method_repr(self):
|
||||
class Foo:
|
||||
def method(self):
|
||||
@@ -5126,6 +5124,8 @@ class DictProxyTests(unittest.TestCase):
|
||||
self.assertEqual(keys, ['__dict__', '__doc__', '__module__',
|
||||
'__weakref__', 'meth'])
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
|
||||
'trace function introduces __local__')
|
||||
def test_iter_values(self):
|
||||
|
||||
4
Lib/test/test_typing.py
vendored
4
Lib/test/test_typing.py
vendored
@@ -2960,8 +2960,6 @@ class ProtocolTests(BaseTestCase):
|
||||
self.assertNotIsInstance(Capybara('a'), HasX)
|
||||
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_everything_implements_empty_protocol(self):
|
||||
@runtime_checkable
|
||||
class Empty(Protocol):
|
||||
@@ -9238,8 +9236,6 @@ SpecialAttrsT = typing.TypeVar('SpecialAttrsT', int, float, complex)
|
||||
|
||||
|
||||
class SpecialAttrsTests(BaseTestCase):
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_special_attrs(self):
|
||||
cls_to_check = {
|
||||
# ABC classes
|
||||
|
||||
@@ -616,6 +616,20 @@ impl Py<PyDict> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop_item<K: DictKey + ?Sized>(
|
||||
&self,
|
||||
key: &K,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
if self.exact_dict(vm) {
|
||||
self.entries.remove_if_exists(vm, key)
|
||||
} else {
|
||||
let value = self.as_object().get_item(key, vm)?;
|
||||
self.as_object().del_item(key, vm)?;
|
||||
Ok(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_chain<K: DictKey + ?Sized>(
|
||||
&self,
|
||||
other: &Self,
|
||||
|
||||
@@ -58,8 +58,10 @@ unsafe impl crate::object::Traverse for PyType {
|
||||
}
|
||||
}
|
||||
|
||||
// PyHeapTypeObject in CPython
|
||||
pub struct HeapTypeExt {
|
||||
pub name: PyRwLock<PyStrRef>,
|
||||
pub qualname: PyRwLock<PyStrRef>,
|
||||
pub slots: Option<PyTupleTyped<PyStrRef>>,
|
||||
pub sequence_methods: PySequenceMethods,
|
||||
pub mapping_methods: PyMappingMethods,
|
||||
@@ -143,6 +145,16 @@ impl PyPayload for PyType {
|
||||
}
|
||||
}
|
||||
|
||||
fn downcast_qualname(value: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
|
||||
match value.downcast::<PyStr>() {
|
||||
Ok(value) => Ok(value),
|
||||
Err(value) => Err(vm.new_type_error(format!(
|
||||
"can only assign string to __qualname__, not '{}'",
|
||||
value.class().name()
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
impl PyType {
|
||||
pub fn new_simple_heap(
|
||||
name: &str,
|
||||
@@ -171,7 +183,8 @@ impl PyType {
|
||||
|
||||
let name = ctx.new_str(name);
|
||||
let heaptype_ext = HeapTypeExt {
|
||||
name: PyRwLock::new(name),
|
||||
name: PyRwLock::new(name.clone()),
|
||||
qualname: PyRwLock::new(name),
|
||||
slots: None,
|
||||
sequence_methods: PySequenceMethods::default(),
|
||||
mapping_methods: PyMappingMethods::default(),
|
||||
@@ -577,19 +590,12 @@ impl PyType {
|
||||
|
||||
#[pygetset]
|
||||
pub fn __qualname__(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.attributes
|
||||
.read()
|
||||
.get(identifier!(vm, __qualname__))
|
||||
.cloned()
|
||||
// We need to exclude this method from going into recursion:
|
||||
.and_then(|found| {
|
||||
if found.fast_isinstance(vm.ctx.types.getset_type) {
|
||||
None
|
||||
} else {
|
||||
Some(found)
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| vm.ctx.new_str(self.name().deref()).into())
|
||||
if let Some(ref heap_type) = self.heaptype_ext {
|
||||
heap_type.qualname.read().clone().into()
|
||||
} else {
|
||||
// For static types, return the name
|
||||
vm.ctx.new_str(self.name().deref()).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[pygetset(setter)]
|
||||
@@ -607,16 +613,14 @@ impl PyType {
|
||||
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);
|
||||
|
||||
let str_value = downcast_qualname(value, vm)?;
|
||||
|
||||
let heap_type = self
|
||||
.heaptype_ext
|
||||
.as_ref()
|
||||
.expect("HEAPTYPE should have heaptype_ext");
|
||||
*heap_type.qualname.write() = str_value;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -856,6 +860,14 @@ impl Constructor for PyType {
|
||||
(metatype, base.to_owned(), bases)
|
||||
};
|
||||
|
||||
let qualname = dict
|
||||
.pop_item(identifier!(vm, __qualname__).as_object(), vm)?
|
||||
.map(|obj| downcast_qualname(obj, vm))
|
||||
.transpose()?
|
||||
.unwrap_or_else(|| {
|
||||
// If __qualname__ is not provided, we can use the name as default
|
||||
name.clone()
|
||||
});
|
||||
let mut attributes = dict.to_attributes(vm);
|
||||
|
||||
if let Some(f) = attributes.get_mut(identifier!(vm, __init_subclass__)) {
|
||||
@@ -882,10 +894,6 @@ impl Constructor for PyType {
|
||||
}
|
||||
}
|
||||
|
||||
attributes
|
||||
.entry(identifier!(vm, __qualname__))
|
||||
.or_insert_with(|| name.clone().into());
|
||||
|
||||
if attributes.get(identifier!(vm, __eq__)).is_some()
|
||||
&& attributes.get(identifier!(vm, __hash__)).is_none()
|
||||
{
|
||||
@@ -952,6 +960,7 @@ impl Constructor for PyType {
|
||||
};
|
||||
let heaptype_ext = HeapTypeExt {
|
||||
name: PyRwLock::new(name),
|
||||
qualname: PyRwLock::new(qualname),
|
||||
slots: heaptype_slots.to_owned(),
|
||||
sequence_methods: PySequenceMethods::default(),
|
||||
mapping_methods: PyMappingMethods::default(),
|
||||
|
||||
@@ -366,7 +366,7 @@ impl<T: Clone> Dict<T> {
|
||||
where
|
||||
K: DictKey + ?Sized,
|
||||
{
|
||||
if self.delete_if_exists(vm, key)? {
|
||||
if self.remove_if_exists(vm, key)?.is_some() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_key_error(key.to_pyobject(vm)))
|
||||
@@ -377,25 +377,45 @@ impl<T: Clone> Dict<T> {
|
||||
where
|
||||
K: DictKey + ?Sized,
|
||||
{
|
||||
self.delete_if(vm, key, |_| Ok(true))
|
||||
self.remove_if_exists(vm, key).map(|opt| opt.is_some())
|
||||
}
|
||||
|
||||
pub fn delete_if<K, F>(&self, vm: &VirtualMachine, key: &K, pred: F) -> PyResult<bool>
|
||||
where
|
||||
K: DictKey + ?Sized,
|
||||
F: Fn(&T) -> PyResult<bool>,
|
||||
{
|
||||
self.remove_if(vm, key, pred).map(|opt| opt.is_some())
|
||||
}
|
||||
|
||||
pub fn remove_if_exists<K>(&self, vm: &VirtualMachine, key: &K) -> PyResult<Option<T>>
|
||||
where
|
||||
K: DictKey + ?Sized,
|
||||
{
|
||||
self.remove_if(vm, key, |_| Ok(true))
|
||||
}
|
||||
|
||||
/// pred should be VERY CAREFUL about what it does as it is called while
|
||||
/// the dict's internal mutex is held
|
||||
pub(crate) fn delete_if<K, F>(&self, vm: &VirtualMachine, key: &K, pred: F) -> PyResult<bool>
|
||||
pub(crate) fn remove_if<K, F>(
|
||||
&self,
|
||||
vm: &VirtualMachine,
|
||||
key: &K,
|
||||
pred: F,
|
||||
) -> PyResult<Option<T>>
|
||||
where
|
||||
K: DictKey + ?Sized,
|
||||
F: Fn(&T) -> PyResult<bool>,
|
||||
{
|
||||
let hash = key.key_hash(vm)?;
|
||||
let deleted = loop {
|
||||
let removed = loop {
|
||||
let lookup = self.lookup(vm, key, hash, None)?;
|
||||
match self.pop_inner_if(lookup, &pred)? {
|
||||
ControlFlow::Break(entry) => break entry,
|
||||
ControlFlow::Continue(()) => continue,
|
||||
}
|
||||
};
|
||||
Ok(deleted.is_some())
|
||||
Ok(removed.map(|entry| entry.value))
|
||||
}
|
||||
|
||||
pub fn delete_or_insert(&self, vm: &VirtualMachine, key: &PyObject, value: T) -> PyResult<()> {
|
||||
|
||||
Reference in New Issue
Block a user