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