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: 0 additions & 1 deletion Lib/test/test_weakref.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,6 @@ def check_shared_without_callback(self, makeref):
p2 = makeref(o)
self.assertIs(p1, p2, "callbacks were None, NULL in the C API")

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_callable_proxy(self):
o = Callable()
ref1 = weakref.proxy(o)
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub use traceback::PyTraceback;
pub(crate) mod tuple;
pub use tuple::{PyTuple, PyTupleRef};
pub(crate) mod weakproxy;
pub use weakproxy::PyWeakProxy;
pub use weakproxy::{PyWeakCallableProxy, PyWeakProxy};
pub(crate) mod weakref;
pub use weakref::PyWeak;
pub(crate) mod zip;
Expand Down
33 changes: 30 additions & 3 deletions crates/vm/src/builtins/weakproxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::{
protocol::{PyIter, PyIterReturn, PyMappingMethods, PyNumberMethods, PySequenceMethods},
stdlib::builtins::reversed,
types::{
AsMapping, AsNumber, AsSequence, Comparable, Constructor, GetAttr, Hashable, IterNext,
Iterable, PyComparisonOp, Representable, SetAttr,
AsMapping, AsNumber, AsSequence, Callable, Comparable, Constructor, GetAttr, Hashable,
IterNext, Iterable, PyComparisonOp, Representable, SetAttr,
},
};

Expand Down Expand Up @@ -67,7 +67,11 @@ impl PyWeakProxy {
callback: Option<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<PyRef<PyWeak>> {
let typ = vm.ctx.types.weakproxy_type.to_owned();
let typ = if referent.is_callable() {
vm.ctx.types.weakcallableproxy_type.to_owned()
} else {
vm.ctx.types.weakproxy_type.to_owned()
};
referent.downgrade_with_typ(callback, typ, vm)
}

Expand All @@ -77,6 +81,28 @@ impl PyWeakProxy {
}
}

#[pyclass(
module = false,
name = "weakcallableproxy",
base = PyWeakProxy,
ctx = "weakcallableproxy_type",
unhashable = true
)]
#[derive(Debug)]
#[repr(transparent)]
pub struct PyWeakCallableProxy(PyWeakProxy);

#[pyclass(with(Callable))]
impl PyWeakCallableProxy {}

impl Callable for PyWeakCallableProxy {
type Args = FuncArgs;

fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
zelf.0.try_upgrade(vm)?.call(args, vm)
}
}

#[pyclass(with(
GetAttr,
SetAttr,
Expand Down Expand Up @@ -371,6 +397,7 @@ impl Representable for PyWeakProxy {

pub(crate) fn init(context: &'static Context) {
PyWeakProxy::extend_class(context, context.types.weakproxy_type);
PyWeakCallableProxy::extend_class(context, context.types.weakcallableproxy_type);
}

impl Hashable for PyWeakProxy {
Expand Down
7 changes: 5 additions & 2 deletions crates/vm/src/object/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,10 +771,12 @@ impl WeakRefList {
Some(candidate) => {
let node = unsafe { candidate.as_ref() };
let has_callback = unsafe { (&*node.0.payload.callback.get()).is_some() };
let node_cls = node.class();
// PyWeakref_CheckProxy: the basic-proxy slot is reserved for
// the canonical proxy type; subclasses and callback-less ref
// subclasses must not be mistaken for it.
let is_proxy = node.class().is(crate::builtins::PyWeakProxy::static_type());
let is_proxy = node_cls.is(crate::builtins::PyWeakProxy::static_type())
|| node_cls.is(crate::builtins::PyWeakCallableProxy::static_type());
if has_callback || !is_proxy {
ptr::null_mut()
} else {
Expand Down Expand Up @@ -1602,7 +1604,8 @@ impl PyObject {
None
};
let cls_is_weakref = typ.is(vm.ctx.types.weakref_type);
let cls_is_weakproxy = typ.is(vm.ctx.types.weakproxy_type);
let cls_is_weakproxy =
typ.is(vm.ctx.types.weakproxy_type) || typ.is(vm.ctx.types.weakcallableproxy_type);
let wrl = self.weak_ref_list().ok_or_else(|| {
vm.new_type_error(format!(
"cannot create weak reference to '{}' object",
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/stdlib/_weakref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ mod _weakref {

#[pyattr(name = "CallableProxyType")]
fn callable_proxy_type(vm: &VirtualMachine) -> PyTypeRef {
vm.ctx.types.weakproxy_type.to_owned()
vm.ctx.types.weakcallableproxy_type.to_owned()
}

#[pyfunction]
Expand Down
2 changes: 2 additions & 0 deletions crates/vm/src/types/zoo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub struct TypeZoo {
pub bound_method_type: &'static Py<PyType>,
pub weakref_type: &'static Py<PyType>,
pub weakproxy_type: &'static Py<PyType>,
pub weakcallableproxy_type: &'static Py<PyType>,
pub mappingproxy_type: &'static Py<PyType>,
pub traceback_type: &'static Py<PyType>,
pub object_type: &'static Py<PyType>,
Expand Down Expand Up @@ -198,6 +199,7 @@ impl TypeZoo {
traceback_type: traceback::PyTraceback::init_builtin_type(),
tuple_iterator_type: tuple::PyTupleIterator::init_builtin_type(),
weakproxy_type: weakproxy::PyWeakProxy::init_builtin_type(),
weakcallableproxy_type: weakproxy::PyWeakCallableProxy::init_builtin_type(),
method_descriptor_type: descriptor::PyMethodDescriptor::init_builtin_type(),
none_type: singletons::PyNone::init_builtin_type(),
typing_no_default_type: crate::stdlib::_typing::NoDefault::init_builtin_type(),
Expand Down
Loading