1use crate::call::PyCallArgs;
2use crate::class::basic::CompareOp;
3use crate::conversion::{FromPyObject, IntoPyObject};
4use crate::err::{error_on_minusone, PyErr, PyResult};
5use crate::exceptions::PyTypeError;
6use crate::ffi_ptr_ext::FfiPtrExt;
7#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
8use crate::impl_::pycell::{PyClassObjectBase, PyStaticClassObject};
9use crate::instance::Bound;
10use crate::internal::get_slot::TP_DESCR_GET;
11use crate::py_result_ext::PyResultExt;
12use crate::type_object::{PyTypeCheck, PyTypeInfo};
13use crate::types::PySuper;
14use crate::types::{PyDict, PyIterator, PyList, PyString, PyType};
15use crate::{err, ffi, Borrowed, BoundObject, IntoPyObjectExt, Py};
16#[cfg(RustPython)]
17use crate::{sync::PyOnceLock, types::typeobject::PyTypeMethods};
18use core::cell::UnsafeCell;
19use core::cmp::Ordering;
20use core::ffi::c_int;
21use core::ptr;
22
23#[doc = concat!("[the guide](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/types.html#concrete-python-types)")]
33#[repr(transparent)]
35pub struct PyAny(UnsafeCell<ffi::PyObject>);
36
37#[allow(non_snake_case)]
38fn PyObject_Check(_: *mut ffi::PyObject) -> c_int {
41 1
42}
43
44#[cfg(not(RustPython))]
46pyobject_native_type_info!(
47 PyAny,
48 pyobject_native_static_type_object!(ffi::PyBaseObject_Type),
49 "typing",
50 "Any",
51 Some("builtins"),
52 #checkfunction=PyObject_Check
53);
54
55#[cfg(RustPython)]
56pyobject_native_type_info!(
57 PyAny,
58 |py| {
59 static TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
60 TYPE.import(py, "builtins", "object").unwrap().as_type_ptr()
61 },
62 "typing",
63 "Any",
64 Some("builtins"),
65 #checkfunction=PyObject_Check
66);
67
68pyobject_native_type_sized!(PyAny, ffi::PyObject);
69#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
76impl crate::impl_::pyclass::PyClassBaseType for PyAny {
77 type LayoutAsBase = PyClassObjectBase<ffi::PyObject>;
78 type BaseNativeType = PyAny;
79 type Initializer = crate::impl_::pyclass_init::PyNativeTypeInitializer<Self>;
80 type PyClassMutability = crate::pycell::impl_::ImmutableClass;
81 type Layout<T: crate::impl_::pyclass::PyClassImpl> = PyStaticClassObject<T>;
82}
83
84#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
85pyobject_subclassable_native_type!(PyAny, ffi::PyObject);
86
87#[doc(alias = "PyAny")]
92pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
93 fn is<T: AsRef<Py<PyAny>>>(&self, other: T) -> bool;
98
99 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
122 where
123 N: IntoPyObject<'py, Target = PyString>;
124
125 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
148 where
149 N: IntoPyObject<'py, Target = PyString>;
150
151 fn getattr_opt<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
180 where
181 N: IntoPyObject<'py, Target = PyString>;
182
183 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
206 where
207 N: IntoPyObject<'py, Target = PyString>,
208 V: IntoPyObject<'py>;
209
210 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
217 where
218 N: IntoPyObject<'py, Target = PyString>;
219
220 fn compare<O>(&self, other: O) -> PyResult<Ordering>
267 where
268 O: IntoPyObject<'py>;
269
270 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
304 where
305 O: IntoPyObject<'py>;
306
307 fn neg(&self) -> PyResult<Bound<'py, PyAny>>;
311
312 fn pos(&self) -> PyResult<Bound<'py, PyAny>>;
316
317 fn abs(&self) -> PyResult<Bound<'py, PyAny>>;
321
322 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>>;
324
325 fn lt<O>(&self, other: O) -> PyResult<bool>
329 where
330 O: IntoPyObject<'py>;
331
332 fn le<O>(&self, other: O) -> PyResult<bool>
336 where
337 O: IntoPyObject<'py>;
338
339 fn eq<O>(&self, other: O) -> PyResult<bool>
343 where
344 O: IntoPyObject<'py>;
345
346 fn ne<O>(&self, other: O) -> PyResult<bool>
350 where
351 O: IntoPyObject<'py>;
352
353 fn gt<O>(&self, other: O) -> PyResult<bool>
357 where
358 O: IntoPyObject<'py>;
359
360 fn ge<O>(&self, other: O) -> PyResult<bool>
364 where
365 O: IntoPyObject<'py>;
366
367 fn add<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
369 where
370 O: IntoPyObject<'py>;
371
372 fn sub<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
374 where
375 O: IntoPyObject<'py>;
376
377 fn mul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
379 where
380 O: IntoPyObject<'py>;
381
382 fn matmul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
384 where
385 O: IntoPyObject<'py>;
386
387 fn div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
389 where
390 O: IntoPyObject<'py>;
391
392 fn floor_div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
394 where
395 O: IntoPyObject<'py>;
396
397 fn rem<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
399 where
400 O: IntoPyObject<'py>;
401
402 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
404 where
405 O: IntoPyObject<'py>;
406
407 fn lshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
409 where
410 O: IntoPyObject<'py>;
411
412 fn rshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
414 where
415 O: IntoPyObject<'py>;
416
417 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
420 where
421 O1: IntoPyObject<'py>,
422 O2: IntoPyObject<'py>;
423
424 fn bitand<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
426 where
427 O: IntoPyObject<'py>;
428
429 fn bitor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
431 where
432 O: IntoPyObject<'py>;
433
434 fn bitxor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
436 where
437 O: IntoPyObject<'py>;
438
439 fn is_callable(&self) -> bool;
467
468 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
501 where
502 A: PyCallArgs<'py>;
503
504 fn call0(&self) -> PyResult<Bound<'py, PyAny>>;
525
526 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
556 where
557 A: PyCallArgs<'py>;
558
559 fn call_method<N, A>(
597 &self,
598 name: N,
599 args: A,
600 kwargs: Option<&Bound<'py, PyDict>>,
601 ) -> PyResult<Bound<'py, PyAny>>
602 where
603 N: IntoPyObject<'py, Target = PyString>,
604 A: PyCallArgs<'py>;
605
606 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
640 where
641 N: IntoPyObject<'py, Target = PyString>;
642
643 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
678 where
679 N: IntoPyObject<'py, Target = PyString>,
680 A: PyCallArgs<'py>;
681
682 fn is_truthy(&self) -> PyResult<bool>;
686
687 fn is_none(&self) -> bool;
691
692 fn is_empty(&self) -> PyResult<bool>;
696
697 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
701 where
702 K: IntoPyObject<'py>;
703
704 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
708 where
709 K: IntoPyObject<'py>,
710 V: IntoPyObject<'py>;
711
712 fn del_item<K>(&self, key: K) -> PyResult<()>
716 where
717 K: IntoPyObject<'py>;
718
719 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>>;
744
745 fn get_type(&self) -> Bound<'py, PyType>;
747
748 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject;
750
751 fn extract<'a, T>(&'a self) -> Result<T, T::Error>
755 where
756 T: FromPyObject<'a, 'py>;
757
758 #[deprecated(
760 since = "0.29.0",
761 note = "use `pyo3::ffi::Py_REFCNT(obj.as_ptr())` instead"
762 )]
763 fn get_refcnt(&self) -> isize;
764
765 fn repr(&self) -> PyResult<Bound<'py, PyString>>;
769
770 fn str(&self) -> PyResult<Bound<'py, PyString>>;
774
775 fn hash(&self) -> PyResult<isize>;
779
780 fn len(&self) -> PyResult<usize>;
784
785 fn dir(&self) -> PyResult<Bound<'py, PyList>>;
789
790 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool>;
794
795 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool;
799
800 fn is_instance_of<T: PyTypeCheck>(&self) -> bool;
805
806 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool;
811
812 fn contains<V>(&self, value: V) -> PyResult<bool>
816 where
817 V: IntoPyObject<'py>;
818
819 fn py_super(&self) -> PyResult<Bound<'py, PySuper>>;
823}
824
825macro_rules! implement_binop {
826 ($name:ident, $c_api:ident, $op:expr) => {
827 #[doc = concat!("Computes `self ", $op, " other`.")]
828 fn $name<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
829 where
830 O: IntoPyObject<'py>,
831 {
832 fn inner<'py>(
833 any: &Bound<'py, PyAny>,
834 other: Borrowed<'_, 'py, PyAny>,
835 ) -> PyResult<Bound<'py, PyAny>> {
836 unsafe { ffi::$c_api(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py()) }
837 }
838
839 let py = self.py();
840 inner(
841 self,
842 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
843 )
844 }
845 };
846}
847
848impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
849 #[inline]
850 fn is<T: AsRef<Py<PyAny>>>(&self, other: T) -> bool {
851 ptr::eq(self.as_ptr(), other.as_ref().as_ptr())
852 }
853
854 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
855 where
856 N: IntoPyObject<'py, Target = PyString>,
857 {
858 fn inner<'py>(
859 any: &Bound<'py, PyAny>,
860 attr_name: Borrowed<'_, '_, PyString>,
861 ) -> PyResult<bool> {
862 let result =
863 unsafe { ffi::compat::PyObject_HasAttrWithError(any.as_ptr(), attr_name.as_ptr()) };
864 error_on_minusone(any.py(), result)?;
865 Ok(result > 0)
866 }
867
868 inner(
869 self,
870 attr_name
871 .into_pyobject(self.py())
872 .map_err(Into::into)?
873 .as_borrowed(),
874 )
875 }
876
877 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
878 where
879 N: IntoPyObject<'py, Target = PyString>,
880 {
881 fn inner<'py>(
882 any: &Bound<'py, PyAny>,
883 attr_name: Borrowed<'_, '_, PyString>,
884 ) -> PyResult<Bound<'py, PyAny>> {
885 unsafe {
886 ffi::PyObject_GetAttr(any.as_ptr(), attr_name.as_ptr())
887 .assume_owned_or_err(any.py())
888 }
889 }
890
891 inner(
892 self,
893 attr_name
894 .into_pyobject(self.py())
895 .map_err(Into::into)?
896 .as_borrowed(),
897 )
898 }
899
900 fn getattr_opt<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
901 where
902 N: IntoPyObject<'py, Target = PyString>,
903 {
904 fn inner<'py>(
905 any: &Bound<'py, PyAny>,
906 attr_name: Borrowed<'_, 'py, PyString>,
907 ) -> PyResult<Option<Bound<'py, PyAny>>> {
908 let mut resp_ptr: *mut ffi::PyObject = core::ptr::null_mut();
909 match unsafe {
910 ffi::compat::PyObject_GetOptionalAttr(
911 any.as_ptr(),
912 attr_name.as_ptr(),
913 &mut resp_ptr,
914 )
915 } {
916 1 => Ok(Some(unsafe { Bound::from_owned_ptr(any.py(), resp_ptr) })),
918 0 => Ok(None),
920 _ => Err(PyErr::fetch(any.py())),
922 }
923 }
924
925 let py = self.py();
926 inner(self, attr_name.into_pyobject_or_pyerr(py)?.as_borrowed())
927 }
928
929 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
930 where
931 N: IntoPyObject<'py, Target = PyString>,
932 V: IntoPyObject<'py>,
933 {
934 fn inner(
935 any: &Bound<'_, PyAny>,
936 attr_name: Borrowed<'_, '_, PyString>,
937 value: Borrowed<'_, '_, PyAny>,
938 ) -> PyResult<()> {
939 err::error_on_minusone(any.py(), unsafe {
940 ffi::PyObject_SetAttr(any.as_ptr(), attr_name.as_ptr(), value.as_ptr())
941 })
942 }
943
944 let py = self.py();
945 inner(
946 self,
947 attr_name.into_pyobject_or_pyerr(py)?.as_borrowed(),
948 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
949 )
950 }
951
952 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
953 where
954 N: IntoPyObject<'py, Target = PyString>,
955 {
956 fn inner(any: &Bound<'_, PyAny>, attr_name: Borrowed<'_, '_, PyString>) -> PyResult<()> {
957 err::error_on_minusone(any.py(), unsafe {
958 ffi::PyObject_DelAttr(any.as_ptr(), attr_name.as_ptr())
959 })
960 }
961
962 let py = self.py();
963 inner(self, attr_name.into_pyobject_or_pyerr(py)?.as_borrowed())
964 }
965
966 fn compare<O>(&self, other: O) -> PyResult<Ordering>
967 where
968 O: IntoPyObject<'py>,
969 {
970 fn inner(any: &Bound<'_, PyAny>, other: Borrowed<'_, '_, PyAny>) -> PyResult<Ordering> {
971 let other = other.as_ptr();
972 let do_compare = |other, op| unsafe {
975 ffi::PyObject_RichCompare(any.as_ptr(), other, op)
976 .assume_owned_or_err(any.py())
977 .and_then(|obj| obj.is_truthy())
978 };
979 if do_compare(other, ffi::Py_EQ)? {
980 Ok(Ordering::Equal)
981 } else if do_compare(other, ffi::Py_LT)? {
982 Ok(Ordering::Less)
983 } else if do_compare(other, ffi::Py_GT)? {
984 Ok(Ordering::Greater)
985 } else {
986 Err(PyTypeError::new_err(
987 "PyAny::compare(): All comparisons returned false",
988 ))
989 }
990 }
991
992 let py = self.py();
993 inner(
994 self,
995 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
996 )
997 }
998
999 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
1000 where
1001 O: IntoPyObject<'py>,
1002 {
1003 fn inner<'py>(
1004 any: &Bound<'py, PyAny>,
1005 other: Borrowed<'_, 'py, PyAny>,
1006 compare_op: CompareOp,
1007 ) -> PyResult<Bound<'py, PyAny>> {
1008 unsafe {
1009 ffi::PyObject_RichCompare(any.as_ptr(), other.as_ptr(), compare_op as c_int)
1010 .assume_owned_or_err(any.py())
1011 }
1012 }
1013
1014 let py = self.py();
1015 inner(
1016 self,
1017 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1018 compare_op,
1019 )
1020 }
1021
1022 fn neg(&self) -> PyResult<Bound<'py, PyAny>> {
1023 unsafe { ffi::PyNumber_Negative(self.as_ptr()).assume_owned_or_err(self.py()) }
1024 }
1025
1026 fn pos(&self) -> PyResult<Bound<'py, PyAny>> {
1027 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1028 unsafe { ffi::PyNumber_Positive(any.as_ptr()).assume_owned_or_err(any.py()) }
1029 }
1030
1031 inner(self)
1032 }
1033
1034 fn abs(&self) -> PyResult<Bound<'py, PyAny>> {
1035 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1036 unsafe { ffi::PyNumber_Absolute(any.as_ptr()).assume_owned_or_err(any.py()) }
1037 }
1038
1039 inner(self)
1040 }
1041
1042 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>> {
1043 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1044 unsafe { ffi::PyNumber_Invert(any.as_ptr()).assume_owned_or_err(any.py()) }
1045 }
1046
1047 inner(self)
1048 }
1049
1050 fn lt<O>(&self, other: O) -> PyResult<bool>
1051 where
1052 O: IntoPyObject<'py>,
1053 {
1054 self.rich_compare(other, CompareOp::Lt)
1055 .and_then(|any| any.is_truthy())
1056 }
1057
1058 fn le<O>(&self, other: O) -> PyResult<bool>
1059 where
1060 O: IntoPyObject<'py>,
1061 {
1062 self.rich_compare(other, CompareOp::Le)
1063 .and_then(|any| any.is_truthy())
1064 }
1065
1066 fn eq<O>(&self, other: O) -> PyResult<bool>
1067 where
1068 O: IntoPyObject<'py>,
1069 {
1070 self.rich_compare(other, CompareOp::Eq)
1071 .and_then(|any| any.is_truthy())
1072 }
1073
1074 fn ne<O>(&self, other: O) -> PyResult<bool>
1075 where
1076 O: IntoPyObject<'py>,
1077 {
1078 self.rich_compare(other, CompareOp::Ne)
1079 .and_then(|any| any.is_truthy())
1080 }
1081
1082 fn gt<O>(&self, other: O) -> PyResult<bool>
1083 where
1084 O: IntoPyObject<'py>,
1085 {
1086 self.rich_compare(other, CompareOp::Gt)
1087 .and_then(|any| any.is_truthy())
1088 }
1089
1090 fn ge<O>(&self, other: O) -> PyResult<bool>
1091 where
1092 O: IntoPyObject<'py>,
1093 {
1094 self.rich_compare(other, CompareOp::Ge)
1095 .and_then(|any| any.is_truthy())
1096 }
1097
1098 implement_binop!(add, PyNumber_Add, "+");
1099 implement_binop!(sub, PyNumber_Subtract, "-");
1100 implement_binop!(mul, PyNumber_Multiply, "*");
1101 implement_binop!(matmul, PyNumber_MatrixMultiply, "@");
1102 implement_binop!(div, PyNumber_TrueDivide, "/");
1103 implement_binop!(floor_div, PyNumber_FloorDivide, "//");
1104 implement_binop!(rem, PyNumber_Remainder, "%");
1105 implement_binop!(lshift, PyNumber_Lshift, "<<");
1106 implement_binop!(rshift, PyNumber_Rshift, ">>");
1107 implement_binop!(bitand, PyNumber_And, "&");
1108 implement_binop!(bitor, PyNumber_Or, "|");
1109 implement_binop!(bitxor, PyNumber_Xor, "^");
1110
1111 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
1113 where
1114 O: IntoPyObject<'py>,
1115 {
1116 fn inner<'py>(
1117 any: &Bound<'py, PyAny>,
1118 other: Borrowed<'_, 'py, PyAny>,
1119 ) -> PyResult<Bound<'py, PyAny>> {
1120 unsafe {
1121 ffi::PyNumber_Divmod(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py())
1122 }
1123 }
1124
1125 let py = self.py();
1126 inner(
1127 self,
1128 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1129 )
1130 }
1131
1132 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
1135 where
1136 O1: IntoPyObject<'py>,
1137 O2: IntoPyObject<'py>,
1138 {
1139 fn inner<'py>(
1140 any: &Bound<'py, PyAny>,
1141 other: Borrowed<'_, 'py, PyAny>,
1142 modulus: Borrowed<'_, 'py, PyAny>,
1143 ) -> PyResult<Bound<'py, PyAny>> {
1144 unsafe {
1145 ffi::PyNumber_Power(any.as_ptr(), other.as_ptr(), modulus.as_ptr())
1146 .assume_owned_or_err(any.py())
1147 }
1148 }
1149
1150 let py = self.py();
1151 inner(
1152 self,
1153 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1154 modulus.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1155 )
1156 }
1157
1158 fn is_callable(&self) -> bool {
1159 unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 }
1160 }
1161
1162 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
1163 where
1164 A: PyCallArgs<'py>,
1165 {
1166 if let Some(kwargs) = kwargs {
1167 args.call(
1168 self.as_borrowed(),
1169 kwargs.as_borrowed(),
1170 crate::call::private::Token,
1171 )
1172 } else {
1173 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1174 }
1175 }
1176
1177 #[inline]
1178 fn call0(&self) -> PyResult<Bound<'py, PyAny>> {
1179 unsafe { ffi::compat::PyObject_CallNoArgs(self.as_ptr()).assume_owned_or_err(self.py()) }
1180 }
1181
1182 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
1183 where
1184 A: PyCallArgs<'py>,
1185 {
1186 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1187 }
1188
1189 #[inline]
1190 fn call_method<N, A>(
1191 &self,
1192 name: N,
1193 args: A,
1194 kwargs: Option<&Bound<'py, PyDict>>,
1195 ) -> PyResult<Bound<'py, PyAny>>
1196 where
1197 N: IntoPyObject<'py, Target = PyString>,
1198 A: PyCallArgs<'py>,
1199 {
1200 if kwargs.is_none() {
1201 self.call_method1(name, args)
1202 } else {
1203 self.getattr(name)
1204 .and_then(|method| method.call(args, kwargs))
1205 }
1206 }
1207
1208 #[inline]
1209 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
1210 where
1211 N: IntoPyObject<'py, Target = PyString>,
1212 {
1213 let py = self.py();
1214 let name = name.into_pyobject_or_pyerr(py)?.into_bound();
1215 unsafe {
1216 ffi::compat::PyObject_CallMethodNoArgs(self.as_ptr(), name.as_ptr())
1217 .assume_owned_or_err(py)
1218 }
1219 }
1220
1221 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
1222 where
1223 N: IntoPyObject<'py, Target = PyString>,
1224 A: PyCallArgs<'py>,
1225 {
1226 let name = name.into_pyobject_or_pyerr(self.py())?;
1227 args.call_method_positional(
1228 self.as_borrowed(),
1229 name.as_borrowed(),
1230 crate::call::private::Token,
1231 )
1232 }
1233
1234 fn is_truthy(&self) -> PyResult<bool> {
1235 let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
1236 err::error_on_minusone(self.py(), v)?;
1237 Ok(v != 0)
1238 }
1239
1240 #[inline]
1241 fn is_none(&self) -> bool {
1242 unsafe { ptr::eq(ffi::Py_None(), self.as_ptr()) }
1243 }
1244
1245 fn is_empty(&self) -> PyResult<bool> {
1246 self.len().map(|l| l == 0)
1247 }
1248
1249 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
1250 where
1251 K: IntoPyObject<'py>,
1252 {
1253 fn inner<'py>(
1254 any: &Bound<'py, PyAny>,
1255 key: Borrowed<'_, 'py, PyAny>,
1256 ) -> PyResult<Bound<'py, PyAny>> {
1257 unsafe {
1258 ffi::PyObject_GetItem(any.as_ptr(), key.as_ptr()).assume_owned_or_err(any.py())
1259 }
1260 }
1261
1262 let py = self.py();
1263 inner(
1264 self,
1265 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1266 )
1267 }
1268
1269 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
1270 where
1271 K: IntoPyObject<'py>,
1272 V: IntoPyObject<'py>,
1273 {
1274 fn inner(
1275 any: &Bound<'_, PyAny>,
1276 key: Borrowed<'_, '_, PyAny>,
1277 value: Borrowed<'_, '_, PyAny>,
1278 ) -> PyResult<()> {
1279 err::error_on_minusone(any.py(), unsafe {
1280 ffi::PyObject_SetItem(any.as_ptr(), key.as_ptr(), value.as_ptr())
1281 })
1282 }
1283
1284 let py = self.py();
1285 inner(
1286 self,
1287 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1288 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1289 )
1290 }
1291
1292 fn del_item<K>(&self, key: K) -> PyResult<()>
1293 where
1294 K: IntoPyObject<'py>,
1295 {
1296 fn inner(any: &Bound<'_, PyAny>, key: Borrowed<'_, '_, PyAny>) -> PyResult<()> {
1297 err::error_on_minusone(any.py(), unsafe {
1298 ffi::PyObject_DelItem(any.as_ptr(), key.as_ptr())
1299 })
1300 }
1301
1302 let py = self.py();
1303 inner(
1304 self,
1305 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1306 )
1307 }
1308
1309 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>> {
1310 PyIterator::from_object(self)
1311 }
1312
1313 fn get_type(&self) -> Bound<'py, PyType> {
1314 unsafe { PyType::from_borrowed_type_ptr(self.py(), ffi::Py_TYPE(self.as_ptr())) }
1315 }
1316
1317 #[inline]
1318 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject {
1319 unsafe { ffi::Py_TYPE(self.as_ptr()) }
1320 }
1321
1322 fn extract<'a, T>(&'a self) -> Result<T, T::Error>
1323 where
1324 T: FromPyObject<'a, 'py>,
1325 {
1326 FromPyObject::extract(self.as_borrowed())
1327 }
1328
1329 fn get_refcnt(&self) -> isize {
1330 self._get_refcnt()
1331 }
1332
1333 fn repr(&self) -> PyResult<Bound<'py, PyString>> {
1334 unsafe {
1335 ffi::PyObject_Repr(self.as_ptr())
1336 .assume_owned_or_err(self.py())
1337 .cast_into_unchecked()
1338 }
1339 }
1340
1341 fn str(&self) -> PyResult<Bound<'py, PyString>> {
1342 unsafe {
1343 ffi::PyObject_Str(self.as_ptr())
1344 .assume_owned_or_err(self.py())
1345 .cast_into_unchecked()
1346 }
1347 }
1348
1349 fn hash(&self) -> PyResult<isize> {
1350 let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) };
1351 crate::err::error_on_minusone(self.py(), v)?;
1352 Ok(v)
1353 }
1354
1355 fn len(&self) -> PyResult<usize> {
1356 let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
1357 crate::err::error_on_minusone(self.py(), v)?;
1358 Ok(v as usize)
1359 }
1360
1361 fn dir(&self) -> PyResult<Bound<'py, PyList>> {
1362 unsafe {
1363 ffi::PyObject_Dir(self.as_ptr())
1364 .assume_owned_or_err(self.py())
1365 .cast_into_unchecked()
1366 }
1367 }
1368
1369 #[inline]
1370 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool> {
1371 let result = unsafe { ffi::PyObject_IsInstance(self.as_ptr(), ty.as_ptr()) };
1372 err::error_on_minusone(self.py(), result)?;
1373 Ok(result == 1)
1374 }
1375
1376 #[inline]
1377 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool {
1378 self.get_type().is(ty)
1379 }
1380
1381 #[inline]
1382 fn is_instance_of<T: PyTypeCheck>(&self) -> bool {
1383 T::type_check(self)
1384 }
1385
1386 #[inline]
1387 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool {
1388 T::is_exact_type_of(self)
1389 }
1390
1391 fn contains<V>(&self, value: V) -> PyResult<bool>
1392 where
1393 V: IntoPyObject<'py>,
1394 {
1395 fn inner(any: &Bound<'_, PyAny>, value: Borrowed<'_, '_, PyAny>) -> PyResult<bool> {
1396 match unsafe { ffi::PySequence_Contains(any.as_ptr(), value.as_ptr()) } {
1397 0 => Ok(false),
1398 1 => Ok(true),
1399 _ => Err(PyErr::fetch(any.py())),
1400 }
1401 }
1402
1403 let py = self.py();
1404 inner(
1405 self,
1406 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1407 )
1408 }
1409
1410 fn py_super(&self) -> PyResult<Bound<'py, PySuper>> {
1411 PySuper::new(&self.get_type(), self)
1412 }
1413}
1414
1415impl<'py> Bound<'py, PyAny> {
1416 #[allow(dead_code, reason = "currently only used with num-complex + abi3")]
1427 pub(crate) fn lookup_special<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
1428 where
1429 N: IntoPyObject<'py, Target = PyString>,
1430 {
1431 let py = self.py();
1432 let self_type = self.get_type();
1433 let attr = if let Ok(attr) = self_type.getattr(attr_name) {
1434 attr
1435 } else {
1436 return Ok(None);
1437 };
1438
1439 if let Some(descr_get) = attr.get_type().get_slot(TP_DESCR_GET) {
1441 unsafe {
1443 descr_get(attr.as_ptr(), self.as_ptr(), self_type.as_ptr())
1444 .assume_owned_or_err(py)
1445 .map(Some)
1446 }
1447 } else {
1448 Ok(Some(attr))
1449 }
1450 }
1451
1452 #[inline]
1453 pub(crate) fn _get_refcnt(&self) -> isize {
1454 unsafe { ffi::Py_REFCNT(self.as_ptr()) }
1455 }
1456}
1457
1458#[cfg(test)]
1459mod tests {
1460 use crate::platform::prelude::*;
1461 use crate::{
1462 basic::CompareOp,
1463 test_utils::generate_unique_module_name,
1464 types::{IntoPyDict, PyAny, PyAnyMethods, PyBool, PyInt, PyList, PyModule, PyTypeMethods},
1465 Bound, BoundObject, IntoPyObject, PyTypeInfo, Python,
1466 };
1467 use core::fmt::Debug;
1468 use pyo3_ffi::c_str;
1469
1470 #[test]
1471 fn test_lookup_special() {
1472 Python::attach(|py| {
1473 let module = PyModule::from_code(
1474 py,
1475 cr#"
1476class CustomCallable:
1477 def __call__(self):
1478 return 1
1479
1480class SimpleInt:
1481 def __int__(self):
1482 return 1
1483
1484class InheritedInt(SimpleInt): pass
1485
1486class NoInt: pass
1487
1488class NoDescriptorInt:
1489 __int__ = CustomCallable()
1490
1491class InstanceOverrideInt:
1492 def __int__(self):
1493 return 1
1494instance_override = InstanceOverrideInt()
1495instance_override.__int__ = lambda self: 2
1496
1497class ErrorInDescriptorInt:
1498 @property
1499 def __int__(self):
1500 raise ValueError("uh-oh!")
1501
1502class NonHeapNonDescriptorInt:
1503 # A static-typed callable that doesn't implement `__get__`. These are pretty hard to come by.
1504 __int__ = int
1505 "#,
1506 c"test.py",
1507 &generate_unique_module_name("test"),
1508 )
1509 .unwrap();
1510
1511 let int = crate::intern!(py, "__int__");
1512 let eval_int =
1513 |obj: Bound<'_, PyAny>| obj.lookup_special(int)?.unwrap().call0()?.extract::<u32>();
1514
1515 let simple = module.getattr("SimpleInt").unwrap().call0().unwrap();
1516 assert_eq!(eval_int(simple).unwrap(), 1);
1517 let inherited = module.getattr("InheritedInt").unwrap().call0().unwrap();
1518 assert_eq!(eval_int(inherited).unwrap(), 1);
1519 let no_descriptor = module.getattr("NoDescriptorInt").unwrap().call0().unwrap();
1520 assert_eq!(eval_int(no_descriptor).unwrap(), 1);
1521 let missing = module.getattr("NoInt").unwrap().call0().unwrap();
1522 assert!(missing.lookup_special(int).unwrap().is_none());
1523 let instance_override = module.getattr("instance_override").unwrap();
1526 assert_eq!(eval_int(instance_override).unwrap(), 1);
1527 let descriptor_error = module
1528 .getattr("ErrorInDescriptorInt")
1529 .unwrap()
1530 .call0()
1531 .unwrap();
1532 assert!(descriptor_error.lookup_special(int).is_err());
1533 let nonheap_nondescriptor = module
1534 .getattr("NonHeapNonDescriptorInt")
1535 .unwrap()
1536 .call0()
1537 .unwrap();
1538 assert_eq!(eval_int(nonheap_nondescriptor).unwrap(), 0);
1539 })
1540 }
1541
1542 #[test]
1543 fn test_getattr_opt() {
1544 Python::attach(|py| {
1545 let module = PyModule::from_code(
1546 py,
1547 cr#"
1548class Test:
1549 class_str_attribute = "class_string"
1550
1551 @property
1552 def error(self):
1553 raise ValueError("This is an intentional error")
1554 "#,
1555 c"test.py",
1556 &generate_unique_module_name("test"),
1557 )
1558 .unwrap();
1559
1560 let class_test = module.getattr_opt("Test").unwrap().unwrap();
1562
1563 let cls_attr_str = class_test
1565 .getattr_opt("class_str_attribute")
1566 .unwrap()
1567 .unwrap();
1568 assert_eq!(cls_attr_str.extract::<String>().unwrap(), "class_string");
1569
1570 let do_not_exist = class_test.getattr_opt("doNotExist").unwrap();
1572 assert!(do_not_exist.is_none());
1573
1574 let instance = class_test.call0().unwrap();
1576 let error = instance.getattr_opt("error");
1577 assert!(error.is_err());
1578 assert!(error
1579 .unwrap_err()
1580 .to_string()
1581 .contains("This is an intentional error"));
1582 });
1583 }
1584
1585 #[test]
1586 fn test_getattr_opt_attribute_error_subclass() {
1587 Python::attach(|py| {
1588 let module = PyModule::from_code(
1589 py,
1590 cr#"
1591class CustomAttrError(AttributeError):
1592 pass
1593
1594class Obj:
1595 @property
1596 def missing(self):
1597 raise CustomAttrError("not here")
1598 "#,
1599 c"test.py",
1600 &generate_unique_module_name("test"),
1601 )
1602 .unwrap();
1603
1604 let obj = module.getattr("Obj").unwrap().call0().unwrap();
1605
1606 let result = obj.getattr_opt("missing").unwrap();
1608 assert!(result.is_none());
1609 });
1610 }
1611
1612 #[test]
1613 fn test_call_for_non_existing_method() {
1614 Python::attach(|py| {
1615 let a = py.eval(c"42", None, None).unwrap();
1616 a.call_method0("__str__").unwrap(); assert!(a.call_method("nonexistent_method", (1,), None).is_err());
1618 assert!(a.call_method0("nonexistent_method").is_err());
1619 assert!(a.call_method1("nonexistent_method", (1,)).is_err());
1620 });
1621 }
1622
1623 #[test]
1624 fn test_call_with_kwargs() {
1625 Python::attach(|py| {
1626 let list = vec![3, 6, 5, 4, 7].into_pyobject(py).unwrap();
1627 let dict = vec![("reverse", true)].into_py_dict(py).unwrap();
1628 list.call_method("sort", (), Some(&dict)).unwrap();
1629 assert_eq!(list.extract::<Vec<i32>>().unwrap(), vec![7, 6, 5, 4, 3]);
1630 });
1631 }
1632
1633 #[test]
1634 fn test_call_method0() {
1635 Python::attach(|py| {
1636 let module = PyModule::from_code(
1637 py,
1638 cr#"
1639class SimpleClass:
1640 def foo(self):
1641 return 42
1642"#,
1643 c_str!(file!()),
1644 &generate_unique_module_name("test_module"),
1645 )
1646 .expect("module creation failed");
1647
1648 let simple_class = module.getattr("SimpleClass").unwrap().call0().unwrap();
1649 assert_eq!(
1650 simple_class
1651 .call_method0("foo")
1652 .unwrap()
1653 .extract::<u32>()
1654 .unwrap(),
1655 42
1656 );
1657 })
1658 }
1659
1660 #[test]
1661 fn test_type() {
1662 Python::attach(|py| {
1663 let obj = py.eval(c"42", None, None).unwrap();
1664 assert_eq!(obj.get_type().as_type_ptr(), obj.get_type_ptr());
1665 });
1666 }
1667
1668 #[test]
1669 fn test_dir() {
1670 Python::attach(|py| {
1671 let obj = py.eval(c"42", None, None).unwrap();
1672 let dir = py
1673 .eval(c"dir(42)", None, None)
1674 .unwrap()
1675 .cast_into::<PyList>()
1676 .unwrap();
1677 let a = obj
1678 .dir()
1679 .unwrap()
1680 .into_iter()
1681 .map(|x| x.extract::<String>().unwrap());
1682 let b = dir.into_iter().map(|x| x.extract::<String>().unwrap());
1683 assert!(a.eq(b));
1684 });
1685 }
1686
1687 #[test]
1688 fn test_hasattr() {
1689 Python::attach(|py| {
1690 let x = 5i32.into_pyobject(py).unwrap();
1691 assert!(x.is_instance_of::<PyInt>());
1692
1693 assert!(x.hasattr("to_bytes").unwrap());
1694 assert!(!x.hasattr("bbbbbbytes").unwrap());
1695 })
1696 }
1697
1698 #[cfg(feature = "macros")]
1699 #[test]
1700 #[allow(unknown_lints, non_local_definitions)]
1701 fn test_hasattr_error() {
1702 use crate::exceptions::PyValueError;
1703 use crate::prelude::*;
1704
1705 #[pyclass(crate = "crate")]
1706 struct GetattrFail;
1707
1708 #[pymethods(crate = "crate")]
1709 impl GetattrFail {
1710 fn __getattr__(&self, attr: Py<PyAny>) -> PyResult<Py<PyAny>> {
1711 Err(PyValueError::new_err(attr))
1712 }
1713 }
1714
1715 Python::attach(|py| {
1716 let obj = Py::new(py, GetattrFail).unwrap();
1717 let obj = obj.bind(py).as_any();
1718
1719 assert!(obj
1720 .hasattr("foo")
1721 .unwrap_err()
1722 .is_instance_of::<PyValueError>(py));
1723 })
1724 }
1725
1726 #[test]
1727 fn test_nan_eq() {
1728 Python::attach(|py| {
1729 let nan = py.eval(c"float('nan')", None, None).unwrap();
1730 assert!(nan.compare(&nan).is_err());
1731 });
1732 }
1733
1734 #[test]
1735 fn test_any_is_instance_of() {
1736 Python::attach(|py| {
1737 let x = 5i32.into_pyobject(py).unwrap();
1738 assert!(x.is_instance_of::<PyInt>());
1739
1740 let l = vec![&x, &x].into_pyobject(py).unwrap();
1741 assert!(l.is_instance_of::<PyList>());
1742 });
1743 }
1744
1745 #[test]
1746 fn test_any_is_instance() {
1747 Python::attach(|py| {
1748 let l = vec![1i8, 2].into_pyobject(py).unwrap();
1749 assert!(l.is_instance(&py.get_type::<PyList>()).unwrap());
1750 });
1751 }
1752
1753 #[test]
1754 fn test_any_is_exact_instance_of() {
1755 Python::attach(|py| {
1756 let x = 5i32.into_pyobject(py).unwrap();
1757 assert!(x.is_exact_instance_of::<PyInt>());
1758
1759 let t = PyBool::new(py, true);
1760 assert!(t.is_instance_of::<PyInt>());
1761 assert!(!t.is_exact_instance_of::<PyInt>());
1762 assert!(t.is_exact_instance_of::<PyBool>());
1763
1764 let l = vec![&x, &x].into_pyobject(py).unwrap();
1765 assert!(l.is_exact_instance_of::<PyList>());
1766 });
1767 }
1768
1769 #[test]
1770 fn test_any_is_exact_instance() {
1771 Python::attach(|py| {
1772 let t = PyBool::new(py, true);
1773 assert!(t.is_instance(&py.get_type::<PyInt>()).unwrap());
1774 assert!(!t.is_exact_instance(&py.get_type::<PyInt>()));
1775 assert!(t.is_exact_instance(&py.get_type::<PyBool>()));
1776 });
1777 }
1778
1779 #[test]
1780 fn test_any_contains() {
1781 Python::attach(|py| {
1782 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
1783 let ob = v.into_pyobject(py).unwrap();
1784
1785 let bad_needle = 7i32.into_pyobject(py).unwrap();
1786 assert!(!ob.contains(&bad_needle).unwrap());
1787
1788 let good_needle = 8i32.into_pyobject(py).unwrap();
1789 assert!(ob.contains(&good_needle).unwrap());
1790
1791 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
1792 assert!(ob.contains(&type_coerced_needle).unwrap());
1793
1794 let n: u32 = 42;
1795 let bad_haystack = n.into_pyobject(py).unwrap();
1796 let irrelevant_needle = 0i32.into_pyobject(py).unwrap();
1797 assert!(bad_haystack.contains(&irrelevant_needle).is_err());
1798 });
1799 }
1800
1801 fn test_eq_methods_generic<'a, T>(list: &'a [T])
1803 where
1804 T: PartialEq + PartialOrd,
1805 for<'py> &'a T: IntoPyObject<'py>,
1806 for<'py> <&'a T as IntoPyObject<'py>>::Error: Debug,
1807 {
1808 Python::attach(|py| {
1809 for a in list {
1810 for b in list {
1811 let a_py = a.into_pyobject(py).unwrap().into_any().into_bound();
1812 let b_py = b.into_pyobject(py).unwrap().into_any().into_bound();
1813
1814 assert_eq!(
1815 a.lt(b),
1816 a_py.lt(&b_py).unwrap(),
1817 "{} < {} should be {}.",
1818 a_py,
1819 b_py,
1820 a.lt(b)
1821 );
1822 assert_eq!(
1823 a.le(b),
1824 a_py.le(&b_py).unwrap(),
1825 "{} <= {} should be {}.",
1826 a_py,
1827 b_py,
1828 a.le(b)
1829 );
1830 assert_eq!(
1831 a.eq(b),
1832 a_py.eq(&b_py).unwrap(),
1833 "{} == {} should be {}.",
1834 a_py,
1835 b_py,
1836 a.eq(b)
1837 );
1838 assert_eq!(
1839 a.ne(b),
1840 a_py.ne(&b_py).unwrap(),
1841 "{} != {} should be {}.",
1842 a_py,
1843 b_py,
1844 a.ne(b)
1845 );
1846 assert_eq!(
1847 a.gt(b),
1848 a_py.gt(&b_py).unwrap(),
1849 "{} > {} should be {}.",
1850 a_py,
1851 b_py,
1852 a.gt(b)
1853 );
1854 assert_eq!(
1855 a.ge(b),
1856 a_py.ge(&b_py).unwrap(),
1857 "{} >= {} should be {}.",
1858 a_py,
1859 b_py,
1860 a.ge(b)
1861 );
1862 }
1863 }
1864 });
1865 }
1866
1867 #[test]
1868 fn test_eq_methods_integers() {
1869 let ints = [-4, -4, 1, 2, 0, -100, 1_000_000];
1870 test_eq_methods_generic::<i32>(&ints);
1871 }
1872
1873 #[test]
1874 fn test_eq_methods_strings() {
1875 let strings = ["Let's", "test", "some", "eq", "methods"];
1876 test_eq_methods_generic::<&str>(&strings);
1877 }
1878
1879 #[test]
1880 fn test_eq_methods_floats() {
1881 let floats = [
1882 -1.0,
1883 2.5,
1884 0.0,
1885 3.0,
1886 core::f64::consts::PI,
1887 10.0,
1888 10.0 / 3.0,
1889 -1_000_000.0,
1890 ];
1891 test_eq_methods_generic::<f64>(&floats);
1892 }
1893
1894 #[test]
1895 fn test_eq_methods_bools() {
1896 let bools = [true, false];
1897 test_eq_methods_generic::<bool>(&bools);
1898 }
1899
1900 #[test]
1901 fn test_rich_compare_type_error() {
1902 Python::attach(|py| {
1903 let py_int = 1i32.into_pyobject(py).unwrap();
1904 let py_str = "1".into_pyobject(py).unwrap();
1905
1906 assert!(py_int.rich_compare(&py_str, CompareOp::Lt).is_err());
1907 assert!(!py_int
1908 .rich_compare(py_str, CompareOp::Eq)
1909 .unwrap()
1910 .is_truthy()
1911 .unwrap());
1912 })
1913 }
1914
1915 #[test]
1916 fn test_is_callable() {
1917 Python::attach(|py| {
1918 assert!(PyList::type_object(py).is_callable());
1919
1920 let not_callable = 5i32.into_pyobject(py).unwrap();
1921 assert!(!not_callable.is_callable());
1922 });
1923 }
1924
1925 #[test]
1926 fn test_is_empty() {
1927 Python::attach(|py| {
1928 let empty_list = PyList::empty(py).into_any();
1929 assert!(empty_list.is_empty().unwrap());
1930
1931 let list = PyList::new(py, vec![1, 2, 3]).unwrap().into_any();
1932 assert!(!list.is_empty().unwrap());
1933
1934 let not_container = 5i32.into_pyobject(py).unwrap();
1935 assert!(not_container.is_empty().is_err());
1936 });
1937 }
1938
1939 #[cfg(feature = "macros")]
1940 #[test]
1941 #[allow(unknown_lints, non_local_definitions)]
1942 fn test_fallible_dir() {
1943 use crate::exceptions::PyValueError;
1944 use crate::prelude::*;
1945
1946 #[pyclass(crate = "crate")]
1947 struct DirFail;
1948
1949 #[pymethods(crate = "crate")]
1950 impl DirFail {
1951 fn __dir__(&self) -> PyResult<Py<PyAny>> {
1952 Err(PyValueError::new_err("uh-oh!"))
1953 }
1954 }
1955
1956 Python::attach(|py| {
1957 let obj = Bound::new(py, DirFail).unwrap();
1958 assert!(obj.dir().unwrap_err().is_instance_of::<PyValueError>(py));
1959 })
1960 }
1961}