1use crate::err::PyResult;
2use crate::ffi_ptr_ext::FfiPtrExt;
3use crate::py_result_ext::PyResultExt;
4use crate::type_object::PyTypeCheck;
5use crate::types::any::PyAny;
6use crate::{ffi, Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt};
7
8use super::PyWeakrefMethods;
9
10#[repr(transparent)]
15pub struct PyWeakrefProxy(PyAny);
16
17pyobject_native_type_named!(PyWeakrefProxy);
18
19impl PyTypeCheck for PyWeakrefProxy {
24 const NAME: &'static str = "weakref.ProxyTypes";
25
26 fn type_check(object: &Bound<'_, PyAny>) -> bool {
27 unsafe { ffi::PyWeakref_CheckProxy(object.as_ptr()) > 0 }
28 }
29}
30
31impl PyWeakrefProxy {
33 #[cfg_attr(
39 not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
40 doc = "```rust,ignore"
41 )]
42 #[cfg_attr(
43 all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
44 doc = "```rust"
45 )]
46 #[inline]
73 pub fn new<'py>(object: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyWeakrefProxy>> {
74 unsafe {
75 Bound::from_owned_ptr_or_err(
76 object.py(),
77 ffi::PyWeakref_NewProxy(object.as_ptr(), ffi::Py_None()),
78 )
79 .downcast_into_unchecked()
80 }
81 }
82
83 #[deprecated(since = "0.23.0", note = "renamed to `PyWeakrefProxy::new`")]
85 #[inline]
86 pub fn new_bound<'py>(object: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyWeakrefProxy>> {
87 Self::new(object)
88 }
89
90 #[cfg_attr(
96 not(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9))))),
97 doc = "```rust,ignore"
98 )]
99 #[cfg_attr(
100 all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))),
101 doc = "```rust"
102 )]
103 #[inline]
146 pub fn new_with<'py, C>(
147 object: &Bound<'py, PyAny>,
148 callback: C,
149 ) -> PyResult<Bound<'py, PyWeakrefProxy>>
150 where
151 C: IntoPyObject<'py>,
152 {
153 fn inner<'py>(
154 object: &Bound<'py, PyAny>,
155 callback: Borrowed<'_, 'py, PyAny>,
156 ) -> PyResult<Bound<'py, PyWeakrefProxy>> {
157 unsafe {
158 Bound::from_owned_ptr_or_err(
159 object.py(),
160 ffi::PyWeakref_NewProxy(object.as_ptr(), callback.as_ptr()),
161 )
162 .downcast_into_unchecked()
163 }
164 }
165
166 let py = object.py();
167 inner(
168 object,
169 callback
170 .into_pyobject_or_pyerr(py)?
171 .into_any()
172 .as_borrowed(),
173 )
174 }
175
176 #[deprecated(since = "0.23.0", note = "renamed to `PyWeakrefProxy::new_with`")]
178 #[allow(deprecated)]
179 #[inline]
180 pub fn new_bound_with<'py, C>(
181 object: &Bound<'py, PyAny>,
182 callback: C,
183 ) -> PyResult<Bound<'py, PyWeakrefProxy>>
184 where
185 C: crate::ToPyObject,
186 {
187 Self::new_with(object, callback.to_object(object.py()))
188 }
189}
190
191impl<'py> PyWeakrefMethods<'py> for Bound<'py, PyWeakrefProxy> {
192 fn upgrade(&self) -> Option<Bound<'py, PyAny>> {
193 let mut obj: *mut ffi::PyObject = std::ptr::null_mut();
194 match unsafe { ffi::compat::PyWeakref_GetRef(self.as_ptr(), &mut obj) } {
195 std::os::raw::c_int::MIN..=-1 => panic!("The 'weakref.ProxyType' (or `weakref.CallableProxyType`) instance should be valid (non-null and actually a weakref reference)"),
196 0 => None,
197 1..=std::os::raw::c_int::MAX => Some(unsafe { obj.assume_owned_unchecked(self.py()) }),
198 }
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use crate::exceptions::{PyAttributeError, PyReferenceError, PyTypeError};
205 use crate::types::any::{PyAny, PyAnyMethods};
206 use crate::types::weakref::{PyWeakrefMethods, PyWeakrefProxy};
207 use crate::{Bound, PyResult, Python};
208
209 #[cfg(all(Py_3_13, not(Py_LIMITED_API)))]
210 const DEADREF_FIX: Option<&str> = None;
211 #[cfg(all(not(Py_3_13), not(Py_LIMITED_API)))]
212 const DEADREF_FIX: Option<&str> = Some("NoneType");
213
214 #[cfg(not(Py_LIMITED_API))]
215 fn check_repr(
216 reference: &Bound<'_, PyWeakrefProxy>,
217 object: &Bound<'_, PyAny>,
218 class: Option<&str>,
219 ) -> PyResult<()> {
220 let repr = reference.repr()?.to_string();
221
222 #[cfg(Py_3_13)]
223 let (first_part, second_part) = repr.split_once(';').unwrap();
224 #[cfg(not(Py_3_13))]
225 let (first_part, second_part) = repr.split_once(" to ").unwrap();
226
227 {
228 let (msg, addr) = first_part.split_once("0x").unwrap();
229
230 assert_eq!(msg, "<weakproxy at ");
231 assert!(addr
232 .to_lowercase()
233 .contains(format!("{:x?}", reference.as_ptr()).split_at(2).1));
234 }
235
236 if let Some(class) = class.or(DEADREF_FIX) {
237 let (msg, addr) = second_part.split_once("0x").unwrap();
238
239 #[cfg(Py_3_13)]
241 assert!(msg.starts_with(" to '"));
242 assert!(msg.contains(class));
243 assert!(msg.ends_with(" at "));
244
245 assert!(addr
246 .to_lowercase()
247 .contains(format!("{:x?}", object.as_ptr()).split_at(2).1));
248 } else {
249 assert!(second_part.contains("dead"));
250 }
251
252 Ok(())
253 }
254
255 mod proxy {
256 use super::*;
257
258 #[cfg(all(not(Py_LIMITED_API), Py_3_10))]
259 const CLASS_NAME: &str = "'weakref.ProxyType'";
260 #[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))]
261 const CLASS_NAME: &str = "'weakproxy'";
262
263 mod python_class {
264 use super::*;
265 use crate::ffi;
266 use crate::{py_result_ext::PyResultExt, types::PyDict, types::PyType};
267
268 fn get_type(py: Python<'_>) -> PyResult<Bound<'_, PyType>> {
269 let globals = PyDict::new(py);
270 py.run(ffi::c_str!("class A:\n pass\n"), Some(&globals), None)?;
271 py.eval(ffi::c_str!("A"), Some(&globals), None)
272 .downcast_into::<PyType>()
273 }
274
275 #[test]
276 fn test_weakref_proxy_behavior() -> PyResult<()> {
277 Python::with_gil(|py| {
278 let class = get_type(py)?;
279 let object = class.call0()?;
280 let reference = PyWeakrefProxy::new(&object)?;
281
282 assert!(!reference.is(&object));
283 assert!(reference.upgrade().unwrap().is(&object));
284
285 #[cfg(not(Py_LIMITED_API))]
286 assert_eq!(
287 reference.get_type().to_string(),
288 format!("<class {}>", CLASS_NAME)
289 );
290
291 assert_eq!(reference.getattr("__class__")?.to_string(), "<class 'A'>");
292 #[cfg(not(Py_LIMITED_API))]
293 check_repr(&reference, &object, Some("A"))?;
294
295 assert!(reference
296 .getattr("__callback__")
297 .err()
298 .map_or(false, |err| err.is_instance_of::<PyAttributeError>(py)));
299
300 assert!(reference.call0().err().map_or(false, |err| {
301 let result = err.is_instance_of::<PyTypeError>(py);
302 #[cfg(not(Py_LIMITED_API))]
303 let result = result
304 & (err.value(py).to_string()
305 == format!("{} object is not callable", CLASS_NAME));
306 result
307 }));
308
309 drop(object);
310
311 assert!(reference.upgrade().is_none());
312 assert!(reference
313 .getattr("__class__")
314 .err()
315 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
316 #[cfg(not(Py_LIMITED_API))]
317 check_repr(&reference, py.None().bind(py), None)?;
318
319 assert!(reference
320 .getattr("__callback__")
321 .err()
322 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
323
324 assert!(reference.call0().err().map_or(false, |err| {
325 let result = err.is_instance_of::<PyTypeError>(py);
326 #[cfg(not(Py_LIMITED_API))]
327 let result = result
328 & (err.value(py).to_string()
329 == format!("{} object is not callable", CLASS_NAME));
330 result
331 }));
332
333 Ok(())
334 })
335 }
336
337 #[test]
338 fn test_weakref_upgrade_as() -> PyResult<()> {
339 Python::with_gil(|py| {
340 let class = get_type(py)?;
341 let object = class.call0()?;
342 let reference = PyWeakrefProxy::new(&object)?;
343
344 {
345 let obj = reference.upgrade_as::<PyAny>();
347
348 assert!(obj.is_ok());
349 let obj = obj.unwrap();
350
351 assert!(obj.is_some());
352 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
353 && obj.is_exact_instance(&class)));
354 }
355
356 drop(object);
357
358 {
359 let obj = reference.upgrade_as::<PyAny>();
361
362 assert!(obj.is_ok());
363 let obj = obj.unwrap();
364
365 assert!(obj.is_none());
366 }
367
368 Ok(())
369 })
370 }
371
372 #[test]
373 fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
374 Python::with_gil(|py| {
375 let class = get_type(py)?;
376 let object = class.call0()?;
377 let reference = PyWeakrefProxy::new(&object)?;
378
379 {
380 let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
382
383 assert!(obj.is_some());
384 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
385 && obj.is_exact_instance(&class)));
386 }
387
388 drop(object);
389
390 {
391 let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
393
394 assert!(obj.is_none());
395 }
396
397 Ok(())
398 })
399 }
400
401 #[test]
402 fn test_weakref_upgrade() -> PyResult<()> {
403 Python::with_gil(|py| {
404 let class = get_type(py)?;
405 let object = class.call0()?;
406 let reference = PyWeakrefProxy::new(&object)?;
407
408 assert!(reference.upgrade().is_some());
409 assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
410
411 drop(object);
412
413 assert!(reference.upgrade().is_none());
414
415 Ok(())
416 })
417 }
418
419 #[test]
420 fn test_weakref_get_object() -> PyResult<()> {
421 Python::with_gil(|py| {
422 let class = get_type(py)?;
423 let object = class.call0()?;
424 let reference = PyWeakrefProxy::new(&object)?;
425
426 assert!(reference.upgrade().unwrap().is(&object));
427
428 drop(object);
429
430 assert!(reference.upgrade().is_none());
431
432 Ok(())
433 })
434 }
435 }
436
437 #[cfg(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))))]
439 mod pyo3_pyclass {
440 use super::*;
441 use crate::{pyclass, Py};
442
443 #[pyclass(weakref, crate = "crate")]
444 struct WeakrefablePyClass {}
445
446 #[test]
447 fn test_weakref_proxy_behavior() -> PyResult<()> {
448 Python::with_gil(|py| {
449 let object: Bound<'_, WeakrefablePyClass> =
450 Bound::new(py, WeakrefablePyClass {})?;
451 let reference = PyWeakrefProxy::new(&object)?;
452
453 assert!(!reference.is(&object));
454 assert!(reference.upgrade().unwrap().is(&object));
455 #[cfg(not(Py_LIMITED_API))]
456 assert_eq!(
457 reference.get_type().to_string(),
458 format!("<class {}>", CLASS_NAME)
459 );
460
461 assert_eq!(
462 reference.getattr("__class__")?.to_string(),
463 "<class 'builtins.WeakrefablePyClass'>"
464 );
465 #[cfg(not(Py_LIMITED_API))]
466 check_repr(&reference, object.as_any(), Some("WeakrefablePyClass"))?;
467
468 assert!(reference
469 .getattr("__callback__")
470 .err()
471 .map_or(false, |err| err.is_instance_of::<PyAttributeError>(py)));
472
473 assert!(reference.call0().err().map_or(false, |err| {
474 let result = err.is_instance_of::<PyTypeError>(py);
475 #[cfg(not(Py_LIMITED_API))]
476 let result = result
477 & (err.value(py).to_string()
478 == format!("{} object is not callable", CLASS_NAME));
479 result
480 }));
481
482 drop(object);
483
484 assert!(reference.upgrade().is_none());
485 assert!(reference
486 .getattr("__class__")
487 .err()
488 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
489 #[cfg(not(Py_LIMITED_API))]
490 check_repr(&reference, py.None().bind(py), None)?;
491
492 assert!(reference
493 .getattr("__callback__")
494 .err()
495 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
496
497 assert!(reference.call0().err().map_or(false, |err| {
498 let result = err.is_instance_of::<PyTypeError>(py);
499 #[cfg(not(Py_LIMITED_API))]
500 let result = result
501 & (err.value(py).to_string()
502 == format!("{} object is not callable", CLASS_NAME));
503 result
504 }));
505
506 Ok(())
507 })
508 }
509
510 #[test]
511 fn test_weakref_upgrade_as() -> PyResult<()> {
512 Python::with_gil(|py| {
513 let object = Py::new(py, WeakrefablePyClass {})?;
514 let reference = PyWeakrefProxy::new(object.bind(py))?;
515
516 {
517 let obj = reference.upgrade_as::<WeakrefablePyClass>();
518
519 assert!(obj.is_ok());
520 let obj = obj.unwrap();
521
522 assert!(obj.is_some());
523 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
524 }
525
526 drop(object);
527
528 {
529 let obj = reference.upgrade_as::<WeakrefablePyClass>();
530
531 assert!(obj.is_ok());
532 let obj = obj.unwrap();
533
534 assert!(obj.is_none());
535 }
536
537 Ok(())
538 })
539 }
540
541 #[test]
542 fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
543 Python::with_gil(|py| {
544 let object = Py::new(py, WeakrefablePyClass {})?;
545 let reference = PyWeakrefProxy::new(object.bind(py))?;
546
547 {
548 let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
549
550 assert!(obj.is_some());
551 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
552 }
553
554 drop(object);
555
556 {
557 let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
558
559 assert!(obj.is_none());
560 }
561
562 Ok(())
563 })
564 }
565
566 #[test]
567 fn test_weakref_upgrade() -> PyResult<()> {
568 Python::with_gil(|py| {
569 let object = Py::new(py, WeakrefablePyClass {})?;
570 let reference = PyWeakrefProxy::new(object.bind(py))?;
571
572 assert!(reference.upgrade().is_some());
573 assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
574
575 drop(object);
576
577 assert!(reference.upgrade().is_none());
578
579 Ok(())
580 })
581 }
582
583 #[test]
584 #[allow(deprecated)]
585 fn test_weakref_get_object() -> PyResult<()> {
586 Python::with_gil(|py| {
587 let object = Py::new(py, WeakrefablePyClass {})?;
588 let reference = PyWeakrefProxy::new(object.bind(py))?;
589
590 assert!(reference.get_object().is(&object));
591
592 drop(object);
593
594 assert!(reference.get_object().is_none());
595
596 Ok(())
597 })
598 }
599 }
600 }
601
602 mod callable_proxy {
603 use super::*;
604
605 #[cfg(all(not(Py_LIMITED_API), Py_3_10))]
606 const CLASS_NAME: &str = "<class 'weakref.CallableProxyType'>";
607 #[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))]
608 const CLASS_NAME: &str = "<class 'weakcallableproxy'>";
609
610 mod python_class {
611 use super::*;
612 use crate::ffi;
613 use crate::{py_result_ext::PyResultExt, types::PyDict, types::PyType};
614
615 fn get_type(py: Python<'_>) -> PyResult<Bound<'_, PyType>> {
616 let globals = PyDict::new(py);
617 py.run(
618 ffi::c_str!("class A:\n def __call__(self):\n return 'This class is callable!'\n"),
619 Some(&globals),
620 None,
621 )?;
622 py.eval(ffi::c_str!("A"), Some(&globals), None)
623 .downcast_into::<PyType>()
624 }
625
626 #[test]
627 fn test_weakref_proxy_behavior() -> PyResult<()> {
628 Python::with_gil(|py| {
629 let class = get_type(py)?;
630 let object = class.call0()?;
631 let reference = PyWeakrefProxy::new(&object)?;
632
633 assert!(!reference.is(&object));
634 assert!(reference.upgrade().unwrap().is(&object));
635 #[cfg(not(Py_LIMITED_API))]
636 assert_eq!(reference.get_type().to_string(), CLASS_NAME);
637
638 assert_eq!(reference.getattr("__class__")?.to_string(), "<class 'A'>");
639 #[cfg(not(Py_LIMITED_API))]
640 check_repr(&reference, &object, Some("A"))?;
641
642 assert!(reference
643 .getattr("__callback__")
644 .err()
645 .map_or(false, |err| err.is_instance_of::<PyAttributeError>(py)));
646
647 assert_eq!(reference.call0()?.to_string(), "This class is callable!");
648
649 drop(object);
650
651 assert!(reference.upgrade().is_none());
652 assert!(reference
653 .getattr("__class__")
654 .err()
655 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
656 #[cfg(not(Py_LIMITED_API))]
657 check_repr(&reference, py.None().bind(py), None)?;
658
659 assert!(reference
660 .getattr("__callback__")
661 .err()
662 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
663
664 assert!(reference
665 .call0()
666 .err()
667 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)
668 & (err.value(py).to_string()
669 == "weakly-referenced object no longer exists")));
670
671 Ok(())
672 })
673 }
674
675 #[test]
676 fn test_weakref_upgrade_as() -> PyResult<()> {
677 Python::with_gil(|py| {
678 let class = get_type(py)?;
679 let object = class.call0()?;
680 let reference = PyWeakrefProxy::new(&object)?;
681
682 {
683 let obj = reference.upgrade_as::<PyAny>();
685
686 assert!(obj.is_ok());
687 let obj = obj.unwrap();
688
689 assert!(obj.is_some());
690 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
691 && obj.is_exact_instance(&class)));
692 }
693
694 drop(object);
695
696 {
697 let obj = reference.upgrade_as::<PyAny>();
699
700 assert!(obj.is_ok());
701 let obj = obj.unwrap();
702
703 assert!(obj.is_none());
704 }
705
706 Ok(())
707 })
708 }
709
710 #[test]
711 fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
712 Python::with_gil(|py| {
713 let class = get_type(py)?;
714 let object = class.call0()?;
715 let reference = PyWeakrefProxy::new(&object)?;
716
717 {
718 let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
720
721 assert!(obj.is_some());
722 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()
723 && obj.is_exact_instance(&class)));
724 }
725
726 drop(object);
727
728 {
729 let obj = unsafe { reference.upgrade_as_unchecked::<PyAny>() };
731
732 assert!(obj.is_none());
733 }
734
735 Ok(())
736 })
737 }
738
739 #[test]
740 fn test_weakref_upgrade() -> PyResult<()> {
741 Python::with_gil(|py| {
742 let class = get_type(py)?;
743 let object = class.call0()?;
744 let reference = PyWeakrefProxy::new(&object)?;
745
746 assert!(reference.upgrade().is_some());
747 assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
748
749 drop(object);
750
751 assert!(reference.upgrade().is_none());
752
753 Ok(())
754 })
755 }
756
757 #[test]
758 #[allow(deprecated)]
759 fn test_weakref_get_object() -> PyResult<()> {
760 Python::with_gil(|py| {
761 let class = get_type(py)?;
762 let object = class.call0()?;
763 let reference = PyWeakrefProxy::new(&object)?;
764
765 assert!(reference.get_object().is(&object));
766
767 drop(object);
768
769 assert!(reference.get_object().is_none());
770
771 Ok(())
772 })
773 }
774 }
775
776 #[cfg(all(feature = "macros", not(all(Py_LIMITED_API, not(Py_3_9)))))]
778 mod pyo3_pyclass {
779 use super::*;
780 use crate::{pyclass, pymethods, Py};
781
782 #[pyclass(weakref, crate = "crate")]
783 struct WeakrefablePyClass {}
784
785 #[pymethods(crate = "crate")]
786 impl WeakrefablePyClass {
787 fn __call__(&self) -> &str {
788 "This class is callable!"
789 }
790 }
791
792 #[test]
793 fn test_weakref_proxy_behavior() -> PyResult<()> {
794 Python::with_gil(|py| {
795 let object: Bound<'_, WeakrefablePyClass> =
796 Bound::new(py, WeakrefablePyClass {})?;
797 let reference = PyWeakrefProxy::new(&object)?;
798
799 assert!(!reference.is(&object));
800 assert!(reference.upgrade().unwrap().is(&object));
801 #[cfg(not(Py_LIMITED_API))]
802 assert_eq!(reference.get_type().to_string(), CLASS_NAME);
803
804 assert_eq!(
805 reference.getattr("__class__")?.to_string(),
806 "<class 'builtins.WeakrefablePyClass'>"
807 );
808 #[cfg(not(Py_LIMITED_API))]
809 check_repr(&reference, object.as_any(), Some("WeakrefablePyClass"))?;
810
811 assert!(reference
812 .getattr("__callback__")
813 .err()
814 .map_or(false, |err| err.is_instance_of::<PyAttributeError>(py)));
815
816 assert_eq!(reference.call0()?.to_string(), "This class is callable!");
817
818 drop(object);
819
820 assert!(reference.upgrade().is_none());
821 assert!(reference
822 .getattr("__class__")
823 .err()
824 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
825 #[cfg(not(Py_LIMITED_API))]
826 check_repr(&reference, py.None().bind(py), None)?;
827
828 assert!(reference
829 .getattr("__callback__")
830 .err()
831 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)));
832
833 assert!(reference
834 .call0()
835 .err()
836 .map_or(false, |err| err.is_instance_of::<PyReferenceError>(py)
837 & (err.value(py).to_string()
838 == "weakly-referenced object no longer exists")));
839
840 Ok(())
841 })
842 }
843
844 #[test]
845 fn test_weakref_upgrade_as() -> PyResult<()> {
846 Python::with_gil(|py| {
847 let object = Py::new(py, WeakrefablePyClass {})?;
848 let reference = PyWeakrefProxy::new(object.bind(py))?;
849
850 {
851 let obj = reference.upgrade_as::<WeakrefablePyClass>();
852
853 assert!(obj.is_ok());
854 let obj = obj.unwrap();
855
856 assert!(obj.is_some());
857 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
858 }
859
860 drop(object);
861
862 {
863 let obj = reference.upgrade_as::<WeakrefablePyClass>();
864
865 assert!(obj.is_ok());
866 let obj = obj.unwrap();
867
868 assert!(obj.is_none());
869 }
870
871 Ok(())
872 })
873 }
874
875 #[test]
876 fn test_weakref_upgrade_as_unchecked() -> PyResult<()> {
877 Python::with_gil(|py| {
878 let object = Py::new(py, WeakrefablePyClass {})?;
879 let reference = PyWeakrefProxy::new(object.bind(py))?;
880
881 {
882 let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
883
884 assert!(obj.is_some());
885 assert!(obj.map_or(false, |obj| obj.as_ptr() == object.as_ptr()));
886 }
887
888 drop(object);
889
890 {
891 let obj = unsafe { reference.upgrade_as_unchecked::<WeakrefablePyClass>() };
892
893 assert!(obj.is_none());
894 }
895
896 Ok(())
897 })
898 }
899
900 #[test]
901 fn test_weakref_upgrade() -> PyResult<()> {
902 Python::with_gil(|py| {
903 let object = Py::new(py, WeakrefablePyClass {})?;
904 let reference = PyWeakrefProxy::new(object.bind(py))?;
905
906 assert!(reference.upgrade().is_some());
907 assert!(reference.upgrade().map_or(false, |obj| obj.is(&object)));
908
909 drop(object);
910
911 assert!(reference.upgrade().is_none());
912
913 Ok(())
914 })
915 }
916
917 #[test]
918 #[allow(deprecated)]
919 fn test_weakref_get_object() -> PyResult<()> {
920 Python::with_gil(|py| {
921 let object = Py::new(py, WeakrefablePyClass {})?;
922 let reference = PyWeakrefProxy::new(object.bind(py))?;
923
924 assert!(reference.get_object().is(&object));
925
926 drop(object);
927
928 assert!(reference.get_object().is_none());
929
930 Ok(())
931 })
932 }
933 }
934 }
935}