From dff0914dd03106c92ff96b1aef4c3e267e17f5e6 Mon Sep 17 00:00:00 2001 From: SuperJappie08 <36795178+SuperJappie08@users.noreply.github.com> Date: Thu, 15 Feb 2024 18:09:14 +0100 Subject: [PATCH] Make weakref tests independent from macros feature --- src/types/weakref/callableproxy.rs | 447 ++++++++++++++++++++-------- src/types/weakref/proxy.rs | 439 +++++++++++++++++++-------- src/types/weakref/reference.rs | 458 ++++++++++++++++++++--------- 3 files changed, 953 insertions(+), 391 deletions(-) diff --git a/src/types/weakref/callableproxy.rs b/src/types/weakref/callableproxy.rs index 3f9f97bc4e8..ebc96978d81 100644 --- a/src/types/weakref/callableproxy.rs +++ b/src/types/weakref/callableproxy.rs @@ -503,179 +503,368 @@ impl<'py> PyWeakRefMethods<'py> for Bound<'py, PyWeakCallableProxy> { #[cfg(test)] mod tests { use crate::exceptions::{PyAttributeError, PyReferenceError}; - use crate::prelude::{pyclass, pymethods, Py, PyResult, Python}; use crate::types::any::PyAnyMethods; use crate::types::weakref::{PyWeakCallableProxy, PyWeakRefMethods}; - use crate::Bound; + use crate::{Bound, PyResult, Python}; + + mod python_class { + use super::*; + use crate::{py_result_ext::PyResultExt, types::PyType, PyAny}; + + fn get_type(py: Python<'_>) -> PyResult> { + py.run_bound( + "class A:\n def __call__(self):\n return 'This class is callable!'\n", + None, + None, + )?; + py.eval_bound("A", None, None).downcast_into::() + } + + #[test] + fn test_weakref_proxy_behavior() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone())?; + + assert!(!reference.is(&object)); + assert!(reference.get_object_raw().is(&object)); + assert_eq!( + reference.get_type().to_string(), + "" + ); + + assert_eq!( + reference.getattr("__class__")?.to_string(), + "" + ); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + object.as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + + assert_eq!(reference.call0()?.to_string(), "This class is callable!"); + + drop(object); + + assert!(reference.get_object_raw().is_none()); + assert!(reference + .getattr("__class__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + py.None().as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + + assert!(reference.call0().err().map_or(false, |err| err + .is_instance_of::(py) + & (err.value(py).to_string() == "weakly-referenced object no longer exists"))); + + Ok(()) + }) + } + + #[test] + fn test_weakref_upgrade() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone())?; + + { + // This test is a bit weird but ok. + let obj = reference.upgrade::(); + + assert!(obj.is_ok()); + let obj = obj.unwrap(); + + assert!(obj.is_some()); + assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr() + && obj.is_exact_instance(&class))); + } - #[pyclass(weakref, crate = "crate")] - struct WeakrefablePyClass {} + drop(object); - #[pymethods(crate = "crate")] - impl WeakrefablePyClass { - fn __call__(&self) -> &str { - "This class is callable!" + { + // This test is a bit weird but ok. + let obj = reference.upgrade::(); + + assert!(obj.is_ok()); + let obj = obj.unwrap(); + + assert!(obj.is_none()); + } + + Ok(()) + }) } - } - #[test] - fn test_weakref_proxy_behavior() -> PyResult<()> { - Python::with_gil(|py| { - let object = Bound::new(py, WeakrefablePyClass {})?; - let reference = PyWeakCallableProxy::new_bound(py, object.clone())?; + #[test] + fn test_weakref_get_object() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone())?; - assert!(!reference.is(&object)); - assert!(reference.get_object_raw().is(&object)); - assert_eq!( - reference.get_type().to_string(), - "" - ); + assert!(reference.get_object().is_some()); + assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); - assert_eq!( - reference.getattr("__class__")?.to_string(), - "" - ); - assert_eq!( - reference.repr()?.to_string(), - format!( - "", - reference.as_ptr(), - object.as_ptr() - ) - ); + drop(object); - assert!(reference - .getattr("__callback__") - .err() - .map_or(false, |err| err.is_instance_of::(py))); + assert!(reference.get_object().is_none()); - assert_eq!(reference.call0()?.to_string(), "This class is callable!"); + Ok(()) + }) + } - drop(object); + #[test] + fn test_weakref_borrrow_object() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone())?; - assert!(reference.get_object_raw().is_none()); - assert!(reference - .getattr("__class__") - .err() - .map_or(false, |err| err.is_instance_of::(py))); - assert_eq!( - reference.repr()?.to_string(), - format!( - "", - reference.as_ptr(), - py.None().as_ptr() - ) - ); + assert!(reference.borrow_object().is_some()); + assert!(reference + .borrow_object() + .map_or(false, |obj| obj.is(&object))); - assert!(reference - .getattr("__callback__") - .err() - .map_or(false, |err| err.is_instance_of::(py))); + drop(object); - assert!(reference.call0().err().map_or(false, |err| err - .is_instance_of::(py) - & (err.value(py).to_string() == "weakly-referenced object no longer exists"))); + assert!(reference.borrow_object().is_none()); - Ok(()) - }) - } + Ok(()) + }) + } - #[test] - fn test_weakref_upgrade() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; + #[test] + fn test_weakref_get_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone())?; - { - let obj = reference.upgrade::(); + assert!(reference.get_object_raw().is(&object)); - assert!(obj.is_ok()); - let obj = obj.unwrap(); + drop(object); - assert!(obj.is_some()); - assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr())); - } + assert!(reference.get_object_raw().is_none()); - drop(object); + Ok(()) + }) + } - { - let obj = reference.upgrade::(); + #[test] + fn test_weakref_borrow_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone())?; - assert!(obj.is_ok()); - let obj = obj.unwrap(); + assert!(reference.borrow_object_raw().is(&object)); - assert!(obj.is_none()); - } + drop(object); + + assert!(reference.borrow_object_raw().is_none()); - Ok(()) - }) + Ok(()) + }) + } } - #[test] - fn test_weakref_get_object() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; + #[cfg(feature = "macros")] + mod pyo3_pyclass { + use super::*; + use crate::{pyclass, pymethods, Py}; - assert!(reference.get_object().is_some()); - assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); + #[pyclass(weakref, crate = "crate")] + struct WeakrefablePyClass {} - drop(object); + #[pymethods(crate = "crate")] + impl WeakrefablePyClass { + fn __call__(&self) -> &str { + "This class is callable!" + } + } - assert!(reference.get_object().is_none()); + #[test] + fn test_weakref_proxy_behavior() -> PyResult<()> { + Python::with_gil(|py| { + let object = Bound::new(py, WeakrefablePyClass {})?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone())?; + + assert!(!reference.is(&object)); + assert!(reference.get_object_raw().is(&object)); + assert_eq!( + reference.get_type().to_string(), + "" + ); + + assert_eq!( + reference.getattr("__class__")?.to_string(), + "" + ); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + object.as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + + assert_eq!(reference.call0()?.to_string(), "This class is callable!"); + + drop(object); + + assert!(reference.get_object_raw().is_none()); + assert!(reference + .getattr("__class__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + py.None().as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + + assert!(reference.call0().err().map_or(false, |err| err + .is_instance_of::(py) + & (err.value(py).to_string() == "weakly-referenced object no longer exists"))); + + Ok(()) + }) + } - Ok(()) - }) - } + #[test] + fn test_weakref_upgrade() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; - #[test] - fn test_weakref_borrrow_object() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; + { + let obj = reference.upgrade::(); - assert!(reference.borrow_object().is_some()); - assert!(reference - .borrow_object() - .map_or(false, |obj| obj.is(&object))); + assert!(obj.is_ok()); + let obj = obj.unwrap(); - drop(object); + assert!(obj.is_some()); + assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr())); + } - assert!(reference.borrow_object().is_none()); + drop(object); - Ok(()) - }) - } + { + let obj = reference.upgrade::(); - #[test] - fn test_weakref_get_object_raw() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; + assert!(obj.is_ok()); + let obj = obj.unwrap(); - assert!(reference.get_object_raw().is(&object)); + assert!(obj.is_none()); + } - drop(object); + Ok(()) + }) + } - assert!(reference.get_object_raw().is_none()); + #[test] + fn test_weakref_get_object() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; - Ok(()) - }) - } + assert!(reference.get_object().is_some()); + assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); + + drop(object); + + assert!(reference.get_object().is_none()); - #[test] - fn test_weakref_borrow_object_raw() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; + Ok(()) + }) + } + + #[test] + fn test_weakref_borrrow_object() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; - assert!(reference.borrow_object_raw().is(&object)); + assert!(reference.borrow_object().is_some()); + assert!(reference + .borrow_object() + .map_or(false, |obj| obj.is(&object))); - drop(object); + drop(object); - assert!(reference.borrow_object_raw().is_none()); + assert!(reference.borrow_object().is_none()); - Ok(()) - }) + Ok(()) + }) + } + + #[test] + fn test_weakref_get_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; + + assert!(reference.get_object_raw().is(&object)); + + drop(object); + + assert!(reference.get_object_raw().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_borrow_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakCallableProxy::new_bound(py, object.clone_ref(py))?; + + assert!(reference.borrow_object_raw().is(&object)); + + drop(object); + + assert!(reference.borrow_object_raw().is_none()); + + Ok(()) + }) + } } } diff --git a/src/types/weakref/proxy.rs b/src/types/weakref/proxy.rs index e249acb16ce..aa82a62ac3c 100644 --- a/src/types/weakref/proxy.rs +++ b/src/types/weakref/proxy.rs @@ -445,174 +445,361 @@ impl<'py> PyWeakRefMethods<'py> for Bound<'py, PyWeakProxy> { #[cfg(test)] mod tests { use crate::exceptions::{PyAttributeError, PyReferenceError, PyTypeError}; - use crate::prelude::{pyclass, Py, PyResult, Python}; use crate::types::any::PyAnyMethods; use crate::types::weakref::{PyWeakProxy, PyWeakRefMethods}; - use crate::Bound; + use crate::{Bound, PyResult, Python}; - #[pyclass(weakref, crate = "crate")] - struct WeakrefablePyClass {} + mod python_class { + use super::*; + use crate::{py_result_ext::PyResultExt, types::PyType, PyAny}; - #[test] - fn test_weakref_proxy_behavior() -> PyResult<()> { - Python::with_gil(|py| { - let object = Bound::new(py, WeakrefablePyClass {})?; - let reference = PyWeakProxy::new_bound(py, object.clone())?; + fn get_type(py: Python<'_>) -> PyResult> { + py.run_bound("class A:\n pass\n", None, None)?; + py.eval_bound("A", None, None).downcast_into::() + } - assert!(!reference.is(&object)); - assert!(reference.get_object_raw().is(&object)); - assert_eq!( - reference.get_type().to_string(), - "" - ); + #[test] + fn test_weakref_proxy_behavior() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakProxy::new_bound(py, object.clone())?; + + assert!(!reference.is(&object)); + assert!(reference.get_object_raw().is(&object)); + assert_eq!( + reference.get_type().to_string(), + "" + ); + + assert_eq!( + reference.getattr("__class__")?.to_string(), + "" + ); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + object.as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + + assert!(reference.call0().err().map_or(false, |err| err + .is_instance_of::(py) + & (err.value(py).to_string() == "'weakref.ProxyType' object is not callable"))); + + drop(object); + + assert!(reference.get_object_raw().is_none()); + assert!(reference + .getattr("__class__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + py.None().as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + + assert!(reference.call0().err().map_or(false, |err| err + .is_instance_of::(py) + & (err.value(py).to_string() == "'weakref.ProxyType' object is not callable"))); + + Ok(()) + }) + } - assert_eq!( - reference.getattr("__class__")?.to_string(), - "" - ); - assert_eq!( - reference.repr()?.to_string(), - format!( - "", - reference.as_ptr(), - object.as_ptr() - ) - ); + #[test] + fn test_weakref_upgrade() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakProxy::new_bound(py, object.clone())?; - assert!(reference - .getattr("__callback__") - .err() - .map_or(false, |err| err.is_instance_of::(py))); + { + // This test is a bit weird but ok. + let obj = reference.upgrade::(); - assert!(reference.call0().err().map_or(false, |err| err - .is_instance_of::(py) - & (err.value(py).to_string() == "'weakref.ProxyType' object is not callable"))); + assert!(obj.is_ok()); + let obj = obj.unwrap(); - drop(object); + assert!(obj.is_some()); + assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr() + && obj.is_exact_instance(&class))); + } - assert!(reference.get_object_raw().is_none()); - assert!(reference - .getattr("__class__") - .err() - .map_or(false, |err| err.is_instance_of::(py))); - assert_eq!( - reference.repr()?.to_string(), - format!( - "", - reference.as_ptr(), - py.None().as_ptr() - ) - ); + drop(object); - assert!(reference - .getattr("__callback__") - .err() - .map_or(false, |err| err.is_instance_of::(py))); + { + // This test is a bit weird but ok. + let obj = reference.upgrade::(); - assert!(reference.call0().err().map_or(false, |err| err - .is_instance_of::(py) - & (err.value(py).to_string() == "'weakref.ProxyType' object is not callable"))); + assert!(obj.is_ok()); + let obj = obj.unwrap(); - Ok(()) - }) - } + assert!(obj.is_none()); + } + + Ok(()) + }) + } - #[test] - fn test_weakref_upgrade() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + #[test] + fn test_weakref_get_object() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakProxy::new_bound(py, object.clone())?; - { - let obj = reference.upgrade::(); + assert!(reference.get_object().is_some()); + assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); - assert!(obj.is_ok()); - let obj = obj.unwrap(); + drop(object); - assert!(obj.is_some()); - assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr())); - } + assert!(reference.get_object().is_none()); - drop(object); + Ok(()) + }) + } - { - let obj = reference.upgrade::(); + #[test] + fn test_weakref_borrrow_object() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakProxy::new_bound(py, object.clone())?; - assert!(obj.is_ok()); - let obj = obj.unwrap(); + assert!(reference.borrow_object().is_some()); + assert!(reference + .borrow_object() + .map_or(false, |obj| obj.is(&object))); - assert!(obj.is_none()); - } + drop(object); - Ok(()) - }) - } + assert!(reference.borrow_object().is_none()); - #[test] - fn test_weakref_get_object() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + Ok(()) + }) + } - assert!(reference.get_object().is_some()); - assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); + #[test] + fn test_weakref_get_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakProxy::new_bound(py, object.clone())?; - drop(object); + assert!(reference.get_object_raw().is(&object)); - assert!(reference.get_object().is_none()); + drop(object); - Ok(()) - }) - } + assert!(reference.get_object_raw().is_none()); + + Ok(()) + }) + } - #[test] - fn test_weakref_borrrow_object() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + #[test] + fn test_weakref_borrow_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakProxy::new_bound(py, object.clone())?; - assert!(reference.borrow_object().is_some()); - assert!(reference - .borrow_object() - .map_or(false, |obj| obj.is(&object))); + assert!(reference.borrow_object_raw().is(&object)); - drop(object); + drop(object); - assert!(reference.borrow_object().is_none()); + assert!(reference.borrow_object_raw().is_none()); - Ok(()) - }) + Ok(()) + }) + } } - #[test] - fn test_weakref_get_object_raw() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + #[cfg(feature = "macros")] + mod pyo3_pyclass { + use super::*; + use crate::{pyclass, Py}; + + #[pyclass(weakref, crate = "crate")] + struct WeakrefablePyClass {} + + #[test] + fn test_weakref_proxy_behavior() -> PyResult<()> { + Python::with_gil(|py| { + let object = Bound::new(py, WeakrefablePyClass {})?; + let reference = PyWeakProxy::new_bound(py, object.clone())?; + + assert!(!reference.is(&object)); + assert!(reference.get_object_raw().is(&object)); + assert_eq!( + reference.get_type().to_string(), + "" + ); + + assert_eq!( + reference.getattr("__class__")?.to_string(), + "" + ); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + object.as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + + assert!(reference.call0().err().map_or(false, |err| err + .is_instance_of::(py) + & (err.value(py).to_string() == "'weakref.ProxyType' object is not callable"))); + + drop(object); + + assert!(reference.get_object_raw().is_none()); + assert!(reference + .getattr("__class__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + py.None().as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .err() + .map_or(false, |err| err.is_instance_of::(py))); + + assert!(reference.call0().err().map_or(false, |err| err + .is_instance_of::(py) + & (err.value(py).to_string() == "'weakref.ProxyType' object is not callable"))); + + Ok(()) + }) + } + + #[test] + fn test_weakref_upgrade() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; - assert!(reference.get_object_raw().is(&object)); + { + let obj = reference.upgrade::(); - drop(object); + assert!(obj.is_ok()); + let obj = obj.unwrap(); - assert!(reference.get_object_raw().is_none()); + assert!(obj.is_some()); + assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr())); + } - Ok(()) - }) - } + drop(object); - #[test] - fn test_weakref_borrow_object_raw() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + { + let obj = reference.upgrade::(); - assert!(reference.borrow_object_raw().is(&object)); + assert!(obj.is_ok()); + let obj = obj.unwrap(); - drop(object); + assert!(obj.is_none()); + } - assert!(reference.borrow_object_raw().is_none()); + Ok(()) + }) + } - Ok(()) - }) + #[test] + fn test_weakref_get_object() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + + assert!(reference.get_object().is_some()); + assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); + + drop(object); + + assert!(reference.get_object().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_borrrow_object() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + + assert!(reference.borrow_object().is_some()); + assert!(reference + .borrow_object() + .map_or(false, |obj| obj.is(&object))); + + drop(object); + + assert!(reference.borrow_object().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_get_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + + assert!(reference.get_object_raw().is(&object)); + + drop(object); + + assert!(reference.get_object_raw().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_borrow_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakProxy::new_bound(py, object.clone_ref(py))?; + + assert!(reference.borrow_object_raw().is(&object)); + + drop(object); + + assert!(reference.borrow_object_raw().is_none()); + + Ok(()) + }) + } } } diff --git a/src/types/weakref/reference.rs b/src/types/weakref/reference.rs index ecd4dd624bf..8c3bc0a0a23 100644 --- a/src/types/weakref/reference.rs +++ b/src/types/weakref/reference.rs @@ -825,173 +825,359 @@ impl<'py> PyWeakRefMethods<'py> for Bound<'py, PyWeakRef> { #[cfg(test)] mod tests { - use crate::prelude::{pyclass, Py, Python}; use crate::types::any::PyAnyMethods; use crate::types::weakref::{PyWeakRef, PyWeakRefMethods}; - use crate::{Bound, PyResult}; - - #[pyclass(weakref, crate = "crate")] - struct WeakrefablePyClass {} - - #[test] - fn test_weakref_refence_behavior() -> PyResult<()> { - Python::with_gil(|py| { - let object = Bound::new(py, WeakrefablePyClass {})?; - let reference = PyWeakRef::new_bound(py, object.clone())?; - - assert!(!reference.is(&object)); - assert!(reference.get_object_raw().is(&object)); - assert_eq!( - reference.get_type().to_string(), - "" - ); - - assert_eq!( - reference.getattr("__class__")?.to_string(), - "" - ); - assert_eq!( - reference.repr()?.to_string(), - format!( - "", - reference.as_ptr(), - object.as_ptr() - ) - ); - - assert!(reference - .getattr("__callback__") - .map_or(false, |result| result.is_none())); - - assert!(reference.call0()?.is(&object)); - - drop(object); - - assert!(reference.get_object_raw().is_none()); - assert_eq!( - reference.getattr("__class__")?.to_string(), - "" - ); - assert_eq!( - reference.repr()?.to_string(), - format!("", reference.as_ptr()) - ); - - assert!(reference - .getattr("__callback__") - .map_or(false, |result| result.is_none())); - - assert!(reference.call0()?.is_none()); - - Ok(()) - }) - } + use crate::{Bound, PyResult, Python}; - #[test] - fn test_weakref_upgrade() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + mod python_class { + use super::*; + use crate::{py_result_ext::PyResultExt, types::PyType, PyAny}; - { - let obj = reference.upgrade::(); + fn get_type(py: Python<'_>) -> PyResult> { + py.run_bound("class A:\n pass\n", None, None)?; + py.eval_bound("A", None, None).downcast_into::() + } - assert!(obj.is_ok()); - let obj = obj.unwrap(); + #[test] + fn test_weakref_refence_behavior() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakRef::new_bound(py, object.clone())?; - assert!(obj.is_some()); - assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr())); - } + assert!(!reference.is(&object)); + assert!(reference.get_object_raw().is(&object)); + assert_eq!( + reference.get_type().to_string(), + "" + ); - drop(object); + assert_eq!( + reference.getattr("__class__")?.to_string(), + "" + ); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + object.as_ptr() + ) + ); - { - let obj = reference.upgrade::(); + assert!(reference + .getattr("__callback__") + .map_or(false, |result| result.is_none())); - assert!(obj.is_ok()); - let obj = obj.unwrap(); + assert!(reference.call0()?.is(&object)); - assert!(obj.is_none()); - } + drop(object); - Ok(()) - }) - } + assert!(reference.get_object_raw().is_none()); + assert_eq!( + reference.getattr("__class__")?.to_string(), + "" + ); + assert_eq!( + reference.repr()?.to_string(), + format!("", reference.as_ptr()) + ); - #[test] - fn test_weakref_get_object() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + assert!(reference + .getattr("__callback__") + .map_or(false, |result| result.is_none())); - assert!(reference.call0()?.is(&object)); - assert!(reference.get_object().is_some()); - assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); + assert!(reference.call0()?.is_none()); - drop(object); + Ok(()) + }) + } - assert!(reference.call0()?.is_none()); - assert!(reference.get_object().is_none()); + #[test] + fn test_weakref_upgrade() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakRef::new_bound(py, object.clone())?; - Ok(()) - }) - } + { + // This test is a bit weird but ok. + let obj = reference.upgrade::(); - #[test] - fn test_weakref_borrrow_object() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + assert!(obj.is_ok()); + let obj = obj.unwrap(); - assert!(reference.call0()?.is(&object)); - assert!(reference.borrow_object().is_some()); - assert!(reference - .borrow_object() - .map_or(false, |obj| obj.is(&object))); + assert!(obj.is_some()); + assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr() + && obj.is_exact_instance(&class))); + } - drop(object); + drop(object); - assert!(reference.call0()?.is_none()); - assert!(reference.borrow_object().is_none()); + { + // This test is a bit weird but ok. + let obj = reference.upgrade::(); - Ok(()) - }) - } + assert!(obj.is_ok()); + let obj = obj.unwrap(); + + assert!(obj.is_none()); + } + + Ok(()) + }) + } - #[test] - fn test_weakref_get_object_raw() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + #[test] + fn test_weakref_get_object() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakRef::new_bound(py, object.clone())?; - assert!(reference.call0()?.is(&object)); - assert!(reference.get_object_raw().is(&object)); + assert!(reference.call0()?.is(&object)); + assert!(reference.get_object().is_some()); + assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); - drop(object); + drop(object); + + assert!(reference.call0()?.is_none()); + assert!(reference.get_object().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_borrrow_object() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakRef::new_bound(py, object.clone())?; + + assert!(reference.call0()?.is(&object)); + assert!(reference.borrow_object().is_some()); + assert!(reference + .borrow_object() + .map_or(false, |obj| obj.is(&object))); + + drop(object); + + assert!(reference.call0()?.is_none()); + assert!(reference.borrow_object().is_none()); + + Ok(()) + }) + } - assert!(reference.call0()?.is(&reference.get_object_raw())); - assert!(reference.call0()?.is_none()); - assert!(reference.get_object_raw().is_none()); + #[test] + fn test_weakref_get_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakRef::new_bound(py, object.clone())?; - Ok(()) - }) + assert!(reference.call0()?.is(&object)); + assert!(reference.get_object_raw().is(&object)); + + drop(object); + + assert!(reference.call0()?.is(&reference.get_object_raw())); + assert!(reference.call0()?.is_none()); + assert!(reference.get_object_raw().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_borrow_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let class = get_type(py)?; + let object = class.call0()?; + let reference = PyWeakRef::new_bound(py, object.clone())?; + + assert!(reference.call0()?.is(&object)); + assert!(reference.borrow_object_raw().is(&object)); + + drop(object); + + assert!(reference.call0()?.is_none()); + assert!(reference.borrow_object_raw().is_none()); + + Ok(()) + }) + } } - #[test] - fn test_weakref_borrow_object_raw() -> PyResult<()> { - Python::with_gil(|py| { - let object = Py::new(py, WeakrefablePyClass {})?; - let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + #[cfg(feature = "macros")] + mod pyo3_pyclass { + use super::*; + use crate::{pyclass, Py}; + + #[pyclass(weakref, crate = "crate")] + struct WeakrefablePyClass {} + + #[test] + fn test_weakref_refence_behavior() -> PyResult<()> { + Python::with_gil(|py| { + let object = Bound::new(py, WeakrefablePyClass {})?; + let reference = PyWeakRef::new_bound(py, object.clone())?; + + assert!(!reference.is(&object)); + assert!(reference.get_object_raw().is(&object)); + assert_eq!( + reference.get_type().to_string(), + "" + ); + + assert_eq!( + reference.getattr("__class__")?.to_string(), + "" + ); + assert_eq!( + reference.repr()?.to_string(), + format!( + "", + reference.as_ptr(), + object.as_ptr() + ) + ); + + assert!(reference + .getattr("__callback__") + .map_or(false, |result| result.is_none())); + + assert!(reference.call0()?.is(&object)); + + drop(object); - assert!(reference.call0()?.is(&object)); - assert!(reference.borrow_object_raw().is(&object)); + assert!(reference.get_object_raw().is_none()); + assert_eq!( + reference.getattr("__class__")?.to_string(), + "" + ); + assert_eq!( + reference.repr()?.to_string(), + format!("", reference.as_ptr()) + ); - drop(object); + assert!(reference + .getattr("__callback__") + .map_or(false, |result| result.is_none())); - assert!(reference.call0()?.is_none()); - assert!(reference.borrow_object_raw().is_none()); + assert!(reference.call0()?.is_none()); - Ok(()) - }) + Ok(()) + }) + } + + #[test] + fn test_weakref_upgrade() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + + { + let obj = reference.upgrade::(); + + assert!(obj.is_ok()); + let obj = obj.unwrap(); + + assert!(obj.is_some()); + assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr())); + } + + drop(object); + + { + let obj = reference.upgrade::(); + + assert!(obj.is_ok()); + let obj = obj.unwrap(); + + assert!(obj.is_none()); + } + + Ok(()) + }) + } + + #[test] + fn test_weakref_get_object() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + + assert!(reference.call0()?.is(&object)); + assert!(reference.get_object().is_some()); + assert!(reference.get_object().map_or(false, |obj| obj.is(&object))); + + drop(object); + + assert!(reference.call0()?.is_none()); + assert!(reference.get_object().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_borrrow_object() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + + assert!(reference.call0()?.is(&object)); + assert!(reference.borrow_object().is_some()); + assert!(reference + .borrow_object() + .map_or(false, |obj| obj.is(&object))); + + drop(object); + + assert!(reference.call0()?.is_none()); + assert!(reference.borrow_object().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_get_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + + assert!(reference.call0()?.is(&object)); + assert!(reference.get_object_raw().is(&object)); + + drop(object); + + assert!(reference.call0()?.is(&reference.get_object_raw())); + assert!(reference.call0()?.is_none()); + assert!(reference.get_object_raw().is_none()); + + Ok(()) + }) + } + + #[test] + fn test_weakref_borrow_object_raw() -> PyResult<()> { + Python::with_gil(|py| { + let object = Py::new(py, WeakrefablePyClass {})?; + let reference = PyWeakRef::new_bound(py, object.clone_ref(py))?; + + assert!(reference.call0()?.is(&object)); + assert!(reference.borrow_object_raw().is(&object)); + + drop(object); + + assert!(reference.call0()?.is_none()); + assert!(reference.borrow_object_raw().is_none()); + + Ok(()) + }) + } } }