1use crate::call::PyCallArgs;
2use crate::class::basic::CompareOp;
3use crate::conversion::{FromPyObject, IntoPyObject};
4use crate::err::{error_on_minusone, PyErr, PyResult};
5use crate::exceptions::PyTypeError;
6use crate::ffi_ptr_ext::FfiPtrExt;
7use crate::impl_::pycell::PyStaticClassObject;
8use crate::instance::Bound;
9use crate::internal::get_slot::TP_DESCR_GET;
10use crate::py_result_ext::PyResultExt;
11use crate::type_object::{PyTypeCheck, PyTypeInfo};
12use crate::types::PySuper;
13use crate::types::{PyDict, PyIterator, PyList, PyString, PyType};
14use crate::{err, ffi, Borrowed, BoundObject, IntoPyObjectExt, Py};
15#[cfg(RustPython)]
16use crate::{sync::PyOnceLock, types::typeobject::PyTypeMethods};
17#[allow(deprecated)]
18use crate::{DowncastError, DowncastIntoError};
19use core::cell::UnsafeCell;
20use core::cmp::Ordering;
21use core::ffi::c_int;
22use core::ptr;
23
24#[doc = concat!("[the guide](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/types.html#concrete-python-types)")]
34#[repr(transparent)]
36pub struct PyAny(UnsafeCell<ffi::PyObject>);
37
38#[allow(non_snake_case)]
39fn PyObject_Check(_: *mut ffi::PyObject) -> c_int {
42 1
43}
44
45#[cfg(not(RustPython))]
47pyobject_native_type_info!(
48 PyAny,
49 pyobject_native_static_type_object!(ffi::PyBaseObject_Type),
50 "typing",
51 "Any",
52 Some("builtins"),
53 #checkfunction=PyObject_Check
54);
55
56#[cfg(RustPython)]
57pyobject_native_type_info!(
58 PyAny,
59 |py| {
60 static TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
61 TYPE.import(py, "builtins", "object").unwrap().as_type_ptr()
62 },
63 "typing",
64 "Any",
65 Some("builtins"),
66 #checkfunction=PyObject_Check
67);
68
69pyobject_native_type_sized!(PyAny, ffi::PyObject);
70impl crate::impl_::pyclass::PyClassBaseType for PyAny {
72 type LayoutAsBase = crate::impl_::pycell::PyClassObjectBase<ffi::PyObject>;
73 type BaseNativeType = PyAny;
74 type Initializer = crate::impl_::pyclass_init::PyNativeTypeInitializer<Self>;
75 type PyClassMutability = crate::pycell::impl_::ImmutableClass;
76 type Layout<T: crate::impl_::pyclass::PyClassImpl> = PyStaticClassObject<T>;
77}
78
79#[doc(alias = "PyAny")]
84pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
85 fn is<T: AsRef<Py<PyAny>>>(&self, other: T) -> bool;
90
91 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
114 where
115 N: IntoPyObject<'py, Target = PyString>;
116
117 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
140 where
141 N: IntoPyObject<'py, Target = PyString>;
142
143 fn getattr_opt<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
172 where
173 N: IntoPyObject<'py, Target = PyString>;
174
175 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
198 where
199 N: IntoPyObject<'py, Target = PyString>,
200 V: IntoPyObject<'py>;
201
202 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
209 where
210 N: IntoPyObject<'py, Target = PyString>;
211
212 fn compare<O>(&self, other: O) -> PyResult<Ordering>
259 where
260 O: IntoPyObject<'py>;
261
262 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
296 where
297 O: IntoPyObject<'py>;
298
299 fn neg(&self) -> PyResult<Bound<'py, PyAny>>;
303
304 fn pos(&self) -> PyResult<Bound<'py, PyAny>>;
308
309 fn abs(&self) -> PyResult<Bound<'py, PyAny>>;
313
314 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>>;
316
317 fn lt<O>(&self, other: O) -> PyResult<bool>
321 where
322 O: IntoPyObject<'py>;
323
324 fn le<O>(&self, other: O) -> PyResult<bool>
328 where
329 O: IntoPyObject<'py>;
330
331 fn eq<O>(&self, other: O) -> PyResult<bool>
335 where
336 O: IntoPyObject<'py>;
337
338 fn ne<O>(&self, other: O) -> PyResult<bool>
342 where
343 O: IntoPyObject<'py>;
344
345 fn gt<O>(&self, other: O) -> PyResult<bool>
349 where
350 O: IntoPyObject<'py>;
351
352 fn ge<O>(&self, other: O) -> PyResult<bool>
356 where
357 O: IntoPyObject<'py>;
358
359 fn add<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
361 where
362 O: IntoPyObject<'py>;
363
364 fn sub<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
366 where
367 O: IntoPyObject<'py>;
368
369 fn mul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
371 where
372 O: IntoPyObject<'py>;
373
374 fn matmul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
376 where
377 O: IntoPyObject<'py>;
378
379 fn div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
381 where
382 O: IntoPyObject<'py>;
383
384 fn floor_div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
386 where
387 O: IntoPyObject<'py>;
388
389 fn rem<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
391 where
392 O: IntoPyObject<'py>;
393
394 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
396 where
397 O: IntoPyObject<'py>;
398
399 fn lshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
401 where
402 O: IntoPyObject<'py>;
403
404 fn rshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
406 where
407 O: IntoPyObject<'py>;
408
409 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
412 where
413 O1: IntoPyObject<'py>,
414 O2: IntoPyObject<'py>;
415
416 fn bitand<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
418 where
419 O: IntoPyObject<'py>;
420
421 fn bitor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
423 where
424 O: IntoPyObject<'py>;
425
426 fn bitxor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
428 where
429 O: IntoPyObject<'py>;
430
431 fn is_callable(&self) -> bool;
459
460 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
493 where
494 A: PyCallArgs<'py>;
495
496 fn call0(&self) -> PyResult<Bound<'py, PyAny>>;
517
518 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
548 where
549 A: PyCallArgs<'py>;
550
551 fn call_method<N, A>(
589 &self,
590 name: N,
591 args: A,
592 kwargs: Option<&Bound<'py, PyDict>>,
593 ) -> PyResult<Bound<'py, PyAny>>
594 where
595 N: IntoPyObject<'py, Target = PyString>,
596 A: PyCallArgs<'py>;
597
598 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
632 where
633 N: IntoPyObject<'py, Target = PyString>;
634
635 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
670 where
671 N: IntoPyObject<'py, Target = PyString>,
672 A: PyCallArgs<'py>;
673
674 fn is_truthy(&self) -> PyResult<bool>;
678
679 fn is_none(&self) -> bool;
683
684 fn is_empty(&self) -> PyResult<bool>;
688
689 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
693 where
694 K: IntoPyObject<'py>;
695
696 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
700 where
701 K: IntoPyObject<'py>,
702 V: IntoPyObject<'py>;
703
704 fn del_item<K>(&self, key: K) -> PyResult<()>
708 where
709 K: IntoPyObject<'py>;
710
711 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>>;
736
737 fn get_type(&self) -> Bound<'py, PyType>;
739
740 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject;
742
743 #[deprecated(since = "0.27.0", note = "use `Bound::cast` instead")]
798 #[allow(deprecated)]
799 fn downcast<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
800 where
801 T: PyTypeCheck;
802
803 #[deprecated(since = "0.27.0", note = "use `Bound::cast_into` instead")]
827 #[allow(deprecated)]
828 fn downcast_into<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
829 where
830 T: PyTypeCheck;
831
832 #[deprecated(since = "0.27.0", note = "use `Bound::cast_exact` instead")]
864 #[allow(deprecated)]
865 fn downcast_exact<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
866 where
867 T: PyTypeInfo;
868
869 #[deprecated(since = "0.27.0", note = "use `Bound::cast_into_exact` instead")]
871 #[allow(deprecated)]
872 fn downcast_into_exact<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
873 where
874 T: PyTypeInfo;
875
876 #[deprecated(since = "0.27.0", note = "use `Bound::cast_unchecked` instead")]
882 unsafe fn downcast_unchecked<T>(&self) -> &Bound<'py, T>;
883
884 #[deprecated(since = "0.27.0", note = "use `Bound::cast_into_unchecked` instead")]
890 unsafe fn downcast_into_unchecked<T>(self) -> Bound<'py, T>;
891
892 fn extract<'a, T>(&'a self) -> Result<T, T::Error>
896 where
897 T: FromPyObject<'a, 'py>;
898
899 #[deprecated(
901 since = "0.29.0",
902 note = "use `pyo3::ffi::Py_REFCNT(obj.as_ptr())` instead"
903 )]
904 fn get_refcnt(&self) -> isize;
905
906 fn repr(&self) -> PyResult<Bound<'py, PyString>>;
910
911 fn str(&self) -> PyResult<Bound<'py, PyString>>;
915
916 fn hash(&self) -> PyResult<isize>;
920
921 fn len(&self) -> PyResult<usize>;
925
926 fn dir(&self) -> PyResult<Bound<'py, PyList>>;
930
931 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool>;
935
936 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool;
940
941 fn is_instance_of<T: PyTypeCheck>(&self) -> bool;
946
947 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool;
952
953 fn contains<V>(&self, value: V) -> PyResult<bool>
957 where
958 V: IntoPyObject<'py>;
959
960 fn py_super(&self) -> PyResult<Bound<'py, PySuper>>;
964}
965
966macro_rules! implement_binop {
967 ($name:ident, $c_api:ident, $op:expr) => {
968 #[doc = concat!("Computes `self ", $op, " other`.")]
969 fn $name<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
970 where
971 O: IntoPyObject<'py>,
972 {
973 fn inner<'py>(
974 any: &Bound<'py, PyAny>,
975 other: Borrowed<'_, 'py, PyAny>,
976 ) -> PyResult<Bound<'py, PyAny>> {
977 unsafe { ffi::$c_api(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py()) }
978 }
979
980 let py = self.py();
981 inner(
982 self,
983 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
984 )
985 }
986 };
987}
988
989impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
990 #[inline]
991 fn is<T: AsRef<Py<PyAny>>>(&self, other: T) -> bool {
992 ptr::eq(self.as_ptr(), other.as_ref().as_ptr())
993 }
994
995 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
996 where
997 N: IntoPyObject<'py, Target = PyString>,
998 {
999 fn inner<'py>(
1000 any: &Bound<'py, PyAny>,
1001 attr_name: Borrowed<'_, '_, PyString>,
1002 ) -> PyResult<bool> {
1003 let result =
1004 unsafe { ffi::compat::PyObject_HasAttrWithError(any.as_ptr(), attr_name.as_ptr()) };
1005 error_on_minusone(any.py(), result)?;
1006 Ok(result > 0)
1007 }
1008
1009 inner(
1010 self,
1011 attr_name
1012 .into_pyobject(self.py())
1013 .map_err(Into::into)?
1014 .as_borrowed(),
1015 )
1016 }
1017
1018 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
1019 where
1020 N: IntoPyObject<'py, Target = PyString>,
1021 {
1022 fn inner<'py>(
1023 any: &Bound<'py, PyAny>,
1024 attr_name: Borrowed<'_, '_, PyString>,
1025 ) -> PyResult<Bound<'py, PyAny>> {
1026 unsafe {
1027 ffi::PyObject_GetAttr(any.as_ptr(), attr_name.as_ptr())
1028 .assume_owned_or_err(any.py())
1029 }
1030 }
1031
1032 inner(
1033 self,
1034 attr_name
1035 .into_pyobject(self.py())
1036 .map_err(Into::into)?
1037 .as_borrowed(),
1038 )
1039 }
1040
1041 fn getattr_opt<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
1042 where
1043 N: IntoPyObject<'py, Target = PyString>,
1044 {
1045 fn inner<'py>(
1046 any: &Bound<'py, PyAny>,
1047 attr_name: Borrowed<'_, 'py, PyString>,
1048 ) -> PyResult<Option<Bound<'py, PyAny>>> {
1049 let mut resp_ptr: *mut ffi::PyObject = core::ptr::null_mut();
1050 match unsafe {
1051 ffi::compat::PyObject_GetOptionalAttr(
1052 any.as_ptr(),
1053 attr_name.as_ptr(),
1054 &mut resp_ptr,
1055 )
1056 } {
1057 1 => Ok(Some(unsafe { Bound::from_owned_ptr(any.py(), resp_ptr) })),
1059 0 => Ok(None),
1061 _ => Err(PyErr::fetch(any.py())),
1063 }
1064 }
1065
1066 let py = self.py();
1067 inner(self, attr_name.into_pyobject_or_pyerr(py)?.as_borrowed())
1068 }
1069
1070 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
1071 where
1072 N: IntoPyObject<'py, Target = PyString>,
1073 V: IntoPyObject<'py>,
1074 {
1075 fn inner(
1076 any: &Bound<'_, PyAny>,
1077 attr_name: Borrowed<'_, '_, PyString>,
1078 value: Borrowed<'_, '_, PyAny>,
1079 ) -> PyResult<()> {
1080 err::error_on_minusone(any.py(), unsafe {
1081 ffi::PyObject_SetAttr(any.as_ptr(), attr_name.as_ptr(), value.as_ptr())
1082 })
1083 }
1084
1085 let py = self.py();
1086 inner(
1087 self,
1088 attr_name.into_pyobject_or_pyerr(py)?.as_borrowed(),
1089 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1090 )
1091 }
1092
1093 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
1094 where
1095 N: IntoPyObject<'py, Target = PyString>,
1096 {
1097 fn inner(any: &Bound<'_, PyAny>, attr_name: Borrowed<'_, '_, PyString>) -> PyResult<()> {
1098 err::error_on_minusone(any.py(), unsafe {
1099 ffi::PyObject_DelAttr(any.as_ptr(), attr_name.as_ptr())
1100 })
1101 }
1102
1103 let py = self.py();
1104 inner(self, attr_name.into_pyobject_or_pyerr(py)?.as_borrowed())
1105 }
1106
1107 fn compare<O>(&self, other: O) -> PyResult<Ordering>
1108 where
1109 O: IntoPyObject<'py>,
1110 {
1111 fn inner(any: &Bound<'_, PyAny>, other: Borrowed<'_, '_, PyAny>) -> PyResult<Ordering> {
1112 let other = other.as_ptr();
1113 let do_compare = |other, op| unsafe {
1116 ffi::PyObject_RichCompare(any.as_ptr(), other, op)
1117 .assume_owned_or_err(any.py())
1118 .and_then(|obj| obj.is_truthy())
1119 };
1120 if do_compare(other, ffi::Py_EQ)? {
1121 Ok(Ordering::Equal)
1122 } else if do_compare(other, ffi::Py_LT)? {
1123 Ok(Ordering::Less)
1124 } else if do_compare(other, ffi::Py_GT)? {
1125 Ok(Ordering::Greater)
1126 } else {
1127 Err(PyTypeError::new_err(
1128 "PyAny::compare(): All comparisons returned false",
1129 ))
1130 }
1131 }
1132
1133 let py = self.py();
1134 inner(
1135 self,
1136 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1137 )
1138 }
1139
1140 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
1141 where
1142 O: IntoPyObject<'py>,
1143 {
1144 fn inner<'py>(
1145 any: &Bound<'py, PyAny>,
1146 other: Borrowed<'_, 'py, PyAny>,
1147 compare_op: CompareOp,
1148 ) -> PyResult<Bound<'py, PyAny>> {
1149 unsafe {
1150 ffi::PyObject_RichCompare(any.as_ptr(), other.as_ptr(), compare_op as c_int)
1151 .assume_owned_or_err(any.py())
1152 }
1153 }
1154
1155 let py = self.py();
1156 inner(
1157 self,
1158 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1159 compare_op,
1160 )
1161 }
1162
1163 fn neg(&self) -> PyResult<Bound<'py, PyAny>> {
1164 unsafe { ffi::PyNumber_Negative(self.as_ptr()).assume_owned_or_err(self.py()) }
1165 }
1166
1167 fn pos(&self) -> PyResult<Bound<'py, PyAny>> {
1168 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1169 unsafe { ffi::PyNumber_Positive(any.as_ptr()).assume_owned_or_err(any.py()) }
1170 }
1171
1172 inner(self)
1173 }
1174
1175 fn abs(&self) -> PyResult<Bound<'py, PyAny>> {
1176 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1177 unsafe { ffi::PyNumber_Absolute(any.as_ptr()).assume_owned_or_err(any.py()) }
1178 }
1179
1180 inner(self)
1181 }
1182
1183 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>> {
1184 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
1185 unsafe { ffi::PyNumber_Invert(any.as_ptr()).assume_owned_or_err(any.py()) }
1186 }
1187
1188 inner(self)
1189 }
1190
1191 fn lt<O>(&self, other: O) -> PyResult<bool>
1192 where
1193 O: IntoPyObject<'py>,
1194 {
1195 self.rich_compare(other, CompareOp::Lt)
1196 .and_then(|any| any.is_truthy())
1197 }
1198
1199 fn le<O>(&self, other: O) -> PyResult<bool>
1200 where
1201 O: IntoPyObject<'py>,
1202 {
1203 self.rich_compare(other, CompareOp::Le)
1204 .and_then(|any| any.is_truthy())
1205 }
1206
1207 fn eq<O>(&self, other: O) -> PyResult<bool>
1208 where
1209 O: IntoPyObject<'py>,
1210 {
1211 self.rich_compare(other, CompareOp::Eq)
1212 .and_then(|any| any.is_truthy())
1213 }
1214
1215 fn ne<O>(&self, other: O) -> PyResult<bool>
1216 where
1217 O: IntoPyObject<'py>,
1218 {
1219 self.rich_compare(other, CompareOp::Ne)
1220 .and_then(|any| any.is_truthy())
1221 }
1222
1223 fn gt<O>(&self, other: O) -> PyResult<bool>
1224 where
1225 O: IntoPyObject<'py>,
1226 {
1227 self.rich_compare(other, CompareOp::Gt)
1228 .and_then(|any| any.is_truthy())
1229 }
1230
1231 fn ge<O>(&self, other: O) -> PyResult<bool>
1232 where
1233 O: IntoPyObject<'py>,
1234 {
1235 self.rich_compare(other, CompareOp::Ge)
1236 .and_then(|any| any.is_truthy())
1237 }
1238
1239 implement_binop!(add, PyNumber_Add, "+");
1240 implement_binop!(sub, PyNumber_Subtract, "-");
1241 implement_binop!(mul, PyNumber_Multiply, "*");
1242 implement_binop!(matmul, PyNumber_MatrixMultiply, "@");
1243 implement_binop!(div, PyNumber_TrueDivide, "/");
1244 implement_binop!(floor_div, PyNumber_FloorDivide, "//");
1245 implement_binop!(rem, PyNumber_Remainder, "%");
1246 implement_binop!(lshift, PyNumber_Lshift, "<<");
1247 implement_binop!(rshift, PyNumber_Rshift, ">>");
1248 implement_binop!(bitand, PyNumber_And, "&");
1249 implement_binop!(bitor, PyNumber_Or, "|");
1250 implement_binop!(bitxor, PyNumber_Xor, "^");
1251
1252 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
1254 where
1255 O: IntoPyObject<'py>,
1256 {
1257 fn inner<'py>(
1258 any: &Bound<'py, PyAny>,
1259 other: Borrowed<'_, 'py, PyAny>,
1260 ) -> PyResult<Bound<'py, PyAny>> {
1261 unsafe {
1262 ffi::PyNumber_Divmod(any.as_ptr(), other.as_ptr()).assume_owned_or_err(any.py())
1263 }
1264 }
1265
1266 let py = self.py();
1267 inner(
1268 self,
1269 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1270 )
1271 }
1272
1273 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
1276 where
1277 O1: IntoPyObject<'py>,
1278 O2: IntoPyObject<'py>,
1279 {
1280 fn inner<'py>(
1281 any: &Bound<'py, PyAny>,
1282 other: Borrowed<'_, 'py, PyAny>,
1283 modulus: Borrowed<'_, 'py, PyAny>,
1284 ) -> PyResult<Bound<'py, PyAny>> {
1285 unsafe {
1286 ffi::PyNumber_Power(any.as_ptr(), other.as_ptr(), modulus.as_ptr())
1287 .assume_owned_or_err(any.py())
1288 }
1289 }
1290
1291 let py = self.py();
1292 inner(
1293 self,
1294 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1295 modulus.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1296 )
1297 }
1298
1299 fn is_callable(&self) -> bool {
1300 unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 }
1301 }
1302
1303 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
1304 where
1305 A: PyCallArgs<'py>,
1306 {
1307 if let Some(kwargs) = kwargs {
1308 args.call(
1309 self.as_borrowed(),
1310 kwargs.as_borrowed(),
1311 crate::call::private::Token,
1312 )
1313 } else {
1314 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1315 }
1316 }
1317
1318 #[inline]
1319 fn call0(&self) -> PyResult<Bound<'py, PyAny>> {
1320 unsafe { ffi::compat::PyObject_CallNoArgs(self.as_ptr()).assume_owned_or_err(self.py()) }
1321 }
1322
1323 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
1324 where
1325 A: PyCallArgs<'py>,
1326 {
1327 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1328 }
1329
1330 #[inline]
1331 fn call_method<N, A>(
1332 &self,
1333 name: N,
1334 args: A,
1335 kwargs: Option<&Bound<'py, PyDict>>,
1336 ) -> PyResult<Bound<'py, PyAny>>
1337 where
1338 N: IntoPyObject<'py, Target = PyString>,
1339 A: PyCallArgs<'py>,
1340 {
1341 if kwargs.is_none() {
1342 self.call_method1(name, args)
1343 } else {
1344 self.getattr(name)
1345 .and_then(|method| method.call(args, kwargs))
1346 }
1347 }
1348
1349 #[inline]
1350 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
1351 where
1352 N: IntoPyObject<'py, Target = PyString>,
1353 {
1354 let py = self.py();
1355 let name = name.into_pyobject_or_pyerr(py)?.into_bound();
1356 unsafe {
1357 ffi::compat::PyObject_CallMethodNoArgs(self.as_ptr(), name.as_ptr())
1358 .assume_owned_or_err(py)
1359 }
1360 }
1361
1362 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
1363 where
1364 N: IntoPyObject<'py, Target = PyString>,
1365 A: PyCallArgs<'py>,
1366 {
1367 let name = name.into_pyobject_or_pyerr(self.py())?;
1368 args.call_method_positional(
1369 self.as_borrowed(),
1370 name.as_borrowed(),
1371 crate::call::private::Token,
1372 )
1373 }
1374
1375 fn is_truthy(&self) -> PyResult<bool> {
1376 let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
1377 err::error_on_minusone(self.py(), v)?;
1378 Ok(v != 0)
1379 }
1380
1381 #[inline]
1382 fn is_none(&self) -> bool {
1383 unsafe { ptr::eq(ffi::Py_None(), self.as_ptr()) }
1384 }
1385
1386 fn is_empty(&self) -> PyResult<bool> {
1387 self.len().map(|l| l == 0)
1388 }
1389
1390 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
1391 where
1392 K: IntoPyObject<'py>,
1393 {
1394 fn inner<'py>(
1395 any: &Bound<'py, PyAny>,
1396 key: Borrowed<'_, 'py, PyAny>,
1397 ) -> PyResult<Bound<'py, PyAny>> {
1398 unsafe {
1399 ffi::PyObject_GetItem(any.as_ptr(), key.as_ptr()).assume_owned_or_err(any.py())
1400 }
1401 }
1402
1403 let py = self.py();
1404 inner(
1405 self,
1406 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1407 )
1408 }
1409
1410 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
1411 where
1412 K: IntoPyObject<'py>,
1413 V: IntoPyObject<'py>,
1414 {
1415 fn inner(
1416 any: &Bound<'_, PyAny>,
1417 key: Borrowed<'_, '_, PyAny>,
1418 value: Borrowed<'_, '_, PyAny>,
1419 ) -> PyResult<()> {
1420 err::error_on_minusone(any.py(), unsafe {
1421 ffi::PyObject_SetItem(any.as_ptr(), key.as_ptr(), value.as_ptr())
1422 })
1423 }
1424
1425 let py = self.py();
1426 inner(
1427 self,
1428 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1429 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1430 )
1431 }
1432
1433 fn del_item<K>(&self, key: K) -> PyResult<()>
1434 where
1435 K: IntoPyObject<'py>,
1436 {
1437 fn inner(any: &Bound<'_, PyAny>, key: Borrowed<'_, '_, PyAny>) -> PyResult<()> {
1438 err::error_on_minusone(any.py(), unsafe {
1439 ffi::PyObject_DelItem(any.as_ptr(), key.as_ptr())
1440 })
1441 }
1442
1443 let py = self.py();
1444 inner(
1445 self,
1446 key.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1447 )
1448 }
1449
1450 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>> {
1451 PyIterator::from_object(self)
1452 }
1453
1454 fn get_type(&self) -> Bound<'py, PyType> {
1455 unsafe { PyType::from_borrowed_type_ptr(self.py(), ffi::Py_TYPE(self.as_ptr())) }
1456 }
1457
1458 #[inline]
1459 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject {
1460 unsafe { ffi::Py_TYPE(self.as_ptr()) }
1461 }
1462
1463 #[inline]
1464 #[allow(deprecated)]
1465 fn downcast<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
1466 where
1467 T: PyTypeCheck,
1468 {
1469 if T::type_check(self) {
1470 Ok(unsafe { self.cast_unchecked() })
1472 } else {
1473 #[allow(deprecated)]
1474 Err(DowncastError::new(self, T::NAME))
1475 }
1476 }
1477
1478 #[inline]
1479 #[allow(deprecated)]
1480 fn downcast_into<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
1481 where
1482 T: PyTypeCheck,
1483 {
1484 if T::type_check(&self) {
1485 Ok(unsafe { self.cast_into_unchecked() })
1487 } else {
1488 #[allow(deprecated)]
1489 Err(DowncastIntoError::new(self, T::NAME))
1490 }
1491 }
1492
1493 #[inline]
1494 #[allow(deprecated)]
1495 fn downcast_exact<T>(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>>
1496 where
1497 T: PyTypeInfo,
1498 {
1499 if T::is_exact_type_of(self) {
1500 Ok(unsafe { self.cast_unchecked() })
1502 } else {
1503 #[allow(deprecated)]
1504 Err(DowncastError::new(self, T::NAME))
1505 }
1506 }
1507
1508 #[inline]
1509 #[allow(deprecated)]
1510 fn downcast_into_exact<T>(self) -> Result<Bound<'py, T>, DowncastIntoError<'py>>
1511 where
1512 T: PyTypeInfo,
1513 {
1514 if T::is_exact_type_of(&self) {
1515 Ok(unsafe { self.cast_into_unchecked() })
1517 } else {
1518 #[allow(deprecated)]
1519 Err(DowncastIntoError::new(self, T::NAME))
1520 }
1521 }
1522
1523 #[inline]
1524 unsafe fn downcast_unchecked<T>(&self) -> &Bound<'py, T> {
1525 unsafe { self.cast_unchecked() }
1526 }
1527
1528 #[inline]
1529 unsafe fn downcast_into_unchecked<T>(self) -> Bound<'py, T> {
1530 unsafe { self.cast_into_unchecked() }
1531 }
1532
1533 fn extract<'a, T>(&'a self) -> Result<T, T::Error>
1534 where
1535 T: FromPyObject<'a, 'py>,
1536 {
1537 FromPyObject::extract(self.as_borrowed())
1538 }
1539
1540 fn get_refcnt(&self) -> isize {
1541 self._get_refcnt()
1542 }
1543
1544 fn repr(&self) -> PyResult<Bound<'py, PyString>> {
1545 unsafe {
1546 ffi::PyObject_Repr(self.as_ptr())
1547 .assume_owned_or_err(self.py())
1548 .cast_into_unchecked()
1549 }
1550 }
1551
1552 fn str(&self) -> PyResult<Bound<'py, PyString>> {
1553 unsafe {
1554 ffi::PyObject_Str(self.as_ptr())
1555 .assume_owned_or_err(self.py())
1556 .cast_into_unchecked()
1557 }
1558 }
1559
1560 fn hash(&self) -> PyResult<isize> {
1561 let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) };
1562 crate::err::error_on_minusone(self.py(), v)?;
1563 Ok(v)
1564 }
1565
1566 fn len(&self) -> PyResult<usize> {
1567 let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
1568 crate::err::error_on_minusone(self.py(), v)?;
1569 Ok(v as usize)
1570 }
1571
1572 fn dir(&self) -> PyResult<Bound<'py, PyList>> {
1573 unsafe {
1574 ffi::PyObject_Dir(self.as_ptr())
1575 .assume_owned_or_err(self.py())
1576 .cast_into_unchecked()
1577 }
1578 }
1579
1580 #[inline]
1581 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool> {
1582 let result = unsafe { ffi::PyObject_IsInstance(self.as_ptr(), ty.as_ptr()) };
1583 err::error_on_minusone(self.py(), result)?;
1584 Ok(result == 1)
1585 }
1586
1587 #[inline]
1588 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool {
1589 self.get_type().is(ty)
1590 }
1591
1592 #[inline]
1593 fn is_instance_of<T: PyTypeCheck>(&self) -> bool {
1594 T::type_check(self)
1595 }
1596
1597 #[inline]
1598 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool {
1599 T::is_exact_type_of(self)
1600 }
1601
1602 fn contains<V>(&self, value: V) -> PyResult<bool>
1603 where
1604 V: IntoPyObject<'py>,
1605 {
1606 fn inner(any: &Bound<'_, PyAny>, value: Borrowed<'_, '_, PyAny>) -> PyResult<bool> {
1607 match unsafe { ffi::PySequence_Contains(any.as_ptr(), value.as_ptr()) } {
1608 0 => Ok(false),
1609 1 => Ok(true),
1610 _ => Err(PyErr::fetch(any.py())),
1611 }
1612 }
1613
1614 let py = self.py();
1615 inner(
1616 self,
1617 value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
1618 )
1619 }
1620
1621 fn py_super(&self) -> PyResult<Bound<'py, PySuper>> {
1622 PySuper::new(&self.get_type(), self)
1623 }
1624}
1625
1626impl<'py> Bound<'py, PyAny> {
1627 #[allow(dead_code, reason = "currently only used with num-complex + abi3")]
1638 pub(crate) fn lookup_special<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
1639 where
1640 N: IntoPyObject<'py, Target = PyString>,
1641 {
1642 let py = self.py();
1643 let self_type = self.get_type();
1644 let attr = if let Ok(attr) = self_type.getattr(attr_name) {
1645 attr
1646 } else {
1647 return Ok(None);
1648 };
1649
1650 if let Some(descr_get) = attr.get_type().get_slot(TP_DESCR_GET) {
1652 unsafe {
1654 descr_get(attr.as_ptr(), self.as_ptr(), self_type.as_ptr())
1655 .assume_owned_or_err(py)
1656 .map(Some)
1657 }
1658 } else {
1659 Ok(Some(attr))
1660 }
1661 }
1662
1663 #[inline]
1664 pub(crate) fn _get_refcnt(&self) -> isize {
1665 unsafe { ffi::Py_REFCNT(self.as_ptr()) }
1666 }
1667}
1668
1669#[cfg(test)]
1670mod tests {
1671 use crate::{
1672 basic::CompareOp,
1673 test_utils::generate_unique_module_name,
1674 types::{IntoPyDict, PyAny, PyAnyMethods, PyBool, PyInt, PyList, PyModule, PyTypeMethods},
1675 Bound, BoundObject, IntoPyObject, PyTypeInfo, Python,
1676 };
1677 use core::fmt::Debug;
1678 use pyo3_ffi::c_str;
1679
1680 #[test]
1681 fn test_lookup_special() {
1682 Python::attach(|py| {
1683 let module = PyModule::from_code(
1684 py,
1685 cr#"
1686class CustomCallable:
1687 def __call__(self):
1688 return 1
1689
1690class SimpleInt:
1691 def __int__(self):
1692 return 1
1693
1694class InheritedInt(SimpleInt): pass
1695
1696class NoInt: pass
1697
1698class NoDescriptorInt:
1699 __int__ = CustomCallable()
1700
1701class InstanceOverrideInt:
1702 def __int__(self):
1703 return 1
1704instance_override = InstanceOverrideInt()
1705instance_override.__int__ = lambda self: 2
1706
1707class ErrorInDescriptorInt:
1708 @property
1709 def __int__(self):
1710 raise ValueError("uh-oh!")
1711
1712class NonHeapNonDescriptorInt:
1713 # A static-typed callable that doesn't implement `__get__`. These are pretty hard to come by.
1714 __int__ = int
1715 "#,
1716 c"test.py",
1717 &generate_unique_module_name("test"),
1718 )
1719 .unwrap();
1720
1721 let int = crate::intern!(py, "__int__");
1722 let eval_int =
1723 |obj: Bound<'_, PyAny>| obj.lookup_special(int)?.unwrap().call0()?.extract::<u32>();
1724
1725 let simple = module.getattr("SimpleInt").unwrap().call0().unwrap();
1726 assert_eq!(eval_int(simple).unwrap(), 1);
1727 let inherited = module.getattr("InheritedInt").unwrap().call0().unwrap();
1728 assert_eq!(eval_int(inherited).unwrap(), 1);
1729 let no_descriptor = module.getattr("NoDescriptorInt").unwrap().call0().unwrap();
1730 assert_eq!(eval_int(no_descriptor).unwrap(), 1);
1731 let missing = module.getattr("NoInt").unwrap().call0().unwrap();
1732 assert!(missing.lookup_special(int).unwrap().is_none());
1733 let instance_override = module.getattr("instance_override").unwrap();
1736 assert_eq!(eval_int(instance_override).unwrap(), 1);
1737 let descriptor_error = module
1738 .getattr("ErrorInDescriptorInt")
1739 .unwrap()
1740 .call0()
1741 .unwrap();
1742 assert!(descriptor_error.lookup_special(int).is_err());
1743 let nonheap_nondescriptor = module
1744 .getattr("NonHeapNonDescriptorInt")
1745 .unwrap()
1746 .call0()
1747 .unwrap();
1748 assert_eq!(eval_int(nonheap_nondescriptor).unwrap(), 0);
1749 })
1750 }
1751
1752 #[test]
1753 fn test_getattr_opt() {
1754 Python::attach(|py| {
1755 let module = PyModule::from_code(
1756 py,
1757 cr#"
1758class Test:
1759 class_str_attribute = "class_string"
1760
1761 @property
1762 def error(self):
1763 raise ValueError("This is an intentional error")
1764 "#,
1765 c"test.py",
1766 &generate_unique_module_name("test"),
1767 )
1768 .unwrap();
1769
1770 let class_test = module.getattr_opt("Test").unwrap().unwrap();
1772
1773 let cls_attr_str = class_test
1775 .getattr_opt("class_str_attribute")
1776 .unwrap()
1777 .unwrap();
1778 assert_eq!(cls_attr_str.extract::<String>().unwrap(), "class_string");
1779
1780 let do_not_exist = class_test.getattr_opt("doNotExist").unwrap();
1782 assert!(do_not_exist.is_none());
1783
1784 let instance = class_test.call0().unwrap();
1786 let error = instance.getattr_opt("error");
1787 assert!(error.is_err());
1788 assert!(error
1789 .unwrap_err()
1790 .to_string()
1791 .contains("This is an intentional error"));
1792 });
1793 }
1794
1795 #[test]
1796 fn test_getattr_opt_attribute_error_subclass() {
1797 Python::attach(|py| {
1798 let module = PyModule::from_code(
1799 py,
1800 cr#"
1801class CustomAttrError(AttributeError):
1802 pass
1803
1804class Obj:
1805 @property
1806 def missing(self):
1807 raise CustomAttrError("not here")
1808 "#,
1809 c"test.py",
1810 &generate_unique_module_name("test"),
1811 )
1812 .unwrap();
1813
1814 let obj = module.getattr("Obj").unwrap().call0().unwrap();
1815
1816 let result = obj.getattr_opt("missing").unwrap();
1818 assert!(result.is_none());
1819 });
1820 }
1821
1822 #[test]
1823 fn test_call_for_non_existing_method() {
1824 Python::attach(|py| {
1825 let a = py.eval(c"42", None, None).unwrap();
1826 a.call_method0("__str__").unwrap(); assert!(a.call_method("nonexistent_method", (1,), None).is_err());
1828 assert!(a.call_method0("nonexistent_method").is_err());
1829 assert!(a.call_method1("nonexistent_method", (1,)).is_err());
1830 });
1831 }
1832
1833 #[test]
1834 fn test_call_with_kwargs() {
1835 Python::attach(|py| {
1836 let list = vec![3, 6, 5, 4, 7].into_pyobject(py).unwrap();
1837 let dict = vec![("reverse", true)].into_py_dict(py).unwrap();
1838 list.call_method("sort", (), Some(&dict)).unwrap();
1839 assert_eq!(list.extract::<Vec<i32>>().unwrap(), vec![7, 6, 5, 4, 3]);
1840 });
1841 }
1842
1843 #[test]
1844 fn test_call_method0() {
1845 Python::attach(|py| {
1846 let module = PyModule::from_code(
1847 py,
1848 cr#"
1849class SimpleClass:
1850 def foo(self):
1851 return 42
1852"#,
1853 c_str!(file!()),
1854 &generate_unique_module_name("test_module"),
1855 )
1856 .expect("module creation failed");
1857
1858 let simple_class = module.getattr("SimpleClass").unwrap().call0().unwrap();
1859 assert_eq!(
1860 simple_class
1861 .call_method0("foo")
1862 .unwrap()
1863 .extract::<u32>()
1864 .unwrap(),
1865 42
1866 );
1867 })
1868 }
1869
1870 #[test]
1871 fn test_type() {
1872 Python::attach(|py| {
1873 let obj = py.eval(c"42", None, None).unwrap();
1874 assert_eq!(obj.get_type().as_type_ptr(), obj.get_type_ptr());
1875 });
1876 }
1877
1878 #[test]
1879 fn test_dir() {
1880 Python::attach(|py| {
1881 let obj = py.eval(c"42", None, None).unwrap();
1882 let dir = py
1883 .eval(c"dir(42)", None, None)
1884 .unwrap()
1885 .cast_into::<PyList>()
1886 .unwrap();
1887 let a = obj
1888 .dir()
1889 .unwrap()
1890 .into_iter()
1891 .map(|x| x.extract::<String>().unwrap());
1892 let b = dir.into_iter().map(|x| x.extract::<String>().unwrap());
1893 assert!(a.eq(b));
1894 });
1895 }
1896
1897 #[test]
1898 fn test_hasattr() {
1899 Python::attach(|py| {
1900 let x = 5i32.into_pyobject(py).unwrap();
1901 assert!(x.is_instance_of::<PyInt>());
1902
1903 assert!(x.hasattr("to_bytes").unwrap());
1904 assert!(!x.hasattr("bbbbbbytes").unwrap());
1905 })
1906 }
1907
1908 #[cfg(feature = "macros")]
1909 #[test]
1910 #[allow(unknown_lints, non_local_definitions)]
1911 fn test_hasattr_error() {
1912 use crate::exceptions::PyValueError;
1913 use crate::prelude::*;
1914
1915 #[pyclass(crate = "crate")]
1916 struct GetattrFail;
1917
1918 #[pymethods(crate = "crate")]
1919 impl GetattrFail {
1920 fn __getattr__(&self, attr: Py<PyAny>) -> PyResult<Py<PyAny>> {
1921 Err(PyValueError::new_err(attr))
1922 }
1923 }
1924
1925 Python::attach(|py| {
1926 let obj = Py::new(py, GetattrFail).unwrap();
1927 let obj = obj.bind(py).as_any();
1928
1929 assert!(obj
1930 .hasattr("foo")
1931 .unwrap_err()
1932 .is_instance_of::<PyValueError>(py));
1933 })
1934 }
1935
1936 #[test]
1937 fn test_nan_eq() {
1938 Python::attach(|py| {
1939 let nan = py.eval(c"float('nan')", None, None).unwrap();
1940 assert!(nan.compare(&nan).is_err());
1941 });
1942 }
1943
1944 #[test]
1945 fn test_any_is_instance_of() {
1946 Python::attach(|py| {
1947 let x = 5i32.into_pyobject(py).unwrap();
1948 assert!(x.is_instance_of::<PyInt>());
1949
1950 let l = vec![&x, &x].into_pyobject(py).unwrap();
1951 assert!(l.is_instance_of::<PyList>());
1952 });
1953 }
1954
1955 #[test]
1956 fn test_any_is_instance() {
1957 Python::attach(|py| {
1958 let l = vec![1i8, 2].into_pyobject(py).unwrap();
1959 assert!(l.is_instance(&py.get_type::<PyList>()).unwrap());
1960 });
1961 }
1962
1963 #[test]
1964 fn test_any_is_exact_instance_of() {
1965 Python::attach(|py| {
1966 let x = 5i32.into_pyobject(py).unwrap();
1967 assert!(x.is_exact_instance_of::<PyInt>());
1968
1969 let t = PyBool::new(py, true);
1970 assert!(t.is_instance_of::<PyInt>());
1971 assert!(!t.is_exact_instance_of::<PyInt>());
1972 assert!(t.is_exact_instance_of::<PyBool>());
1973
1974 let l = vec![&x, &x].into_pyobject(py).unwrap();
1975 assert!(l.is_exact_instance_of::<PyList>());
1976 });
1977 }
1978
1979 #[test]
1980 fn test_any_is_exact_instance() {
1981 Python::attach(|py| {
1982 let t = PyBool::new(py, true);
1983 assert!(t.is_instance(&py.get_type::<PyInt>()).unwrap());
1984 assert!(!t.is_exact_instance(&py.get_type::<PyInt>()));
1985 assert!(t.is_exact_instance(&py.get_type::<PyBool>()));
1986 });
1987 }
1988
1989 #[test]
1990 fn test_any_contains() {
1991 Python::attach(|py| {
1992 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
1993 let ob = v.into_pyobject(py).unwrap();
1994
1995 let bad_needle = 7i32.into_pyobject(py).unwrap();
1996 assert!(!ob.contains(&bad_needle).unwrap());
1997
1998 let good_needle = 8i32.into_pyobject(py).unwrap();
1999 assert!(ob.contains(&good_needle).unwrap());
2000
2001 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
2002 assert!(ob.contains(&type_coerced_needle).unwrap());
2003
2004 let n: u32 = 42;
2005 let bad_haystack = n.into_pyobject(py).unwrap();
2006 let irrelevant_needle = 0i32.into_pyobject(py).unwrap();
2007 assert!(bad_haystack.contains(&irrelevant_needle).is_err());
2008 });
2009 }
2010
2011 fn test_eq_methods_generic<'a, T>(list: &'a [T])
2013 where
2014 T: PartialEq + PartialOrd,
2015 for<'py> &'a T: IntoPyObject<'py>,
2016 for<'py> <&'a T as IntoPyObject<'py>>::Error: Debug,
2017 {
2018 Python::attach(|py| {
2019 for a in list {
2020 for b in list {
2021 let a_py = a.into_pyobject(py).unwrap().into_any().into_bound();
2022 let b_py = b.into_pyobject(py).unwrap().into_any().into_bound();
2023
2024 assert_eq!(
2025 a.lt(b),
2026 a_py.lt(&b_py).unwrap(),
2027 "{} < {} should be {}.",
2028 a_py,
2029 b_py,
2030 a.lt(b)
2031 );
2032 assert_eq!(
2033 a.le(b),
2034 a_py.le(&b_py).unwrap(),
2035 "{} <= {} should be {}.",
2036 a_py,
2037 b_py,
2038 a.le(b)
2039 );
2040 assert_eq!(
2041 a.eq(b),
2042 a_py.eq(&b_py).unwrap(),
2043 "{} == {} should be {}.",
2044 a_py,
2045 b_py,
2046 a.eq(b)
2047 );
2048 assert_eq!(
2049 a.ne(b),
2050 a_py.ne(&b_py).unwrap(),
2051 "{} != {} should be {}.",
2052 a_py,
2053 b_py,
2054 a.ne(b)
2055 );
2056 assert_eq!(
2057 a.gt(b),
2058 a_py.gt(&b_py).unwrap(),
2059 "{} > {} should be {}.",
2060 a_py,
2061 b_py,
2062 a.gt(b)
2063 );
2064 assert_eq!(
2065 a.ge(b),
2066 a_py.ge(&b_py).unwrap(),
2067 "{} >= {} should be {}.",
2068 a_py,
2069 b_py,
2070 a.ge(b)
2071 );
2072 }
2073 }
2074 });
2075 }
2076
2077 #[test]
2078 fn test_eq_methods_integers() {
2079 let ints = [-4, -4, 1, 2, 0, -100, 1_000_000];
2080 test_eq_methods_generic::<i32>(&ints);
2081 }
2082
2083 #[test]
2084 fn test_eq_methods_strings() {
2085 let strings = ["Let's", "test", "some", "eq", "methods"];
2086 test_eq_methods_generic::<&str>(&strings);
2087 }
2088
2089 #[test]
2090 fn test_eq_methods_floats() {
2091 let floats = [
2092 -1.0,
2093 2.5,
2094 0.0,
2095 3.0,
2096 core::f64::consts::PI,
2097 10.0,
2098 10.0 / 3.0,
2099 -1_000_000.0,
2100 ];
2101 test_eq_methods_generic::<f64>(&floats);
2102 }
2103
2104 #[test]
2105 fn test_eq_methods_bools() {
2106 let bools = [true, false];
2107 test_eq_methods_generic::<bool>(&bools);
2108 }
2109
2110 #[test]
2111 fn test_rich_compare_type_error() {
2112 Python::attach(|py| {
2113 let py_int = 1i32.into_pyobject(py).unwrap();
2114 let py_str = "1".into_pyobject(py).unwrap();
2115
2116 assert!(py_int.rich_compare(&py_str, CompareOp::Lt).is_err());
2117 assert!(!py_int
2118 .rich_compare(py_str, CompareOp::Eq)
2119 .unwrap()
2120 .is_truthy()
2121 .unwrap());
2122 })
2123 }
2124
2125 #[test]
2126 fn test_is_callable() {
2127 Python::attach(|py| {
2128 assert!(PyList::type_object(py).is_callable());
2129
2130 let not_callable = 5i32.into_pyobject(py).unwrap();
2131 assert!(!not_callable.is_callable());
2132 });
2133 }
2134
2135 #[test]
2136 fn test_is_empty() {
2137 Python::attach(|py| {
2138 let empty_list = PyList::empty(py).into_any();
2139 assert!(empty_list.is_empty().unwrap());
2140
2141 let list = PyList::new(py, vec![1, 2, 3]).unwrap().into_any();
2142 assert!(!list.is_empty().unwrap());
2143
2144 let not_container = 5i32.into_pyobject(py).unwrap();
2145 assert!(not_container.is_empty().is_err());
2146 });
2147 }
2148
2149 #[cfg(feature = "macros")]
2150 #[test]
2151 #[allow(unknown_lints, non_local_definitions)]
2152 fn test_fallible_dir() {
2153 use crate::exceptions::PyValueError;
2154 use crate::prelude::*;
2155
2156 #[pyclass(crate = "crate")]
2157 struct DirFail;
2158
2159 #[pymethods(crate = "crate")]
2160 impl DirFail {
2161 fn __dir__(&self) -> PyResult<Py<PyAny>> {
2162 Err(PyValueError::new_err("uh-oh!"))
2163 }
2164 }
2165
2166 Python::attach(|py| {
2167 let obj = Bound::new(py, DirFail).unwrap();
2168 assert!(obj.dir().unwrap_err().is_instance_of::<PyValueError>(py));
2169 })
2170 }
2171}