1use crate::call::PyCallArgs;
2use crate::class::basic::CompareOp;
3use crate::conversion::{AsPyPointer, FromPyObjectBound, IntoPyObject};
4use crate::err::{DowncastError, DowncastIntoError, PyErr, PyResult};
5use crate::exceptions::{PyAttributeError, PyTypeError};
6use crate::ffi_ptr_ext::FfiPtrExt;
7use crate::instance::Bound;
8use crate::internal::get_slot::TP_DESCR_GET;
9use crate::internal_tricks::ptr_from_ref;
10use crate::py_result_ext::PyResultExt;
11use crate::type_object::{PyTypeCheck, PyTypeInfo};
12#[cfg(not(any(PyPy, GraalPy)))]
13use crate::types::PySuper;
14use crate::types::{PyDict, PyIterator, PyList, PyString, PyType};
15use crate::{err, ffi, Borrowed, BoundObject, IntoPyObjectExt, Python};
16use std::cell::UnsafeCell;
17use std::cmp::Ordering;
18use std::os::raw::c_int;
19
20#[doc = concat!("[the guide](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/types.html#concrete-python-types)")]
30#[repr(transparent)]
32pub struct PyAny(UnsafeCell<ffi::PyObject>);
33
34#[allow(non_snake_case)]
35fn PyObject_Check(_: *mut ffi::PyObject) -> c_int {
38 1
39}
40
41pyobject_native_type_info!(
42 PyAny,
43 pyobject_native_static_type_object!(ffi::PyBaseObject_Type),
44 Some("builtins"),
45 #checkfunction=PyObject_Check
46);
47
48pyobject_native_type_sized!(PyAny, ffi::PyObject);
49impl crate::impl_::pyclass::PyClassBaseType for PyAny {
51 type LayoutAsBase = crate::impl_::pycell::PyClassObjectBase<ffi::PyObject>;
52 type BaseNativeType = PyAny;
53 type Initializer = crate::impl_::pyclass_init::PyNativeTypeInitializer<Self>;
54 type PyClassMutability = crate::pycell::impl_::ImmutableClass;
55}
56
57#[doc(alias = "PyAny")]
62pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
63 fn is<T: AsPyPointer>(&self, other: &T) -> bool;
68
69 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
92 where
93 N: IntoPyObject<'py, Target = PyString>;
94
95 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
118 where
119 N: IntoPyObject<'py, Target = PyString>;
120
121 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
144 where
145 N: IntoPyObject<'py, Target = PyString>,
146 V: IntoPyObject<'py>;
147
148 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
155 where
156 N: IntoPyObject<'py, Target = PyString>;
157
158 fn compare<O>(&self, other: O) -> PyResult<Ordering>
205 where
206 O: IntoPyObject<'py>;
207
208 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
242 where
243 O: IntoPyObject<'py>;
244
245 fn neg(&self) -> PyResult<Bound<'py, PyAny>>;
249
250 fn pos(&self) -> PyResult<Bound<'py, PyAny>>;
254
255 fn abs(&self) -> PyResult<Bound<'py, PyAny>>;
259
260 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>>;
262
263 fn lt<O>(&self, other: O) -> PyResult<bool>
267 where
268 O: IntoPyObject<'py>;
269
270 fn le<O>(&self, other: O) -> PyResult<bool>
274 where
275 O: IntoPyObject<'py>;
276
277 fn eq<O>(&self, other: O) -> PyResult<bool>
281 where
282 O: IntoPyObject<'py>;
283
284 fn ne<O>(&self, other: O) -> PyResult<bool>
288 where
289 O: IntoPyObject<'py>;
290
291 fn gt<O>(&self, other: O) -> PyResult<bool>
295 where
296 O: IntoPyObject<'py>;
297
298 fn ge<O>(&self, other: O) -> PyResult<bool>
302 where
303 O: IntoPyObject<'py>;
304
305 fn add<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
307 where
308 O: IntoPyObject<'py>;
309
310 fn sub<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
312 where
313 O: IntoPyObject<'py>;
314
315 fn mul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
317 where
318 O: IntoPyObject<'py>;
319
320 fn matmul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
322 where
323 O: IntoPyObject<'py>;
324
325 fn div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
327 where
328 O: IntoPyObject<'py>;
329
330 fn floor_div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
332 where
333 O: IntoPyObject<'py>;
334
335 fn rem<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
337 where
338 O: IntoPyObject<'py>;
339
340 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
342 where
343 O: IntoPyObject<'py>;
344
345 fn lshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
347 where
348 O: IntoPyObject<'py>;
349
350 fn rshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
352 where
353 O: IntoPyObject<'py>;
354
355 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
358 where
359 O1: IntoPyObject<'py>,
360 O2: IntoPyObject<'py>;
361
362 fn bitand<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
364 where
365 O: IntoPyObject<'py>;
366
367 fn bitor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
369 where
370 O: IntoPyObject<'py>;
371
372 fn bitxor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
374 where
375 O: IntoPyObject<'py>;
376
377 fn is_callable(&self) -> bool;
405
406 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
439 where
440 A: PyCallArgs<'py>;
441
442 fn call0(&self) -> PyResult<Bound<'py, PyAny>>;
463
464 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
494 where
495 A: PyCallArgs<'py>;
496
497 fn call_method<N, A>(
535 &self,
536 name: N,
537 args: A,
538 kwargs: Option<&Bound<'py, PyDict>>,
539 ) -> PyResult<Bound<'py, PyAny>>
540 where
541 N: IntoPyObject<'py, Target = PyString>,
542 A: PyCallArgs<'py>;
543
544 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
578 where
579 N: IntoPyObject<'py, Target = PyString>;
580
581 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
616 where
617 N: IntoPyObject<'py, Target = PyString>,
618 A: PyCallArgs<'py>;
619
620 fn is_truthy(&self) -> PyResult<bool>;
624
625 fn is_none(&self) -> bool;
629
630 #[deprecated(since = "0.23.0", note = "use `.is(py.Ellipsis())` instead")]
634 fn is_ellipsis(&self) -> bool;
635
636 fn is_empty(&self) -> PyResult<bool>;
640
641 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
645 where
646 K: IntoPyObject<'py>;
647
648 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
652 where
653 K: IntoPyObject<'py>,
654 V: IntoPyObject<'py>;
655
656 fn del_item<K>(&self, key: K) -> PyResult<()>
660 where
661 K: IntoPyObject<'py>;
662
663 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>>;
688
689 #[deprecated(since = "0.23.0", note = "use `try_iter` instead")]
694 fn iter(&self) -> PyResult<Bound<'py, PyIterator>>;
695
696 fn get_type(&self) -> Bound<'py, PyType>;
698
699 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject;
701
702 fn downcast<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
755 where
756 T: PyTypeCheck;
757
758 fn downcast_into<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
781 where
782 T: PyTypeCheck;
783
784 fn downcast_exact<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
815 where
816 T: PyTypeInfo;
817
818 fn downcast_into_exact<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
820 where
821 T: PyTypeInfo;
822
823 unsafe fn downcast_unchecked<T>(&self) -> &Bound<'py, T>;
829
830 unsafe fn downcast_into_unchecked<T>(self) -> Bound<'py, T>;
836
837 fn extract<'a, T>(&'a self) -> PyResult<T>
842 where
843 T: FromPyObjectBound<'a, 'py>;
844
845 fn get_refcnt(&self) -> isize;
847
848 fn repr(&self) -> PyResult<Bound<'py, PyString>>;
852
853 fn str(&self) -> PyResult<Bound<'py, PyString>>;
857
858 fn hash(&self) -> PyResult<isize>;
862
863 fn len(&self) -> PyResult<usize>;
867
868 fn dir(&self) -> PyResult<Bound<'py, PyList>>;
872
873 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool>;
877
878 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool;
882
883 fn is_instance_of<T: PyTypeInfo>(&self) -> bool;
888
889 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool;
894
895 fn contains<V>(&self, value: V) -> PyResult<bool>
899 where
900 V: IntoPyObject<'py>;
901
902 #[cfg(not(any(PyPy, GraalPy)))]
906 fn py_super(&self) -> PyResult<Bound<'py, PySuper>>;
907}
908
909macro_rules! implement_binop {
910 ($name:ident, $c_api:ident, $op:expr) => {
911 #[doc = concat!("Computes `self ", $op, " other`.")]
912 fn $name<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
913 where
914 O: IntoPyObject<'py>,
915 {
916 fn inner<'py>(
917 any: &Bound<'py, PyAny>,
918 other: Borrowed<'_, 'py, PyAny>,
919 ) -> PyResult<Bound<'py, PyAny>> {
920 unsafe { ffi::$c_api(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py()) }
921 }
922
923 let py = self.py();
924 inner(
925 self,
926 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
927 )
928 }
929 };
930}
931
932impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
933 #[inline]
934 fn is<T: AsPyPointer>(&self, other: &T) -> bool {
935 self.as_ptr() == other.as_ptr()
936 }
937
938 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
939 where
940 N: IntoPyObject<'py, Target = PyString>,
941 {
942 fn inner(py: Python<'_>, getattr_result: PyResult<Bound<'_, PyAny>>) -> PyResult<bool> {
945 match getattr_result {
946 Ok(_) => Ok(true),
947 Err(err) if err.is_instance_of::<PyAttributeError>(py) => Ok(false),
948 Err(e) => Err(e),
949 }
950 }
951
952 inner(self.py(), self.getattr(attr_name))
953 }
954
955 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
956 where
957 N: IntoPyObject<'py, Target = PyString>,
958 {
959 fn inner<'py>(
960 any: &Bound<'py, PyAny>,
961 attr_name: Borrowed<'_, '_, PyString>,
962 ) -> PyResult<Bound<'py, PyAny>> {
963 unsafe {
964 ffi::PyObject_GetAttr(any.as_ptr(), attr_name.as_ptr())
965 .assume_owned_or_err(any.py())
966 }
967 }
968
969 inner(
970 self,
971 attr_name
972 .into_pyobject(self.py())
973 .map_err(Into::into)?
974 .as_borrowed(),
975 )
976 }
977
978 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
979 where
980 N: IntoPyObject<'py, Target = PyString>,
981 V: IntoPyObject<'py>,
982 {
983 fn inner(
984 any: &Bound<'_, PyAny>,
985 attr_name: Borrowed<'_, '_, PyString>,
986 value: Borrowed<'_, '_, PyAny>,
987 ) -> PyResult<()> {
988 err::error_on_minusone(any.py(), unsafe {
989 ffi::PyObject_SetAttr(any.as_ptr(), attr_name.as_ptr(), value.as_ptr())
990 })
991 }
992
993 let py = self.py();
994 inner(
995 self,
996 attr_name.into_pyobject_or_pyerr(py)?.as_borrowed(),
997 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
998 )
999 }
1000
1001 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
1002 where
1003 N: IntoPyObject<'py, Target = PyString>,
1004 {
1005 fn inner(any: &Bound<'_, PyAny>, attr_name: Borrowed<'_, '_, PyString>) -> PyResult<()> {
1006 err::error_on_minusone(any.py(), unsafe {
1007 ffi::PyObject_DelAttr(any.as_ptr(), attr_name.as_ptr())
1008 })
1009 }
1010
1011 let py = self.py();
1012 inner(self, attr_name.into_pyobject_or_pyerr(py)?.as_borrowed())
1013 }
1014
1015 fn compare<O>(&self, other: O) -> PyResult<Ordering>
1016 where
1017 O: IntoPyObject<'py>,
1018 {
1019 fn inner(any: &Bound<'_, PyAny>, other: Borrowed<'_, '_, PyAny>) -> PyResult<Ordering> {
1020 let other = other.as_ptr();
1021 let do_compare = |other, op| unsafe {
1024 ffi::PyObject_RichCompare(any.as_ptr(), other, op)
1025 .assume_owned_or_err(any.py())
1026 .and_then(|obj| obj.is_truthy())
1027 };
1028 if do_compare(other, ffi::Py_EQ)? {
1029 Ok(Ordering::Equal)
1030 } else if do_compare(other, ffi::Py_LT)? {
1031 Ok(Ordering::Less)
1032 } else if do_compare(other, ffi::Py_GT)? {
1033 Ok(Ordering::Greater)
1034 } else {
1035 Err(PyTypeError::new_err(
1036 "PyAny::compare(): All comparisons returned false",
1037 ))
1038 }
1039 }
1040
1041 let py = self.py();
1042 inner(
1043 self,
1044 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1045 )
1046 }
1047
1048 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
1049 where
1050 O: IntoPyObject<'py>,
1051 {
1052 fn inner<'py>(
1053 any: &Bound<'py, PyAny>,
1054 other: Borrowed<'_, 'py, PyAny>,
1055 compare_op: CompareOp,
1056 ) -> PyResult<Bound<'py, PyAny>> {
1057 unsafe {
1058 ffi::PyObject_RichCompare(any.as_ptr(), other.as_ptr(), compare_op as c_int)
1059 .assume_owned_or_err(any.py())
1060 }
1061 }
1062
1063 let py = self.py();
1064 inner(
1065 self,
1066 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1067 compare_op,
1068 )
1069 }
1070
1071 fn neg(&self) -> PyResult<Bound<'py, PyAny>> {
1072 unsafe { ffi::PyNumber_Negative(self.as_ptr()).assume_owned_or_err(self.py()) }
1073 }
1074
1075 fn pos(&self) -> PyResult<Bound<'py, PyAny>> {
1076 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1077 unsafe { ffi::PyNumber_Positive(any.as_ptr()).assume_owned_or_err(any.py()) }
1078 }
1079
1080 inner(self)
1081 }
1082
1083 fn abs(&self) -> PyResult<Bound<'py, PyAny>> {
1084 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1085 unsafe { ffi::PyNumber_Absolute(any.as_ptr()).assume_owned_or_err(any.py()) }
1086 }
1087
1088 inner(self)
1089 }
1090
1091 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>> {
1092 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1093 unsafe { ffi::PyNumber_Invert(any.as_ptr()).assume_owned_or_err(any.py()) }
1094 }
1095
1096 inner(self)
1097 }
1098
1099 fn lt<O>(&self, other: O) -> PyResult<bool>
1100 where
1101 O: IntoPyObject<'py>,
1102 {
1103 self.rich_compare(other, CompareOp::Lt)
1104 .and_then(|any| any.is_truthy())
1105 }
1106
1107 fn le<O>(&self, other: O) -> PyResult<bool>
1108 where
1109 O: IntoPyObject<'py>,
1110 {
1111 self.rich_compare(other, CompareOp::Le)
1112 .and_then(|any| any.is_truthy())
1113 }
1114
1115 fn eq<O>(&self, other: O) -> PyResult<bool>
1116 where
1117 O: IntoPyObject<'py>,
1118 {
1119 self.rich_compare(other, CompareOp::Eq)
1120 .and_then(|any| any.is_truthy())
1121 }
1122
1123 fn ne<O>(&self, other: O) -> PyResult<bool>
1124 where
1125 O: IntoPyObject<'py>,
1126 {
1127 self.rich_compare(other, CompareOp::Ne)
1128 .and_then(|any| any.is_truthy())
1129 }
1130
1131 fn gt<O>(&self, other: O) -> PyResult<bool>
1132 where
1133 O: IntoPyObject<'py>,
1134 {
1135 self.rich_compare(other, CompareOp::Gt)
1136 .and_then(|any| any.is_truthy())
1137 }
1138
1139 fn ge<O>(&self, other: O) -> PyResult<bool>
1140 where
1141 O: IntoPyObject<'py>,
1142 {
1143 self.rich_compare(other, CompareOp::Ge)
1144 .and_then(|any| any.is_truthy())
1145 }
1146
1147 implement_binop!(add, PyNumber_Add, "+");
1148 implement_binop!(sub, PyNumber_Subtract, "-");
1149 implement_binop!(mul, PyNumber_Multiply, "*");
1150 implement_binop!(matmul, PyNumber_MatrixMultiply, "@");
1151 implement_binop!(div, PyNumber_TrueDivide, "/");
1152 implement_binop!(floor_div, PyNumber_FloorDivide, "//");
1153 implement_binop!(rem, PyNumber_Remainder, "%");
1154 implement_binop!(lshift, PyNumber_Lshift, "<<");
1155 implement_binop!(rshift, PyNumber_Rshift, ">>");
1156 implement_binop!(bitand, PyNumber_And, "&");
1157 implement_binop!(bitor, PyNumber_Or, "|");
1158 implement_binop!(bitxor, PyNumber_Xor, "^");
1159
1160 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
1162 where
1163 O: IntoPyObject<'py>,
1164 {
1165 fn inner<'py>(
1166 any: &Bound<'py, PyAny>,
1167 other: Borrowed<'_, 'py, PyAny>,
1168 ) -> PyResult<Bound<'py, PyAny>> {
1169 unsafe {
1170 ffi::PyNumber_Divmod(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py())
1171 }
1172 }
1173
1174 let py = self.py();
1175 inner(
1176 self,
1177 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1178 )
1179 }
1180
1181 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
1184 where
1185 O1: IntoPyObject<'py>,
1186 O2: IntoPyObject<'py>,
1187 {
1188 fn inner<'py>(
1189 any: &Bound<'py, PyAny>,
1190 other: Borrowed<'_, 'py, PyAny>,
1191 modulus: Borrowed<'_, 'py, PyAny>,
1192 ) -> PyResult<Bound<'py, PyAny>> {
1193 unsafe {
1194 ffi::PyNumber_Power(any.as_ptr(), other.as_ptr(), modulus.as_ptr())
1195 .assume_owned_or_err(any.py())
1196 }
1197 }
1198
1199 let py = self.py();
1200 inner(
1201 self,
1202 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1203 modulus.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1204 )
1205 }
1206
1207 fn is_callable(&self) -> bool {
1208 unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 }
1209 }
1210
1211 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
1212 where
1213 A: PyCallArgs<'py>,
1214 {
1215 if let Some(kwargs) = kwargs {
1216 args.call(
1217 self.as_borrowed(),
1218 kwargs.as_borrowed(),
1219 crate::call::private::Token,
1220 )
1221 } else {
1222 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1223 }
1224 }
1225
1226 #[inline]
1227 fn call0(&self) -> PyResult<Bound<'py, PyAny>> {
1228 unsafe { ffi::compat::PyObject_CallNoArgs(self.as_ptr()).assume_owned_or_err(self.py()) }
1229 }
1230
1231 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
1232 where
1233 A: PyCallArgs<'py>,
1234 {
1235 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1236 }
1237
1238 #[inline]
1239 fn call_method<N, A>(
1240 &self,
1241 name: N,
1242 args: A,
1243 kwargs: Option<&Bound<'py, PyDict>>,
1244 ) -> PyResult<Bound<'py, PyAny>>
1245 where
1246 N: IntoPyObject<'py, Target = PyString>,
1247 A: PyCallArgs<'py>,
1248 {
1249 if kwargs.is_none() {
1250 self.call_method1(name, args)
1251 } else {
1252 self.getattr(name)
1253 .and_then(|method| method.call(args, kwargs))
1254 }
1255 }
1256
1257 #[inline]
1258 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
1259 where
1260 N: IntoPyObject<'py, Target = PyString>,
1261 {
1262 let py = self.py();
1263 let name = name.into_pyobject_or_pyerr(py)?.into_bound();
1264 unsafe {
1265 ffi::compat::PyObject_CallMethodNoArgs(self.as_ptr(), name.as_ptr())
1266 .assume_owned_or_err(py)
1267 }
1268 }
1269
1270 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
1271 where
1272 N: IntoPyObject<'py, Target = PyString>,
1273 A: PyCallArgs<'py>,
1274 {
1275 let name = name.into_pyobject_or_pyerr(self.py())?;
1276 args.call_method_positional(
1277 self.as_borrowed(),
1278 name.as_borrowed(),
1279 crate::call::private::Token,
1280 )
1281 }
1282
1283 fn is_truthy(&self) -> PyResult<bool> {
1284 let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
1285 err::error_on_minusone(self.py(), v)?;
1286 Ok(v != 0)
1287 }
1288
1289 #[inline]
1290 fn is_none(&self) -> bool {
1291 unsafe { ffi::Py_None() == self.as_ptr() }
1292 }
1293
1294 fn is_ellipsis(&self) -> bool {
1295 unsafe { ffi::Py_Ellipsis() == self.as_ptr() }
1296 }
1297
1298 fn is_empty(&self) -> PyResult<bool> {
1299 self.len().map(|l| l == 0)
1300 }
1301
1302 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
1303 where
1304 K: IntoPyObject<'py>,
1305 {
1306 fn inner<'py>(
1307 any: &Bound<'py, PyAny>,
1308 key: Borrowed<'_, 'py, PyAny>,
1309 ) -> PyResult<Bound<'py, PyAny>> {
1310 unsafe {
1311 ffi::PyObject_GetItem(any.as_ptr(), key.as_ptr()).assume_owned_or_err(any.py())
1312 }
1313 }
1314
1315 let py = self.py();
1316 inner(
1317 self,
1318 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1319 )
1320 }
1321
1322 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
1323 where
1324 K: IntoPyObject<'py>,
1325 V: IntoPyObject<'py>,
1326 {
1327 fn inner(
1328 any: &Bound<'_, PyAny>,
1329 key: Borrowed<'_, '_, PyAny>,
1330 value: Borrowed<'_, '_, PyAny>,
1331 ) -> PyResult<()> {
1332 err::error_on_minusone(any.py(), unsafe {
1333 ffi::PyObject_SetItem(any.as_ptr(), key.as_ptr(), value.as_ptr())
1334 })
1335 }
1336
1337 let py = self.py();
1338 inner(
1339 self,
1340 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1341 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1342 )
1343 }
1344
1345 fn del_item<K>(&self, key: K) -> PyResult<()>
1346 where
1347 K: IntoPyObject<'py>,
1348 {
1349 fn inner(any: &Bound<'_, PyAny>, key: Borrowed<'_, '_, PyAny>) -> PyResult<()> {
1350 err::error_on_minusone(any.py(), unsafe {
1351 ffi::PyObject_DelItem(any.as_ptr(), key.as_ptr())
1352 })
1353 }
1354
1355 let py = self.py();
1356 inner(
1357 self,
1358 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1359 )
1360 }
1361
1362 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>> {
1363 PyIterator::from_object(self)
1364 }
1365
1366 fn iter(&self) -> PyResult<Bound<'py, PyIterator>> {
1367 self.try_iter()
1368 }
1369
1370 fn get_type(&self) -> Bound<'py, PyType> {
1371 unsafe { PyType::from_borrowed_type_ptr(self.py(), ffi::Py_TYPE(self.as_ptr())) }
1372 }
1373
1374 #[inline]
1375 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject {
1376 unsafe { ffi::Py_TYPE(self.as_ptr()) }
1377 }
1378
1379 #[inline]
1380 fn downcast<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
1381 where
1382 T: PyTypeCheck,
1383 {
1384 if T::type_check(self) {
1385 Ok(unsafe { self.downcast_unchecked() })
1387 } else {
1388 Err(DowncastError::new(self, T::NAME))
1389 }
1390 }
1391
1392 #[inline]
1393 fn downcast_into<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
1394 where
1395 T: PyTypeCheck,
1396 {
1397 if T::type_check(&self) {
1398 Ok(unsafe { self.downcast_into_unchecked() })
1400 } else {
1401 Err(DowncastIntoError::new(self, T::NAME))
1402 }
1403 }
1404
1405 #[inline]
1406 fn downcast_exact<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
1407 where
1408 T: PyTypeInfo,
1409 {
1410 if self.is_exact_instance_of::<T>() {
1411 Ok(unsafe { self.downcast_unchecked() })
1413 } else {
1414 Err(DowncastError::new(self, T::NAME))
1415 }
1416 }
1417
1418 #[inline]
1419 fn downcast_into_exact<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
1420 where
1421 T: PyTypeInfo,
1422 {
1423 if self.is_exact_instance_of::<T>() {
1424 Ok(unsafe { self.downcast_into_unchecked() })
1426 } else {
1427 Err(DowncastIntoError::new(self, T::NAME))
1428 }
1429 }
1430
1431 #[inline]
1432 unsafe fn downcast_unchecked<T>(&self) -> &Bound<'py, T> {
1433 &*ptr_from_ref(self).cast()
1434 }
1435
1436 #[inline]
1437 unsafe fn downcast_into_unchecked<T>(self) -> Bound<'py, T> {
1438 std::mem::transmute(self)
1439 }
1440
1441 fn extract<'a, T>(&'a self) -> PyResult<T>
1442 where
1443 T: FromPyObjectBound<'a, 'py>,
1444 {
1445 FromPyObjectBound::from_py_object_bound(self.as_borrowed())
1446 }
1447
1448 fn get_refcnt(&self) -> isize {
1449 unsafe { ffi::Py_REFCNT(self.as_ptr()) }
1450 }
1451
1452 fn repr(&self) -> PyResult<Bound<'py, PyString>> {
1453 unsafe {
1454 ffi::PyObject_Repr(self.as_ptr())
1455 .assume_owned_or_err(self.py())
1456 .downcast_into_unchecked()
1457 }
1458 }
1459
1460 fn str(&self) -> PyResult<Bound<'py, PyString>> {
1461 unsafe {
1462 ffi::PyObject_Str(self.as_ptr())
1463 .assume_owned_or_err(self.py())
1464 .downcast_into_unchecked()
1465 }
1466 }
1467
1468 fn hash(&self) -> PyResult<isize> {
1469 let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) };
1470 crate::err::error_on_minusone(self.py(), v)?;
1471 Ok(v)
1472 }
1473
1474 fn len(&self) -> PyResult<usize> {
1475 let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
1476 crate::err::error_on_minusone(self.py(), v)?;
1477 Ok(v as usize)
1478 }
1479
1480 fn dir(&self) -> PyResult<Bound<'py, PyList>> {
1481 unsafe {
1482 ffi::PyObject_Dir(self.as_ptr())
1483 .assume_owned_or_err(self.py())
1484 .downcast_into_unchecked()
1485 }
1486 }
1487
1488 #[inline]
1489 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool> {
1490 let result = unsafe { ffi::PyObject_IsInstance(self.as_ptr(), ty.as_ptr()) };
1491 err::error_on_minusone(self.py(), result)?;
1492 Ok(result == 1)
1493 }
1494
1495 #[inline]
1496 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool {
1497 self.get_type().is(ty)
1498 }
1499
1500 #[inline]
1501 fn is_instance_of<T: PyTypeInfo>(&self) -> bool {
1502 T::is_type_of(self)
1503 }
1504
1505 #[inline]
1506 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool {
1507 T::is_exact_type_of(self)
1508 }
1509
1510 fn contains<V>(&self, value: V) -> PyResult<bool>
1511 where
1512 V: IntoPyObject<'py>,
1513 {
1514 fn inner(any: &Bound<'_, PyAny>, value: Borrowed<'_, '_, PyAny>) -> PyResult<bool> {
1515 match unsafe { ffi::PySequence_Contains(any.as_ptr(), value.as_ptr()) } {
1516 0 => Ok(false),
1517 1 => Ok(true),
1518 _ => Err(PyErr::fetch(any.py())),
1519 }
1520 }
1521
1522 let py = self.py();
1523 inner(
1524 self,
1525 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1526 )
1527 }
1528
1529 #[cfg(not(any(PyPy, GraalPy)))]
1530 fn py_super(&self) -> PyResult<Bound<'py, PySuper>> {
1531 PySuper::new(&self.get_type(), self)
1532 }
1533}
1534
1535impl<'py> Bound<'py, PyAny> {
1536 #[allow(dead_code)] pub(crate) fn lookup_special<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
1548 where
1549 N: IntoPyObject<'py, Target = PyString>,
1550 {
1551 let py = self.py();
1552 let self_type = self.get_type();
1553 let attr = if let Ok(attr) = self_type.getattr(attr_name) {
1554 attr
1555 } else {
1556 return Ok(None);
1557 };
1558
1559 if let Some(descr_get) = attr.get_type().get_slot(TP_DESCR_GET) {
1561 unsafe {
1563 descr_get(attr.as_ptr(), self.as_ptr(), self_type.as_ptr())
1564 .assume_owned_or_err(py)
1565 .map(Some)
1566 }
1567 } else {
1568 Ok(Some(attr))
1569 }
1570 }
1571}
1572
1573#[cfg(test)]
1574mod tests {
1575 use crate::{
1576 basic::CompareOp,
1577 ffi,
1578 tests::common::generate_unique_module_name,
1579 types::{IntoPyDict, PyAny, PyAnyMethods, PyBool, PyInt, PyList, PyModule, PyTypeMethods},
1580 Bound, BoundObject, IntoPyObject, PyTypeInfo, Python,
1581 };
1582 use pyo3_ffi::c_str;
1583 use std::fmt::Debug;
1584
1585 #[test]
1586 fn test_lookup_special() {
1587 Python::with_gil(|py| {
1588 let module = PyModule::from_code(
1589 py,
1590 c_str!(
1591 r#"
1592class CustomCallable:
1593 def __call__(self):
1594 return 1
1595
1596class SimpleInt:
1597 def __int__(self):
1598 return 1
1599
1600class InheritedInt(SimpleInt): pass
1601
1602class NoInt: pass
1603
1604class NoDescriptorInt:
1605 __int__ = CustomCallable()
1606
1607class InstanceOverrideInt:
1608 def __int__(self):
1609 return 1
1610instance_override = InstanceOverrideInt()
1611instance_override.__int__ = lambda self: 2
1612
1613class ErrorInDescriptorInt:
1614 @property
1615 def __int__(self):
1616 raise ValueError("uh-oh!")
1617
1618class NonHeapNonDescriptorInt:
1619 # A static-typed callable that doesn't implement `__get__`. These are pretty hard to come by.
1620 __int__ = int
1621 "#
1622 ),
1623 c_str!("test.py"),
1624 &generate_unique_module_name("test"),
1625 )
1626 .unwrap();
1627
1628 let int = crate::intern!(py, "__int__");
1629 let eval_int =
1630 |obj: Bound<'_, PyAny>| obj.lookup_special(int)?.unwrap().call0()?.extract::<u32>();
1631
1632 let simple = module.getattr("SimpleInt").unwrap().call0().unwrap();
1633 assert_eq!(eval_int(simple).unwrap(), 1);
1634 let inherited = module.getattr("InheritedInt").unwrap().call0().unwrap();
1635 assert_eq!(eval_int(inherited).unwrap(), 1);
1636 let no_descriptor = module.getattr("NoDescriptorInt").unwrap().call0().unwrap();
1637 assert_eq!(eval_int(no_descriptor).unwrap(), 1);
1638 let missing = module.getattr("NoInt").unwrap().call0().unwrap();
1639 assert!(missing.lookup_special(int).unwrap().is_none());
1640 let instance_override = module.getattr("instance_override").unwrap();
1643 assert_eq!(eval_int(instance_override).unwrap(), 1);
1644 let descriptor_error = module
1645 .getattr("ErrorInDescriptorInt")
1646 .unwrap()
1647 .call0()
1648 .unwrap();
1649 assert!(descriptor_error.lookup_special(int).is_err());
1650 let nonheap_nondescriptor = module
1651 .getattr("NonHeapNonDescriptorInt")
1652 .unwrap()
1653 .call0()
1654 .unwrap();
1655 assert_eq!(eval_int(nonheap_nondescriptor).unwrap(), 0);
1656 })
1657 }
1658
1659 #[test]
1660 fn test_call_for_non_existing_method() {
1661 Python::with_gil(|py| {
1662 let a = py.eval(ffi::c_str!("42"), None, None).unwrap();
1663 a.call_method0("__str__").unwrap(); assert!(a.call_method("nonexistent_method", (1,), None).is_err());
1665 assert!(a.call_method0("nonexistent_method").is_err());
1666 assert!(a.call_method1("nonexistent_method", (1,)).is_err());
1667 });
1668 }
1669
1670 #[test]
1671 fn test_call_with_kwargs() {
1672 Python::with_gil(|py| {
1673 let list = vec![3, 6, 5, 4, 7].into_pyobject(py).unwrap();
1674 let dict = vec![("reverse", true)].into_py_dict(py).unwrap();
1675 list.call_method("sort", (), Some(&dict)).unwrap();
1676 assert_eq!(list.extract::<Vec<i32>>().unwrap(), vec![7, 6, 5, 4, 3]);
1677 });
1678 }
1679
1680 #[test]
1681 fn test_call_method0() {
1682 Python::with_gil(|py| {
1683 let module = PyModule::from_code(
1684 py,
1685 c_str!(
1686 r#"
1687class SimpleClass:
1688 def foo(self):
1689 return 42
1690"#
1691 ),
1692 c_str!(file!()),
1693 &generate_unique_module_name("test_module"),
1694 )
1695 .expect("module creation failed");
1696
1697 let simple_class = module.getattr("SimpleClass").unwrap().call0().unwrap();
1698 assert_eq!(
1699 simple_class
1700 .call_method0("foo")
1701 .unwrap()
1702 .extract::<u32>()
1703 .unwrap(),
1704 42
1705 );
1706 })
1707 }
1708
1709 #[test]
1710 fn test_type() {
1711 Python::with_gil(|py| {
1712 let obj = py.eval(ffi::c_str!("42"), None, None).unwrap();
1713 assert_eq!(obj.get_type().as_type_ptr(), obj.get_type_ptr());
1714 });
1715 }
1716
1717 #[test]
1718 fn test_dir() {
1719 Python::with_gil(|py| {
1720 let obj = py.eval(ffi::c_str!("42"), None, None).unwrap();
1721 let dir = py
1722 .eval(ffi::c_str!("dir(42)"), None, None)
1723 .unwrap()
1724 .downcast_into::<PyList>()
1725 .unwrap();
1726 let a = obj
1727 .dir()
1728 .unwrap()
1729 .into_iter()
1730 .map(|x| x.extract::<String>().unwrap());
1731 let b = dir.into_iter().map(|x| x.extract::<String>().unwrap());
1732 assert!(a.eq(b));
1733 });
1734 }
1735
1736 #[test]
1737 fn test_hasattr() {
1738 Python::with_gil(|py| {
1739 let x = 5i32.into_pyobject(py).unwrap();
1740 assert!(x.is_instance_of::<PyInt>());
1741
1742 assert!(x.hasattr("to_bytes").unwrap());
1743 assert!(!x.hasattr("bbbbbbytes").unwrap());
1744 })
1745 }
1746
1747 #[cfg(feature = "macros")]
1748 #[test]
1749 #[allow(unknown_lints, non_local_definitions)]
1750 fn test_hasattr_error() {
1751 use crate::exceptions::PyValueError;
1752 use crate::prelude::*;
1753
1754 #[pyclass(crate = "crate")]
1755 struct GetattrFail;
1756
1757 #[pymethods(crate = "crate")]
1758 impl GetattrFail {
1759 fn __getattr__(&self, attr: PyObject) -> PyResult<PyObject> {
1760 Err(PyValueError::new_err(attr))
1761 }
1762 }
1763
1764 Python::with_gil(|py| {
1765 let obj = Py::new(py, GetattrFail).unwrap();
1766 let obj = obj.bind(py).as_ref();
1767
1768 assert!(obj
1769 .hasattr("foo")
1770 .unwrap_err()
1771 .is_instance_of::<PyValueError>(py));
1772 })
1773 }
1774
1775 #[test]
1776 fn test_nan_eq() {
1777 Python::with_gil(|py| {
1778 let nan = py.eval(ffi::c_str!("float('nan')"), None, None).unwrap();
1779 assert!(nan.compare(&nan).is_err());
1780 });
1781 }
1782
1783 #[test]
1784 fn test_any_is_instance_of() {
1785 Python::with_gil(|py| {
1786 let x = 5i32.into_pyobject(py).unwrap();
1787 assert!(x.is_instance_of::<PyInt>());
1788
1789 let l = vec![&x, &x].into_pyobject(py).unwrap();
1790 assert!(l.is_instance_of::<PyList>());
1791 });
1792 }
1793
1794 #[test]
1795 fn test_any_is_instance() {
1796 Python::with_gil(|py| {
1797 let l = vec![1i8, 2].into_pyobject(py).unwrap();
1798 assert!(l.is_instance(&py.get_type::<PyList>()).unwrap());
1799 });
1800 }
1801
1802 #[test]
1803 fn test_any_is_exact_instance_of() {
1804 Python::with_gil(|py| {
1805 let x = 5i32.into_pyobject(py).unwrap();
1806 assert!(x.is_exact_instance_of::<PyInt>());
1807
1808 let t = PyBool::new(py, true);
1809 assert!(t.is_instance_of::<PyInt>());
1810 assert!(!t.is_exact_instance_of::<PyInt>());
1811 assert!(t.is_exact_instance_of::<PyBool>());
1812
1813 let l = vec![&x, &x].into_pyobject(py).unwrap();
1814 assert!(l.is_exact_instance_of::<PyList>());
1815 });
1816 }
1817
1818 #[test]
1819 fn test_any_is_exact_instance() {
1820 Python::with_gil(|py| {
1821 let t = PyBool::new(py, true);
1822 assert!(t.is_instance(&py.get_type::<PyInt>()).unwrap());
1823 assert!(!t.is_exact_instance(&py.get_type::<PyInt>()));
1824 assert!(t.is_exact_instance(&py.get_type::<PyBool>()));
1825 });
1826 }
1827
1828 #[test]
1829 fn test_any_contains() {
1830 Python::with_gil(|py| {
1831 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
1832 let ob = v.into_pyobject(py).unwrap();
1833
1834 let bad_needle = 7i32.into_pyobject(py).unwrap();
1835 assert!(!ob.contains(&bad_needle).unwrap());
1836
1837 let good_needle = 8i32.into_pyobject(py).unwrap();
1838 assert!(ob.contains(&good_needle).unwrap());
1839
1840 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
1841 assert!(ob.contains(&type_coerced_needle).unwrap());
1842
1843 let n: u32 = 42;
1844 let bad_haystack = n.into_pyobject(py).unwrap();
1845 let irrelevant_needle = 0i32.into_pyobject(py).unwrap();
1846 assert!(bad_haystack.contains(&irrelevant_needle).is_err());
1847 });
1848 }
1849
1850 fn test_eq_methods_generic<'a, T>(list: &'a [T])
1852 where
1853 T: PartialEq + PartialOrd,
1854 for<'py> &'a T: IntoPyObject<'py>,
1855 for<'py> <&'a T as IntoPyObject<'py>>::Error: Debug,
1856 {
1857 Python::with_gil(|py| {
1858 for a in list {
1859 for b in list {
1860 let a_py = a.into_pyobject(py).unwrap().into_any().into_bound();
1861 let b_py = b.into_pyobject(py).unwrap().into_any().into_bound();
1862
1863 assert_eq!(
1864 a.lt(b),
1865 a_py.lt(&b_py).unwrap(),
1866 "{} < {} should be {}.",
1867 a_py,
1868 b_py,
1869 a.lt(b)
1870 );
1871 assert_eq!(
1872 a.le(b),
1873 a_py.le(&b_py).unwrap(),
1874 "{} <= {} should be {}.",
1875 a_py,
1876 b_py,
1877 a.le(b)
1878 );
1879 assert_eq!(
1880 a.eq(b),
1881 a_py.eq(&b_py).unwrap(),
1882 "{} == {} should be {}.",
1883 a_py,
1884 b_py,
1885 a.eq(b)
1886 );
1887 assert_eq!(
1888 a.ne(b),
1889 a_py.ne(&b_py).unwrap(),
1890 "{} != {} should be {}.",
1891 a_py,
1892 b_py,
1893 a.ne(b)
1894 );
1895 assert_eq!(
1896 a.gt(b),
1897 a_py.gt(&b_py).unwrap(),
1898 "{} > {} should be {}.",
1899 a_py,
1900 b_py,
1901 a.gt(b)
1902 );
1903 assert_eq!(
1904 a.ge(b),
1905 a_py.ge(&b_py).unwrap(),
1906 "{} >= {} should be {}.",
1907 a_py,
1908 b_py,
1909 a.ge(b)
1910 );
1911 }
1912 }
1913 });
1914 }
1915
1916 #[test]
1917 fn test_eq_methods_integers() {
1918 let ints = [-4, -4, 1, 2, 0, -100, 1_000_000];
1919 test_eq_methods_generic::<i32>(&ints);
1920 }
1921
1922 #[test]
1923 fn test_eq_methods_strings() {
1924 let strings = ["Let's", "test", "some", "eq", "methods"];
1925 test_eq_methods_generic::<&str>(&strings);
1926 }
1927
1928 #[test]
1929 fn test_eq_methods_floats() {
1930 let floats = [
1931 -1.0,
1932 2.5,
1933 0.0,
1934 3.0,
1935 std::f64::consts::PI,
1936 10.0,
1937 10.0 / 3.0,
1938 -1_000_000.0,
1939 ];
1940 test_eq_methods_generic::<f64>(&floats);
1941 }
1942
1943 #[test]
1944 fn test_eq_methods_bools() {
1945 let bools = [true, false];
1946 test_eq_methods_generic::<bool>(&bools);
1947 }
1948
1949 #[test]
1950 fn test_rich_compare_type_error() {
1951 Python::with_gil(|py| {
1952 let py_int = 1i32.into_pyobject(py).unwrap();
1953 let py_str = "1".into_pyobject(py).unwrap();
1954
1955 assert!(py_int.rich_compare(&py_str, CompareOp::Lt).is_err());
1956 assert!(!py_int
1957 .rich_compare(py_str, CompareOp::Eq)
1958 .unwrap()
1959 .is_truthy()
1960 .unwrap());
1961 })
1962 }
1963
1964 #[test]
1965 #[allow(deprecated)]
1966 fn test_is_ellipsis() {
1967 Python::with_gil(|py| {
1968 let v = py
1969 .eval(ffi::c_str!("..."), None, None)
1970 .map_err(|e| e.display(py))
1971 .unwrap();
1972
1973 assert!(v.is_ellipsis());
1974
1975 let not_ellipsis = 5i32.into_pyobject(py).unwrap();
1976 assert!(!not_ellipsis.is_ellipsis());
1977 });
1978 }
1979
1980 #[test]
1981 fn test_is_callable() {
1982 Python::with_gil(|py| {
1983 assert!(PyList::type_object(py).is_callable());
1984
1985 let not_callable = 5i32.into_pyobject(py).unwrap();
1986 assert!(!not_callable.is_callable());
1987 });
1988 }
1989
1990 #[test]
1991 fn test_is_empty() {
1992 Python::with_gil(|py| {
1993 let empty_list = PyList::empty(py).into_any();
1994 assert!(empty_list.is_empty().unwrap());
1995
1996 let list = PyList::new(py, vec![1, 2, 3]).unwrap().into_any();
1997 assert!(!list.is_empty().unwrap());
1998
1999 let not_container = 5i32.into_pyobject(py).unwrap();
2000 assert!(not_container.is_empty().is_err());
2001 });
2002 }
2003
2004 #[cfg(feature = "macros")]
2005 #[test]
2006 #[allow(unknown_lints, non_local_definitions)]
2007 fn test_fallible_dir() {
2008 use crate::exceptions::PyValueError;
2009 use crate::prelude::*;
2010
2011 #[pyclass(crate = "crate")]
2012 struct DirFail;
2013
2014 #[pymethods(crate = "crate")]
2015 impl DirFail {
2016 fn __dir__(&self) -> PyResult<PyObject> {
2017 Err(PyValueError::new_err("uh-oh!"))
2018 }
2019 }
2020
2021 Python::with_gil(|py| {
2022 let obj = Bound::new(py, DirFail).unwrap();
2023 assert!(obj.dir().unwrap_err().is_instance_of::<PyValueError>(py));
2024 })
2025 }
2026}