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