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