1use crate::call::PyCallArgs;
2use crate::class::basic::CompareOp;
3use crate::conversion::{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::py_result_ext::PyResultExt;
10use crate::type_object::{PyTypeCheck, PyTypeInfo};
11#[cfg(not(any(PyPy, GraalPy)))]
12use crate::types::PySuper;
13use crate::types::{PyDict, PyIterator, PyList, PyString, PyType};
14use crate::{err, ffi, Borrowed, BoundObject, IntoPyObjectExt, Py, Python};
15use std::cell::UnsafeCell;
16use std::cmp::Ordering;
17use std::ffi::c_int;
18use std::ptr;
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: AsRef<Py<PyAny>>>(&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 getattr_opt<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
150 where
151 N: IntoPyObject<'py, Target = PyString>;
152
153 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
176 where
177 N: IntoPyObject<'py, Target = PyString>,
178 V: IntoPyObject<'py>;
179
180 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
187 where
188 N: IntoPyObject<'py, Target = PyString>;
189
190 fn compare<O>(&self, other: O) -> PyResult<Ordering>
237 where
238 O: IntoPyObject<'py>;
239
240 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
274 where
275 O: IntoPyObject<'py>;
276
277 fn neg(&self) -> PyResult<Bound<'py, PyAny>>;
281
282 fn pos(&self) -> PyResult<Bound<'py, PyAny>>;
286
287 fn abs(&self) -> PyResult<Bound<'py, PyAny>>;
291
292 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>>;
294
295 fn lt<O>(&self, other: O) -> PyResult<bool>
299 where
300 O: IntoPyObject<'py>;
301
302 fn le<O>(&self, other: O) -> PyResult<bool>
306 where
307 O: IntoPyObject<'py>;
308
309 fn eq<O>(&self, other: O) -> PyResult<bool>
313 where
314 O: IntoPyObject<'py>;
315
316 fn ne<O>(&self, other: O) -> PyResult<bool>
320 where
321 O: IntoPyObject<'py>;
322
323 fn gt<O>(&self, other: O) -> PyResult<bool>
327 where
328 O: IntoPyObject<'py>;
329
330 fn ge<O>(&self, other: O) -> PyResult<bool>
334 where
335 O: IntoPyObject<'py>;
336
337 fn add<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
339 where
340 O: IntoPyObject<'py>;
341
342 fn sub<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
344 where
345 O: IntoPyObject<'py>;
346
347 fn mul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
349 where
350 O: IntoPyObject<'py>;
351
352 fn matmul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
354 where
355 O: IntoPyObject<'py>;
356
357 fn div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
359 where
360 O: IntoPyObject<'py>;
361
362 fn floor_div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
364 where
365 O: IntoPyObject<'py>;
366
367 fn rem<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
369 where
370 O: IntoPyObject<'py>;
371
372 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
374 where
375 O: IntoPyObject<'py>;
376
377 fn lshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
379 where
380 O: IntoPyObject<'py>;
381
382 fn rshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
384 where
385 O: IntoPyObject<'py>;
386
387 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
390 where
391 O1: IntoPyObject<'py>,
392 O2: IntoPyObject<'py>;
393
394 fn bitand<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
396 where
397 O: IntoPyObject<'py>;
398
399 fn bitor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
401 where
402 O: IntoPyObject<'py>;
403
404 fn bitxor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
406 where
407 O: IntoPyObject<'py>;
408
409 fn is_callable(&self) -> bool;
437
438 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
471 where
472 A: PyCallArgs<'py>;
473
474 fn call0(&self) -> PyResult<Bound<'py, PyAny>>;
495
496 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
526 where
527 A: PyCallArgs<'py>;
528
529 fn call_method<N, A>(
567 &self,
568 name: N,
569 args: A,
570 kwargs: Option<&Bound<'py, PyDict>>,
571 ) -> PyResult<Bound<'py, PyAny>>
572 where
573 N: IntoPyObject<'py, Target = PyString>,
574 A: PyCallArgs<'py>;
575
576 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
610 where
611 N: IntoPyObject<'py, Target = PyString>;
612
613 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
648 where
649 N: IntoPyObject<'py, Target = PyString>,
650 A: PyCallArgs<'py>;
651
652 fn is_truthy(&self) -> PyResult<bool>;
656
657 fn is_none(&self) -> bool;
661
662 fn is_empty(&self) -> PyResult<bool>;
666
667 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
671 where
672 K: IntoPyObject<'py>;
673
674 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
678 where
679 K: IntoPyObject<'py>,
680 V: IntoPyObject<'py>;
681
682 fn del_item<K>(&self, key: K) -> PyResult<()>
686 where
687 K: IntoPyObject<'py>;
688
689 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>>;
714
715 fn get_type(&self) -> Bound<'py, PyType>;
717
718 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject;
720
721 fn downcast<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
777 where
778 T: PyTypeCheck;
779
780 fn downcast_into<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
805 where
806 T: PyTypeCheck;
807
808 fn downcast_exact<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
841 where
842 T: PyTypeInfo;
843
844 fn downcast_into_exact<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
847 where
848 T: PyTypeInfo;
849
850 unsafe fn downcast_unchecked<T>(&self) -> &Bound<'py, T>;
857
858 unsafe fn downcast_into_unchecked<T>(self) -> Bound<'py, T>;
865
866 fn extract<'a, T>(&'a self) -> PyResult<T>
871 where
872 T: FromPyObjectBound<'a, 'py>;
873
874 fn get_refcnt(&self) -> isize;
876
877 fn repr(&self) -> PyResult<Bound<'py, PyString>>;
881
882 fn str(&self) -> PyResult<Bound<'py, PyString>>;
886
887 fn hash(&self) -> PyResult<isize>;
891
892 fn len(&self) -> PyResult<usize>;
896
897 fn dir(&self) -> PyResult<Bound<'py, PyList>>;
901
902 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool>;
906
907 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool;
911
912 fn is_instance_of<T: PyTypeCheck>(&self) -> bool;
917
918 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool;
923
924 fn contains<V>(&self, value: V) -> PyResult<bool>
928 where
929 V: IntoPyObject<'py>;
930
931 #[cfg(not(any(PyPy, GraalPy)))]
935 fn py_super(&self) -> PyResult<Bound<'py, PySuper>>;
936}
937
938macro_rules! implement_binop {
939 ($name:ident, $c_api:ident, $op:expr) => {
940 #[doc = concat!("Computes `self ", $op, " other`.")]
941 fn $name<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
942 where
943 O: IntoPyObject<'py>,
944 {
945 fn inner<'py>(
946 any: &Bound<'py, PyAny>,
947 other: Borrowed<'_, 'py, PyAny>,
948 ) -> PyResult<Bound<'py, PyAny>> {
949 unsafe { ffi::$c_api(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py()) }
950 }
951
952 let py = self.py();
953 inner(
954 self,
955 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
956 )
957 }
958 };
959}
960
961impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
962 #[inline]
963 fn is<T: AsRef<Py<PyAny>>>(&self, other: T) -> bool {
964 ptr::eq(self.as_ptr(), other.as_ref().as_ptr())
965 }
966
967 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
968 where
969 N: IntoPyObject<'py, Target = PyString>,
970 {
971 fn inner(py: Python<'_>, getattr_result: PyResult<Bound<'_, PyAny>>) -> PyResult<bool> {
974 match getattr_result {
975 Ok(_) => Ok(true),
976 Err(err) if err.is_instance_of::<PyAttributeError>(py) => Ok(false),
977 Err(e) => Err(e),
978 }
979 }
980
981 inner(self.py(), self.getattr(attr_name))
982 }
983
984 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
985 where
986 N: IntoPyObject<'py, Target = PyString>,
987 {
988 fn inner<'py>(
989 any: &Bound<'py, PyAny>,
990 attr_name: Borrowed<'_, '_, PyString>,
991 ) -> PyResult<Bound<'py, PyAny>> {
992 unsafe {
993 ffi::PyObject_GetAttr(any.as_ptr(), attr_name.as_ptr())
994 .assume_owned_or_err(any.py())
995 }
996 }
997
998 inner(
999 self,
1000 attr_name
1001 .into_pyobject(self.py())
1002 .map_err(Into::into)?
1003 .as_borrowed(),
1004 )
1005 }
1006
1007 fn getattr_opt<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
1008 where
1009 N: IntoPyObject<'py, Target = PyString>,
1010 {
1011 fn inner<'py>(
1012 any: &Bound<'py, PyAny>,
1013 attr_name: Borrowed<'_, 'py, PyString>,
1014 ) -> PyResult<Option<Bound<'py, PyAny>>> {
1015 #[cfg(Py_3_13)]
1016 {
1017 let mut resp_ptr: *mut ffi::PyObject = std::ptr::null_mut();
1018 match unsafe {
1019 ffi::PyObject_GetOptionalAttr(any.as_ptr(), attr_name.as_ptr(), &mut resp_ptr)
1020 } {
1021 1 => {
1023 let bound = unsafe { Bound::from_owned_ptr(any.py(), resp_ptr) };
1024 Ok(Some(bound))
1025 }
1026 0 => Ok(None),
1028
1029 _ => Err(PyErr::fetch(any.py())),
1031 }
1032 }
1033
1034 #[cfg(not(Py_3_13))]
1035 {
1036 match any.getattr(attr_name) {
1037 Ok(bound) => Ok(Some(bound)),
1038 Err(err) => {
1039 let err_type = err
1040 .get_type(any.py())
1041 .is(PyType::new::<PyAttributeError>(any.py()));
1042 match err_type {
1043 true => Ok(None),
1044 false => Err(err),
1045 }
1046 }
1047 }
1048 }
1049 }
1050
1051 let py = self.py();
1052 inner(self, attr_name.into_pyobject_or_pyerr(py)?.as_borrowed())
1053 }
1054
1055 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
1056 where
1057 N: IntoPyObject<'py, Target = PyString>,
1058 V: IntoPyObject<'py>,
1059 {
1060 fn inner(
1061 any: &Bound<'_, PyAny>,
1062 attr_name: Borrowed<'_, '_, PyString>,
1063 value: Borrowed<'_, '_, PyAny>,
1064 ) -> PyResult<()> {
1065 err::error_on_minusone(any.py(), unsafe {
1066 ffi::PyObject_SetAttr(any.as_ptr(), attr_name.as_ptr(), value.as_ptr())
1067 })
1068 }
1069
1070 let py = self.py();
1071 inner(
1072 self,
1073 attr_name.into_pyobject_or_pyerr(py)?.as_borrowed(),
1074 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1075 )
1076 }
1077
1078 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
1079 where
1080 N: IntoPyObject<'py, Target = PyString>,
1081 {
1082 fn inner(any: &Bound<'_, PyAny>, attr_name: Borrowed<'_, '_, PyString>) -> PyResult<()> {
1083 err::error_on_minusone(any.py(), unsafe {
1084 ffi::PyObject_DelAttr(any.as_ptr(), attr_name.as_ptr())
1085 })
1086 }
1087
1088 let py = self.py();
1089 inner(self, attr_name.into_pyobject_or_pyerr(py)?.as_borrowed())
1090 }
1091
1092 fn compare<O>(&self, other: O) -> PyResult<Ordering>
1093 where
1094 O: IntoPyObject<'py>,
1095 {
1096 fn inner(any: &Bound<'_, PyAny>, other: Borrowed<'_, '_, PyAny>) -> PyResult<Ordering> {
1097 let other = other.as_ptr();
1098 let do_compare = |other, op| unsafe {
1101 ffi::PyObject_RichCompare(any.as_ptr(), other, op)
1102 .assume_owned_or_err(any.py())
1103 .and_then(|obj| obj.is_truthy())
1104 };
1105 if do_compare(other, ffi::Py_EQ)? {
1106 Ok(Ordering::Equal)
1107 } else if do_compare(other, ffi::Py_LT)? {
1108 Ok(Ordering::Less)
1109 } else if do_compare(other, ffi::Py_GT)? {
1110 Ok(Ordering::Greater)
1111 } else {
1112 Err(PyTypeError::new_err(
1113 "PyAny::compare(): All comparisons returned false",
1114 ))
1115 }
1116 }
1117
1118 let py = self.py();
1119 inner(
1120 self,
1121 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1122 )
1123 }
1124
1125 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
1126 where
1127 O: IntoPyObject<'py>,
1128 {
1129 fn inner<'py>(
1130 any: &Bound<'py, PyAny>,
1131 other: Borrowed<'_, 'py, PyAny>,
1132 compare_op: CompareOp,
1133 ) -> PyResult<Bound<'py, PyAny>> {
1134 unsafe {
1135 ffi::PyObject_RichCompare(any.as_ptr(), other.as_ptr(), compare_op as c_int)
1136 .assume_owned_or_err(any.py())
1137 }
1138 }
1139
1140 let py = self.py();
1141 inner(
1142 self,
1143 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1144 compare_op,
1145 )
1146 }
1147
1148 fn neg(&self) -> PyResult<Bound<'py, PyAny>> {
1149 unsafe { ffi::PyNumber_Negative(self.as_ptr()).assume_owned_or_err(self.py()) }
1150 }
1151
1152 fn pos(&self) -> PyResult<Bound<'py, PyAny>> {
1153 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1154 unsafe { ffi::PyNumber_Positive(any.as_ptr()).assume_owned_or_err(any.py()) }
1155 }
1156
1157 inner(self)
1158 }
1159
1160 fn abs(&self) -> PyResult<Bound<'py, PyAny>> {
1161 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1162 unsafe { ffi::PyNumber_Absolute(any.as_ptr()).assume_owned_or_err(any.py()) }
1163 }
1164
1165 inner(self)
1166 }
1167
1168 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>> {
1169 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1170 unsafe { ffi::PyNumber_Invert(any.as_ptr()).assume_owned_or_err(any.py()) }
1171 }
1172
1173 inner(self)
1174 }
1175
1176 fn lt<O>(&self, other: O) -> PyResult<bool>
1177 where
1178 O: IntoPyObject<'py>,
1179 {
1180 self.rich_compare(other, CompareOp::Lt)
1181 .and_then(|any| any.is_truthy())
1182 }
1183
1184 fn le<O>(&self, other: O) -> PyResult<bool>
1185 where
1186 O: IntoPyObject<'py>,
1187 {
1188 self.rich_compare(other, CompareOp::Le)
1189 .and_then(|any| any.is_truthy())
1190 }
1191
1192 fn eq<O>(&self, other: O) -> PyResult<bool>
1193 where
1194 O: IntoPyObject<'py>,
1195 {
1196 self.rich_compare(other, CompareOp::Eq)
1197 .and_then(|any| any.is_truthy())
1198 }
1199
1200 fn ne<O>(&self, other: O) -> PyResult<bool>
1201 where
1202 O: IntoPyObject<'py>,
1203 {
1204 self.rich_compare(other, CompareOp::Ne)
1205 .and_then(|any| any.is_truthy())
1206 }
1207
1208 fn gt<O>(&self, other: O) -> PyResult<bool>
1209 where
1210 O: IntoPyObject<'py>,
1211 {
1212 self.rich_compare(other, CompareOp::Gt)
1213 .and_then(|any| any.is_truthy())
1214 }
1215
1216 fn ge<O>(&self, other: O) -> PyResult<bool>
1217 where
1218 O: IntoPyObject<'py>,
1219 {
1220 self.rich_compare(other, CompareOp::Ge)
1221 .and_then(|any| any.is_truthy())
1222 }
1223
1224 implement_binop!(add, PyNumber_Add, "+");
1225 implement_binop!(sub, PyNumber_Subtract, "-");
1226 implement_binop!(mul, PyNumber_Multiply, "*");
1227 implement_binop!(matmul, PyNumber_MatrixMultiply, "@");
1228 implement_binop!(div, PyNumber_TrueDivide, "/");
1229 implement_binop!(floor_div, PyNumber_FloorDivide, "//");
1230 implement_binop!(rem, PyNumber_Remainder, "%");
1231 implement_binop!(lshift, PyNumber_Lshift, "<<");
1232 implement_binop!(rshift, PyNumber_Rshift, ">>");
1233 implement_binop!(bitand, PyNumber_And, "&");
1234 implement_binop!(bitor, PyNumber_Or, "|");
1235 implement_binop!(bitxor, PyNumber_Xor, "^");
1236
1237 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
1239 where
1240 O: IntoPyObject<'py>,
1241 {
1242 fn inner<'py>(
1243 any: &Bound<'py, PyAny>,
1244 other: Borrowed<'_, 'py, PyAny>,
1245 ) -> PyResult<Bound<'py, PyAny>> {
1246 unsafe {
1247 ffi::PyNumber_Divmod(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py())
1248 }
1249 }
1250
1251 let py = self.py();
1252 inner(
1253 self,
1254 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1255 )
1256 }
1257
1258 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
1261 where
1262 O1: IntoPyObject<'py>,
1263 O2: IntoPyObject<'py>,
1264 {
1265 fn inner<'py>(
1266 any: &Bound<'py, PyAny>,
1267 other: Borrowed<'_, 'py, PyAny>,
1268 modulus: Borrowed<'_, 'py, PyAny>,
1269 ) -> PyResult<Bound<'py, PyAny>> {
1270 unsafe {
1271 ffi::PyNumber_Power(any.as_ptr(), other.as_ptr(), modulus.as_ptr())
1272 .assume_owned_or_err(any.py())
1273 }
1274 }
1275
1276 let py = self.py();
1277 inner(
1278 self,
1279 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1280 modulus.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1281 )
1282 }
1283
1284 fn is_callable(&self) -> bool {
1285 unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 }
1286 }
1287
1288 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
1289 where
1290 A: PyCallArgs<'py>,
1291 {
1292 if let Some(kwargs) = kwargs {
1293 args.call(
1294 self.as_borrowed(),
1295 kwargs.as_borrowed(),
1296 crate::call::private::Token,
1297 )
1298 } else {
1299 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1300 }
1301 }
1302
1303 #[inline]
1304 fn call0(&self) -> PyResult<Bound<'py, PyAny>> {
1305 unsafe { ffi::compat::PyObject_CallNoArgs(self.as_ptr()).assume_owned_or_err(self.py()) }
1306 }
1307
1308 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
1309 where
1310 A: PyCallArgs<'py>,
1311 {
1312 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1313 }
1314
1315 #[inline]
1316 fn call_method<N, A>(
1317 &self,
1318 name: N,
1319 args: A,
1320 kwargs: Option<&Bound<'py, PyDict>>,
1321 ) -> PyResult<Bound<'py, PyAny>>
1322 where
1323 N: IntoPyObject<'py, Target = PyString>,
1324 A: PyCallArgs<'py>,
1325 {
1326 if kwargs.is_none() {
1327 self.call_method1(name, args)
1328 } else {
1329 self.getattr(name)
1330 .and_then(|method| method.call(args, kwargs))
1331 }
1332 }
1333
1334 #[inline]
1335 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
1336 where
1337 N: IntoPyObject<'py, Target = PyString>,
1338 {
1339 let py = self.py();
1340 let name = name.into_pyobject_or_pyerr(py)?.into_bound();
1341 unsafe {
1342 ffi::compat::PyObject_CallMethodNoArgs(self.as_ptr(), name.as_ptr())
1343 .assume_owned_or_err(py)
1344 }
1345 }
1346
1347 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
1348 where
1349 N: IntoPyObject<'py, Target = PyString>,
1350 A: PyCallArgs<'py>,
1351 {
1352 let name = name.into_pyobject_or_pyerr(self.py())?;
1353 args.call_method_positional(
1354 self.as_borrowed(),
1355 name.as_borrowed(),
1356 crate::call::private::Token,
1357 )
1358 }
1359
1360 fn is_truthy(&self) -> PyResult<bool> {
1361 let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
1362 err::error_on_minusone(self.py(), v)?;
1363 Ok(v != 0)
1364 }
1365
1366 #[inline]
1367 fn is_none(&self) -> bool {
1368 unsafe { ptr::eq(ffi::Py_None(), self.as_ptr()) }
1369 }
1370
1371 fn is_empty(&self) -> PyResult<bool> {
1372 self.len().map(|l| l == 0)
1373 }
1374
1375 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
1376 where
1377 K: IntoPyObject<'py>,
1378 {
1379 fn inner<'py>(
1380 any: &Bound<'py, PyAny>,
1381 key: Borrowed<'_, 'py, PyAny>,
1382 ) -> PyResult<Bound<'py, PyAny>> {
1383 unsafe {
1384 ffi::PyObject_GetItem(any.as_ptr(), key.as_ptr()).assume_owned_or_err(any.py())
1385 }
1386 }
1387
1388 let py = self.py();
1389 inner(
1390 self,
1391 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1392 )
1393 }
1394
1395 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
1396 where
1397 K: IntoPyObject<'py>,
1398 V: IntoPyObject<'py>,
1399 {
1400 fn inner(
1401 any: &Bound<'_, PyAny>,
1402 key: Borrowed<'_, '_, PyAny>,
1403 value: Borrowed<'_, '_, PyAny>,
1404 ) -> PyResult<()> {
1405 err::error_on_minusone(any.py(), unsafe {
1406 ffi::PyObject_SetItem(any.as_ptr(), key.as_ptr(), value.as_ptr())
1407 })
1408 }
1409
1410 let py = self.py();
1411 inner(
1412 self,
1413 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1414 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1415 )
1416 }
1417
1418 fn del_item<K>(&self, key: K) -> PyResult<()>
1419 where
1420 K: IntoPyObject<'py>,
1421 {
1422 fn inner(any: &Bound<'_, PyAny>, key: Borrowed<'_, '_, PyAny>) -> PyResult<()> {
1423 err::error_on_minusone(any.py(), unsafe {
1424 ffi::PyObject_DelItem(any.as_ptr(), key.as_ptr())
1425 })
1426 }
1427
1428 let py = self.py();
1429 inner(
1430 self,
1431 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1432 )
1433 }
1434
1435 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>> {
1436 PyIterator::from_object(self)
1437 }
1438
1439 fn get_type(&self) -> Bound<'py, PyType> {
1440 unsafe { PyType::from_borrowed_type_ptr(self.py(), ffi::Py_TYPE(self.as_ptr())) }
1441 }
1442
1443 #[inline]
1444 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject {
1445 unsafe { ffi::Py_TYPE(self.as_ptr()) }
1446 }
1447
1448 #[inline]
1449 fn downcast<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
1450 where
1451 T: PyTypeCheck,
1452 {
1453 self.cast()
1454 }
1455
1456 #[inline]
1457 fn downcast_into<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
1458 where
1459 T: PyTypeCheck,
1460 {
1461 self.cast_into()
1462 }
1463
1464 #[inline]
1465 fn downcast_exact<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
1466 where
1467 T: PyTypeInfo,
1468 {
1469 self.cast_exact()
1470 }
1471
1472 #[inline]
1473 fn downcast_into_exact<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
1474 where
1475 T: PyTypeInfo,
1476 {
1477 self.cast_into_exact()
1478 }
1479
1480 #[inline]
1481 unsafe fn downcast_unchecked<T>(&self) -> &Bound<'py, T> {
1482 unsafe { self.cast_unchecked() }
1483 }
1484
1485 #[inline]
1486 unsafe fn downcast_into_unchecked<T>(self) -> Bound<'py, T> {
1487 unsafe { self.cast_into_unchecked() }
1488 }
1489
1490 fn extract<'a, T>(&'a self) -> PyResult<T>
1491 where
1492 T: FromPyObjectBound<'a, 'py>,
1493 {
1494 FromPyObjectBound::from_py_object_bound(self.as_borrowed())
1495 }
1496
1497 fn get_refcnt(&self) -> isize {
1498 unsafe { ffi::Py_REFCNT(self.as_ptr()) }
1499 }
1500
1501 fn repr(&self) -> PyResult<Bound<'py, PyString>> {
1502 unsafe {
1503 ffi::PyObject_Repr(self.as_ptr())
1504 .assume_owned_or_err(self.py())
1505 .cast_into_unchecked()
1506 }
1507 }
1508
1509 fn str(&self) -> PyResult<Bound<'py, PyString>> {
1510 unsafe {
1511 ffi::PyObject_Str(self.as_ptr())
1512 .assume_owned_or_err(self.py())
1513 .cast_into_unchecked()
1514 }
1515 }
1516
1517 fn hash(&self) -> PyResult<isize> {
1518 let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) };
1519 crate::err::error_on_minusone(self.py(), v)?;
1520 Ok(v)
1521 }
1522
1523 fn len(&self) -> PyResult<usize> {
1524 let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
1525 crate::err::error_on_minusone(self.py(), v)?;
1526 Ok(v as usize)
1527 }
1528
1529 fn dir(&self) -> PyResult<Bound<'py, PyList>> {
1530 unsafe {
1531 ffi::PyObject_Dir(self.as_ptr())
1532 .assume_owned_or_err(self.py())
1533 .cast_into_unchecked()
1534 }
1535 }
1536
1537 #[inline]
1538 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool> {
1539 let result = unsafe { ffi::PyObject_IsInstance(self.as_ptr(), ty.as_ptr()) };
1540 err::error_on_minusone(self.py(), result)?;
1541 Ok(result == 1)
1542 }
1543
1544 #[inline]
1545 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool {
1546 self.get_type().is(ty)
1547 }
1548
1549 #[inline]
1550 fn is_instance_of<T: PyTypeCheck>(&self) -> bool {
1551 T::type_check(self)
1552 }
1553
1554 #[inline]
1555 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool {
1556 T::is_exact_type_of(self)
1557 }
1558
1559 fn contains<V>(&self, value: V) -> PyResult<bool>
1560 where
1561 V: IntoPyObject<'py>,
1562 {
1563 fn inner(any: &Bound<'_, PyAny>, value: Borrowed<'_, '_, PyAny>) -> PyResult<bool> {
1564 match unsafe { ffi::PySequence_Contains(any.as_ptr(), value.as_ptr()) } {
1565 0 => Ok(false),
1566 1 => Ok(true),
1567 _ => Err(PyErr::fetch(any.py())),
1568 }
1569 }
1570
1571 let py = self.py();
1572 inner(
1573 self,
1574 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1575 )
1576 }
1577
1578 #[cfg(not(any(PyPy, GraalPy)))]
1579 fn py_super(&self) -> PyResult<Bound<'py, PySuper>> {
1580 PySuper::new(&self.get_type(), self)
1581 }
1582}
1583
1584impl<'py> Bound<'py, PyAny> {
1585 #[allow(dead_code)] pub(crate) fn lookup_special<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
1597 where
1598 N: IntoPyObject<'py, Target = PyString>,
1599 {
1600 let py = self.py();
1601 let self_type = self.get_type();
1602 let attr = if let Ok(attr) = self_type.getattr(attr_name) {
1603 attr
1604 } else {
1605 return Ok(None);
1606 };
1607
1608 if let Some(descr_get) = attr.get_type().get_slot(TP_DESCR_GET) {
1610 unsafe {
1612 descr_get(attr.as_ptr(), self.as_ptr(), self_type.as_ptr())
1613 .assume_owned_or_err(py)
1614 .map(Some)
1615 }
1616 } else {
1617 Ok(Some(attr))
1618 }
1619 }
1620}
1621
1622#[cfg(test)]
1623mod tests {
1624 use crate::{
1625 basic::CompareOp,
1626 ffi,
1627 test_utils::generate_unique_module_name,
1628 types::{IntoPyDict, PyAny, PyAnyMethods, PyBool, PyInt, PyList, PyModule, PyTypeMethods},
1629 Bound, BoundObject, IntoPyObject, PyTypeInfo, Python,
1630 };
1631 use pyo3_ffi::c_str;
1632 use std::fmt::Debug;
1633
1634 #[test]
1635 fn test_lookup_special() {
1636 Python::attach(|py| {
1637 let module = PyModule::from_code(
1638 py,
1639 c_str!(
1640 r#"
1641class CustomCallable:
1642 def __call__(self):
1643 return 1
1644
1645class SimpleInt:
1646 def __int__(self):
1647 return 1
1648
1649class InheritedInt(SimpleInt): pass
1650
1651class NoInt: pass
1652
1653class NoDescriptorInt:
1654 __int__ = CustomCallable()
1655
1656class InstanceOverrideInt:
1657 def __int__(self):
1658 return 1
1659instance_override = InstanceOverrideInt()
1660instance_override.__int__ = lambda self: 2
1661
1662class ErrorInDescriptorInt:
1663 @property
1664 def __int__(self):
1665 raise ValueError("uh-oh!")
1666
1667class NonHeapNonDescriptorInt:
1668 # A static-typed callable that doesn't implement `__get__`. These are pretty hard to come by.
1669 __int__ = int
1670 "#
1671 ),
1672 c_str!("test.py"),
1673 &generate_unique_module_name("test"),
1674 )
1675 .unwrap();
1676
1677 let int = crate::intern!(py, "__int__");
1678 let eval_int =
1679 |obj: Bound<'_, PyAny>| obj.lookup_special(int)?.unwrap().call0()?.extract::<u32>();
1680
1681 let simple = module.getattr("SimpleInt").unwrap().call0().unwrap();
1682 assert_eq!(eval_int(simple).unwrap(), 1);
1683 let inherited = module.getattr("InheritedInt").unwrap().call0().unwrap();
1684 assert_eq!(eval_int(inherited).unwrap(), 1);
1685 let no_descriptor = module.getattr("NoDescriptorInt").unwrap().call0().unwrap();
1686 assert_eq!(eval_int(no_descriptor).unwrap(), 1);
1687 let missing = module.getattr("NoInt").unwrap().call0().unwrap();
1688 assert!(missing.lookup_special(int).unwrap().is_none());
1689 let instance_override = module.getattr("instance_override").unwrap();
1692 assert_eq!(eval_int(instance_override).unwrap(), 1);
1693 let descriptor_error = module
1694 .getattr("ErrorInDescriptorInt")
1695 .unwrap()
1696 .call0()
1697 .unwrap();
1698 assert!(descriptor_error.lookup_special(int).is_err());
1699 let nonheap_nondescriptor = module
1700 .getattr("NonHeapNonDescriptorInt")
1701 .unwrap()
1702 .call0()
1703 .unwrap();
1704 assert_eq!(eval_int(nonheap_nondescriptor).unwrap(), 0);
1705 })
1706 }
1707
1708 #[test]
1709 fn test_getattr_opt() {
1710 Python::attach(|py| {
1711 let module = PyModule::from_code(
1712 py,
1713 c_str!(
1714 r#"
1715class Test:
1716 class_str_attribute = "class_string"
1717
1718 @property
1719 def error(self):
1720 raise ValueError("This is an intentional error")
1721 "#
1722 ),
1723 c_str!("test.py"),
1724 &generate_unique_module_name("test"),
1725 )
1726 .unwrap();
1727
1728 let class_test = module.getattr_opt("Test").unwrap().unwrap();
1730
1731 let cls_attr_str = class_test
1733 .getattr_opt("class_str_attribute")
1734 .unwrap()
1735 .unwrap();
1736 assert_eq!(cls_attr_str.extract::<String>().unwrap(), "class_string");
1737
1738 let do_not_exist = class_test.getattr_opt("doNotExist").unwrap();
1740 assert!(do_not_exist.is_none());
1741
1742 let instance = class_test.call0().unwrap();
1744 let error = instance.getattr_opt("error");
1745 assert!(error.is_err());
1746 assert!(error
1747 .unwrap_err()
1748 .to_string()
1749 .contains("This is an intentional error"));
1750 });
1751 }
1752
1753 #[test]
1754 fn test_call_for_non_existing_method() {
1755 Python::attach(|py| {
1756 let a = py.eval(ffi::c_str!("42"), None, None).unwrap();
1757 a.call_method0("__str__").unwrap(); assert!(a.call_method("nonexistent_method", (1,), None).is_err());
1759 assert!(a.call_method0("nonexistent_method").is_err());
1760 assert!(a.call_method1("nonexistent_method", (1,)).is_err());
1761 });
1762 }
1763
1764 #[test]
1765 fn test_call_with_kwargs() {
1766 Python::attach(|py| {
1767 let list = vec![3, 6, 5, 4, 7].into_pyobject(py).unwrap();
1768 let dict = vec![("reverse", true)].into_py_dict(py).unwrap();
1769 list.call_method("sort", (), Some(&dict)).unwrap();
1770 assert_eq!(list.extract::<Vec<i32>>().unwrap(), vec![7, 6, 5, 4, 3]);
1771 });
1772 }
1773
1774 #[test]
1775 fn test_call_method0() {
1776 Python::attach(|py| {
1777 let module = PyModule::from_code(
1778 py,
1779 c_str!(
1780 r#"
1781class SimpleClass:
1782 def foo(self):
1783 return 42
1784"#
1785 ),
1786 c_str!(file!()),
1787 &generate_unique_module_name("test_module"),
1788 )
1789 .expect("module creation failed");
1790
1791 let simple_class = module.getattr("SimpleClass").unwrap().call0().unwrap();
1792 assert_eq!(
1793 simple_class
1794 .call_method0("foo")
1795 .unwrap()
1796 .extract::<u32>()
1797 .unwrap(),
1798 42
1799 );
1800 })
1801 }
1802
1803 #[test]
1804 fn test_type() {
1805 Python::attach(|py| {
1806 let obj = py.eval(ffi::c_str!("42"), None, None).unwrap();
1807 assert_eq!(obj.get_type().as_type_ptr(), obj.get_type_ptr());
1808 });
1809 }
1810
1811 #[test]
1812 fn test_dir() {
1813 Python::attach(|py| {
1814 let obj = py.eval(ffi::c_str!("42"), None, None).unwrap();
1815 let dir = py
1816 .eval(ffi::c_str!("dir(42)"), None, None)
1817 .unwrap()
1818 .cast_into::<PyList>()
1819 .unwrap();
1820 let a = obj
1821 .dir()
1822 .unwrap()
1823 .into_iter()
1824 .map(|x| x.extract::<String>().unwrap());
1825 let b = dir.into_iter().map(|x| x.extract::<String>().unwrap());
1826 assert!(a.eq(b));
1827 });
1828 }
1829
1830 #[test]
1831 fn test_hasattr() {
1832 Python::attach(|py| {
1833 let x = 5i32.into_pyobject(py).unwrap();
1834 assert!(x.is_instance_of::<PyInt>());
1835
1836 assert!(x.hasattr("to_bytes").unwrap());
1837 assert!(!x.hasattr("bbbbbbytes").unwrap());
1838 })
1839 }
1840
1841 #[cfg(feature = "macros")]
1842 #[test]
1843 #[allow(unknown_lints, non_local_definitions)]
1844 fn test_hasattr_error() {
1845 use crate::exceptions::PyValueError;
1846 use crate::prelude::*;
1847
1848 #[pyclass(crate = "crate")]
1849 struct GetattrFail;
1850
1851 #[pymethods(crate = "crate")]
1852 impl GetattrFail {
1853 fn __getattr__(&self, attr: Py<PyAny>) -> PyResult<Py<PyAny>> {
1854 Err(PyValueError::new_err(attr))
1855 }
1856 }
1857
1858 Python::attach(|py| {
1859 let obj = Py::new(py, GetattrFail).unwrap();
1860 let obj = obj.bind(py).as_any();
1861
1862 assert!(obj
1863 .hasattr("foo")
1864 .unwrap_err()
1865 .is_instance_of::<PyValueError>(py));
1866 })
1867 }
1868
1869 #[test]
1870 fn test_nan_eq() {
1871 Python::attach(|py| {
1872 let nan = py.eval(ffi::c_str!("float('nan')"), None, None).unwrap();
1873 assert!(nan.compare(&nan).is_err());
1874 });
1875 }
1876
1877 #[test]
1878 fn test_any_is_instance_of() {
1879 Python::attach(|py| {
1880 let x = 5i32.into_pyobject(py).unwrap();
1881 assert!(x.is_instance_of::<PyInt>());
1882
1883 let l = vec![&x, &x].into_pyobject(py).unwrap();
1884 assert!(l.is_instance_of::<PyList>());
1885 });
1886 }
1887
1888 #[test]
1889 fn test_any_is_instance() {
1890 Python::attach(|py| {
1891 let l = vec![1i8, 2].into_pyobject(py).unwrap();
1892 assert!(l.is_instance(&py.get_type::<PyList>()).unwrap());
1893 });
1894 }
1895
1896 #[test]
1897 fn test_any_is_exact_instance_of() {
1898 Python::attach(|py| {
1899 let x = 5i32.into_pyobject(py).unwrap();
1900 assert!(x.is_exact_instance_of::<PyInt>());
1901
1902 let t = PyBool::new(py, true);
1903 assert!(t.is_instance_of::<PyInt>());
1904 assert!(!t.is_exact_instance_of::<PyInt>());
1905 assert!(t.is_exact_instance_of::<PyBool>());
1906
1907 let l = vec![&x, &x].into_pyobject(py).unwrap();
1908 assert!(l.is_exact_instance_of::<PyList>());
1909 });
1910 }
1911
1912 #[test]
1913 fn test_any_is_exact_instance() {
1914 Python::attach(|py| {
1915 let t = PyBool::new(py, true);
1916 assert!(t.is_instance(&py.get_type::<PyInt>()).unwrap());
1917 assert!(!t.is_exact_instance(&py.get_type::<PyInt>()));
1918 assert!(t.is_exact_instance(&py.get_type::<PyBool>()));
1919 });
1920 }
1921
1922 #[test]
1923 fn test_any_contains() {
1924 Python::attach(|py| {
1925 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
1926 let ob = v.into_pyobject(py).unwrap();
1927
1928 let bad_needle = 7i32.into_pyobject(py).unwrap();
1929 assert!(!ob.contains(&bad_needle).unwrap());
1930
1931 let good_needle = 8i32.into_pyobject(py).unwrap();
1932 assert!(ob.contains(&good_needle).unwrap());
1933
1934 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
1935 assert!(ob.contains(&type_coerced_needle).unwrap());
1936
1937 let n: u32 = 42;
1938 let bad_haystack = n.into_pyobject(py).unwrap();
1939 let irrelevant_needle = 0i32.into_pyobject(py).unwrap();
1940 assert!(bad_haystack.contains(&irrelevant_needle).is_err());
1941 });
1942 }
1943
1944 fn test_eq_methods_generic<'a, T>(list: &'a [T])
1946 where
1947 T: PartialEq + PartialOrd,
1948 for<'py> &'a T: IntoPyObject<'py>,
1949 for<'py> <&'a T as IntoPyObject<'py>>::Error: Debug,
1950 {
1951 Python::attach(|py| {
1952 for a in list {
1953 for b in list {
1954 let a_py = a.into_pyobject(py).unwrap().into_any().into_bound();
1955 let b_py = b.into_pyobject(py).unwrap().into_any().into_bound();
1956
1957 assert_eq!(
1958 a.lt(b),
1959 a_py.lt(&b_py).unwrap(),
1960 "{} < {} should be {}.",
1961 a_py,
1962 b_py,
1963 a.lt(b)
1964 );
1965 assert_eq!(
1966 a.le(b),
1967 a_py.le(&b_py).unwrap(),
1968 "{} <= {} should be {}.",
1969 a_py,
1970 b_py,
1971 a.le(b)
1972 );
1973 assert_eq!(
1974 a.eq(b),
1975 a_py.eq(&b_py).unwrap(),
1976 "{} == {} should be {}.",
1977 a_py,
1978 b_py,
1979 a.eq(b)
1980 );
1981 assert_eq!(
1982 a.ne(b),
1983 a_py.ne(&b_py).unwrap(),
1984 "{} != {} should be {}.",
1985 a_py,
1986 b_py,
1987 a.ne(b)
1988 );
1989 assert_eq!(
1990 a.gt(b),
1991 a_py.gt(&b_py).unwrap(),
1992 "{} > {} should be {}.",
1993 a_py,
1994 b_py,
1995 a.gt(b)
1996 );
1997 assert_eq!(
1998 a.ge(b),
1999 a_py.ge(&b_py).unwrap(),
2000 "{} >= {} should be {}.",
2001 a_py,
2002 b_py,
2003 a.ge(b)
2004 );
2005 }
2006 }
2007 });
2008 }
2009
2010 #[test]
2011 fn test_eq_methods_integers() {
2012 let ints = [-4, -4, 1, 2, 0, -100, 1_000_000];
2013 test_eq_methods_generic::<i32>(&ints);
2014 }
2015
2016 #[test]
2017 fn test_eq_methods_strings() {
2018 let strings = ["Let's", "test", "some", "eq", "methods"];
2019 test_eq_methods_generic::<&str>(&strings);
2020 }
2021
2022 #[test]
2023 fn test_eq_methods_floats() {
2024 let floats = [
2025 -1.0,
2026 2.5,
2027 0.0,
2028 3.0,
2029 std::f64::consts::PI,
2030 10.0,
2031 10.0 / 3.0,
2032 -1_000_000.0,
2033 ];
2034 test_eq_methods_generic::<f64>(&floats);
2035 }
2036
2037 #[test]
2038 fn test_eq_methods_bools() {
2039 let bools = [true, false];
2040 test_eq_methods_generic::<bool>(&bools);
2041 }
2042
2043 #[test]
2044 fn test_rich_compare_type_error() {
2045 Python::attach(|py| {
2046 let py_int = 1i32.into_pyobject(py).unwrap();
2047 let py_str = "1".into_pyobject(py).unwrap();
2048
2049 assert!(py_int.rich_compare(&py_str, CompareOp::Lt).is_err());
2050 assert!(!py_int
2051 .rich_compare(py_str, CompareOp::Eq)
2052 .unwrap()
2053 .is_truthy()
2054 .unwrap());
2055 })
2056 }
2057
2058 #[test]
2059 fn test_is_callable() {
2060 Python::attach(|py| {
2061 assert!(PyList::type_object(py).is_callable());
2062
2063 let not_callable = 5i32.into_pyobject(py).unwrap();
2064 assert!(!not_callable.is_callable());
2065 });
2066 }
2067
2068 #[test]
2069 fn test_is_empty() {
2070 Python::attach(|py| {
2071 let empty_list = PyList::empty(py).into_any();
2072 assert!(empty_list.is_empty().unwrap());
2073
2074 let list = PyList::new(py, vec![1, 2, 3]).unwrap().into_any();
2075 assert!(!list.is_empty().unwrap());
2076
2077 let not_container = 5i32.into_pyobject(py).unwrap();
2078 assert!(not_container.is_empty().is_err());
2079 });
2080 }
2081
2082 #[cfg(feature = "macros")]
2083 #[test]
2084 #[allow(unknown_lints, non_local_definitions)]
2085 fn test_fallible_dir() {
2086 use crate::exceptions::PyValueError;
2087 use crate::prelude::*;
2088
2089 #[pyclass(crate = "crate")]
2090 struct DirFail;
2091
2092 #[pymethods(crate = "crate")]
2093 impl DirFail {
2094 fn __dir__(&self) -> PyResult<Py<PyAny>> {
2095 Err(PyValueError::new_err("uh-oh!"))
2096 }
2097 }
2098
2099 Python::attach(|py| {
2100 let obj = Bound::new(py, DirFail).unwrap();
2101 assert!(obj.dir().unwrap_err().is_instance_of::<PyValueError>(py));
2102 })
2103 }
2104}