mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Make mappingproxy's nb_or slot symmetric for dict | mp (#7723)
* Make mappingproxy's nb_or slot symmetric for dict | mp CPython's mappingproxy_or (Objects/descrobject.c) unwraps a mappingproxy on either side of '|' to its underlying mapping and delegates back to PyNumber_Or. This makes 'dict | mp', 'mp | dict', and 'mp | mp' all produce a plain dict result without dict's own nb_or having to know about mappingproxy. RustPython's 'or' slot in 'AsNumber for PyMappingProxy' only handled the case where the left operand is a mappingproxy. When the slot fired with a=dict, b=mp (because dict.nb_or returned NotImplemented), it returned NotImplemented again — so 'dict | mp' raised TypeError. This propagated to 'UserDict | mappingproxy' (which calls self.data | other). Rewrite the slot to unwrap a mappingproxy on either side (or both) before delegating to vm._or on the underlying mappings. The inplace_or slot is unchanged — '|=' is still rejected. Unmasks test_userdict.UserDictTest.test_mixed_or. * Unmask test_types.MappingProxyTests.test_union The slot fix in this PR also enables this test, which was marked expectedFailure for the same dict|mappingproxy TypeError. Caught as UNEXPECTED SUCCESS in CI.
This commit is contained in:
1 parent
8605702980
commit
e7252b2c4e
3 files changed
+13
-7
No files matched your search
Vendored
-1
@@ -1362,7 +1362,6 @@ class MappingProxyTests(unittest.TestCase):
|
||||
self.assertEqual(view['key1'], 70)
|
||||
self.assertEqual(copy['key1'], 27)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: unsupported operand type(s) for |: 'dict' and 'mappingproxy'
|
||||
def test_union(self):
|
||||
mapping = {'a': 0, 'b': 1, 'c': 2}
|
||||
view = self.mappingproxy(mapping)
|
||||
|
||||
Vendored
-1
@@ -244,7 +244,6 @@ class UserDictTest(mapping_tests.TestHashMappingProtocol):
|
||||
|
||||
test_repr_deep = mapping_tests.TestHashMappingProtocol.test_repr_deep
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: unsupported operand type(s) for |: 'UserDict' and 'mappingproxy'
|
||||
def test_mixed_or(self):
|
||||
for t in UserDict, dict, types.MappingProxyType:
|
||||
with self.subTest(t.__name__):
|
||||
|
||||
@@ -258,11 +258,19 @@ impl AsNumber for PyMappingProxy {
|
||||
fn as_number() -> &'static PyNumberMethods {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
or: Some(|a, b, vm| {
|
||||
if let Some(a) = a.downcast_ref::<PyMappingProxy>() {
|
||||
a.__or__(b.to_pyobject(vm), vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
}
|
||||
// Mirror CPython's mappingproxy_or: when either side is a
|
||||
// mappingproxy, unwrap to its underlying mapping and delegate
|
||||
// to PyNumber_Or so `dict | mp`, `mp | dict`, and `mp | mp`
|
||||
// all produce a `dict` result.
|
||||
let a_obj = match a.downcast_ref::<PyMappingProxy>() {
|
||||
Some(mp) => mp.copy(vm)?,
|
||||
None => a.to_pyobject(vm),
|
||||
};
|
||||
let b_obj = match b.downcast_ref::<PyMappingProxy>() {
|
||||
Some(mp) => mp.copy(vm)?,
|
||||
None => b.to_pyobject(vm),
|
||||
};
|
||||
vm._or(a_obj.as_ref(), b_obj.as_ref())
|
||||
}),
|
||||
inplace_or: Some(|a, b, vm| {
|
||||
if let Some(a) = a.downcast_ref::<PyMappingProxy>() {
|
||||
|
||||
Reference in new issue
Block a user