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