Skip to content

Commit ddc801e

Browse files
authored
Merge pull request RustPython#3854 from oow214/weakproxy_sequence
Add weakproxy Sequence, Mapping
2 parents 97a4d2b + b39549c commit ddc801e

File tree

3 files changed

+67
-18
lines changed

3 files changed

+67
-18
lines changed

Lib/test/test_array.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,8 +1028,6 @@ def test_buffer(self):
10281028
self.assertRaises(BufferError, operator.delitem, a, slice(0, 1))
10291029
self.assertEqual(m.tobytes(), expected)
10301030

1031-
# TODO: RUSTPYTHON
1032-
@unittest.expectedFailure
10331031
def test_weakref(self):
10341032
s = array.array(self.typecode, self.example)
10351033
p = weakref.proxy(s)

Lib/test/test_weakref.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,6 @@ def check_proxy(self, o, proxy):
394394
self.assertFalse(hasattr(o, 'foo'),
395395
"object does not reflect attribute removal via proxy")
396396

397-
# TODO: RUSTPYTHON
398-
@unittest.expectedFailure
399397
def test_proxy_deletion(self):
400398
# Test clearing of SF bug #762891
401399
class Foo:

vm/src/builtins/weakproxy.rs

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use super::{PyStrRef, PyType, PyTypeRef, PyWeak};
22
use crate::{
33
class::PyClassImpl,
44
function::OptionalArg,
5-
types::{Constructor, GetAttr, SetAttr},
5+
protocol::{PyMappingMethods, PySequence, PySequenceMethods},
6+
types::{AsMapping, AsSequence, Constructor, GetAttr, SetAttr},
67
Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
78
};
89

@@ -57,14 +58,44 @@ crate::common::static_cell! {
5758
static WEAK_SUBCLASS: PyTypeRef;
5859
}
5960

60-
#[pyimpl(with(GetAttr, SetAttr, Constructor))]
61+
#[pyimpl(with(GetAttr, SetAttr, Constructor, AsSequence, AsMapping))]
6162
impl PyWeakProxy {
63+
fn try_upgrade(&self, vm: &VirtualMachine) -> PyResult {
64+
self.weak.upgrade().ok_or_else(|| new_reference_error(vm))
65+
}
66+
6267
#[pymethod(magic)]
6368
fn str(&self, vm: &VirtualMachine) -> PyResult<PyStrRef> {
64-
match self.weak.upgrade() {
65-
Some(obj) => obj.str(vm),
66-
None => Err(new_reference_error(vm)),
67-
}
69+
self.try_upgrade(vm)?.str(vm)
70+
}
71+
72+
fn len(&self, vm: &VirtualMachine) -> PyResult<usize> {
73+
self.try_upgrade(vm)?.length(vm)
74+
}
75+
76+
fn contains(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
77+
let obj = self.try_upgrade(vm)?;
78+
PySequence::contains(&obj, &needle, vm)
79+
}
80+
81+
fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
82+
let obj = self.try_upgrade(vm)?;
83+
obj.get_item(&*needle, vm)
84+
}
85+
86+
fn setitem(
87+
&self,
88+
needle: PyObjectRef,
89+
value: PyObjectRef,
90+
vm: &VirtualMachine,
91+
) -> PyResult<()> {
92+
let obj = self.try_upgrade(vm)?;
93+
obj.set_item(&*needle, value, vm)
94+
}
95+
96+
fn delitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
97+
let obj = self.try_upgrade(vm)?;
98+
obj.del_item(&*needle, vm)
6899
}
69100
}
70101

@@ -78,7 +109,7 @@ fn new_reference_error(vm: &VirtualMachine) -> PyRef<super::PyBaseException> {
78109
impl GetAttr for PyWeakProxy {
79110
// TODO: callbacks
80111
fn getattro(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
81-
let obj = zelf.weak.upgrade().ok_or_else(|| new_reference_error(vm))?;
112+
let obj = zelf.try_upgrade(vm)?;
82113
obj.get_attr(name, vm)
83114
}
84115
}
@@ -90,16 +121,38 @@ impl SetAttr for PyWeakProxy {
90121
value: Option<PyObjectRef>,
91122
vm: &VirtualMachine,
92123
) -> PyResult<()> {
93-
match zelf.weak.upgrade() {
94-
Some(obj) => obj.call_set_attr(vm, attr_name, value),
95-
None => Err(vm.new_exception_msg(
96-
vm.ctx.exceptions.reference_error.to_owned(),
97-
"weakly-referenced object no longer exists".to_owned(),
98-
)),
99-
}
124+
let obj = zelf.try_upgrade(vm)?;
125+
obj.call_set_attr(vm, attr_name, value)
100126
}
101127
}
102128

129+
impl AsSequence for PyWeakProxy {
130+
const AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
131+
length: Some(|seq, vm| Self::sequence_downcast(seq).len(vm)),
132+
contains: Some(|seq, needle, vm| {
133+
Self::sequence_downcast(seq).contains(needle.to_owned(), vm)
134+
}),
135+
..PySequenceMethods::NOT_IMPLEMENTED
136+
};
137+
}
138+
139+
impl AsMapping for PyWeakProxy {
140+
const AS_MAPPING: PyMappingMethods = PyMappingMethods {
141+
length: Some(|mapping, vm| Self::mapping_downcast(mapping).len(vm)),
142+
subscript: Some(|mapping, needle, vm| {
143+
Self::mapping_downcast(mapping).getitem(needle.to_owned(), vm)
144+
}),
145+
ass_subscript: Some(|mapping, needle, value, vm| {
146+
let zelf = Self::mapping_downcast(mapping);
147+
if let Some(value) = value {
148+
zelf.setitem(needle.to_owned(), value, vm)
149+
} else {
150+
zelf.delitem(needle.to_owned(), vm)
151+
}
152+
}),
153+
};
154+
}
155+
103156
pub fn init(context: &Context) {
104157
PyWeakProxy::extend_class(context, context.types.weakproxy_type);
105158
}

0 commit comments

Comments
 (0)