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