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