1use crate::call::PyCallArgs;
2use crate::class::basic::CompareOp;
3use crate::conversion::{FromPyObject, IntoPyObject};
4use crate::err::{PyErr, PyResult};
5use crate::exceptions::PyTypeError;
6use crate::ffi_ptr_ext::FfiPtrExt;
7#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
8use crate::impl_::pycell::{PyClassObjectBase, PyStaticClassObject};
9use crate::instance::Bound;
10use crate::internal::get_slot::TP_DESCR_GET;
11use crate::py_result_ext::PyResultExt;
12use crate::type_object::{PyTypeCheck, PyTypeInfo};
13use crate::types::PySuper;
14use crate::types::{PyDict, PyIterator, PyList, PyString, PyType};
15use crate::{Borrowed, BoundObject, IntoPyObjectExt, Py, err, ffi};
16#[cfg(RustPython)]
17use crate::{sync::PyOnceLock, types::typeobject::PyTypeMethods};
18use core::cell::UnsafeCell;
19use core::cmp::Ordering;
20use core::ffi::c_int;
21use core::ptr;
22
23#[doc = concat!("[the guide](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/types.html#concrete-python-types)")]
33#[repr(transparent)]
35pub struct PyAny(UnsafeCell<ffi::PyObject>);
36
37#[allow(non_snake_case)]
38fn PyObject_Check(_: *mut ffi::PyObject) -> c_int {
41 1
42}
43
44#[cfg(not(RustPython))]
46pyobject_native_type_info!(
47 PyAny,
48 pyobject_native_static_type_object!(ffi::PyBaseObject_Type),
49 "typing",
50 "Any",
51 Some("builtins"),
52 #checkfunction=PyObject_Check
53);
54
55#[cfg(RustPython)]
56pyobject_native_type_info!(
57 PyAny,
58 |py| {
59 static TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
60 TYPE.import(py, "builtins", "object").unwrap().as_type_ptr()
61 },
62 "typing",
63 "Any",
64 Some("builtins"),
65 #checkfunction=PyObject_Check
66);
67
68pyobject_native_type_sized!(PyAny, ffi::PyObject);
69#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
76impl crate::impl_::pyclass::PyClassBaseType for PyAny {
77 type LayoutAsBase = PyClassObjectBase<ffi::PyObject>;
78 type BaseNativeType = PyAny;
79 type Initializer = crate::impl_::pyclass_init::PyNativeTypeInitializer<Self>;
80 type PyClassMutability = crate::pycell::impl_::ImmutableClass;
81 type Layout<T: crate::impl_::pyclass::PyClassImpl> = PyStaticClassObject<T>;
82}
83
84#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
85pyobject_subclassable_native_type!(PyAny, ffi::PyObject);
86
87#[doc(alias = "PyAny")]
92pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
93 fn is<T: AsRef<Py<PyAny>>>(&self, other: T) -> bool;
98
99 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
122 where
123 N: IntoPyObject<'py, Target = PyString>;
124
125 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
148 where
149 N: IntoPyObject<'py, Target = PyString>;
150
151 fn getattr_opt<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
180 where
181 N: IntoPyObject<'py, Target = PyString>;
182
183 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
206 where
207 N: IntoPyObject<'py, Target = PyString>,
208 V: IntoPyObject<'py>;
209
210 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
217 where
218 N: IntoPyObject<'py, Target = PyString>;
219
220 fn compare<O>(&self, other: O) -> PyResult<Ordering>
267 where
268 O: IntoPyObject<'py>;
269
270 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
304 where
305 O: IntoPyObject<'py>;
306
307 fn neg(&self) -> PyResult<Bound<'py, PyAny>>;
311
312 fn pos(&self) -> PyResult<Bound<'py, PyAny>>;
316
317 fn abs(&self) -> PyResult<Bound<'py, PyAny>>;
321
322 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>>;
324
325 fn lt<O>(&self, other: O) -> PyResult<bool>
329 where
330 O: IntoPyObject<'py>;
331
332 fn le<O>(&self, other: O) -> PyResult<bool>
336 where
337 O: IntoPyObject<'py>;
338
339 fn eq<O>(&self, other: O) -> PyResult<bool>
343 where
344 O: IntoPyObject<'py>;
345
346 fn ne<O>(&self, other: O) -> PyResult<bool>
350 where
351 O: IntoPyObject<'py>;
352
353 fn gt<O>(&self, other: O) -> PyResult<bool>
357 where
358 O: IntoPyObject<'py>;
359
360 fn ge<O>(&self, other: O) -> PyResult<bool>
364 where
365 O: IntoPyObject<'py>;
366
367 fn add<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
369 where
370 O: IntoPyObject<'py>;
371
372 fn sub<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
374 where
375 O: IntoPyObject<'py>;
376
377 fn mul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
379 where
380 O: IntoPyObject<'py>;
381
382 fn matmul<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
384 where
385 O: IntoPyObject<'py>;
386
387 fn div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
389 where
390 O: IntoPyObject<'py>;
391
392 fn floor_div<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
394 where
395 O: IntoPyObject<'py>;
396
397 fn rem<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
399 where
400 O: IntoPyObject<'py>;
401
402 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
404 where
405 O: IntoPyObject<'py>;
406
407 fn lshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
409 where
410 O: IntoPyObject<'py>;
411
412 fn rshift<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
414 where
415 O: IntoPyObject<'py>;
416
417 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
420 where
421 O1: IntoPyObject<'py>,
422 O2: IntoPyObject<'py>;
423
424 fn bitand<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
426 where
427 O: IntoPyObject<'py>;
428
429 fn bitor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
431 where
432 O: IntoPyObject<'py>;
433
434 fn bitxor<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
436 where
437 O: IntoPyObject<'py>;
438
439 fn is_callable(&self) -> bool;
467
468 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
501 where
502 A: PyCallArgs<'py>;
503
504 fn call0(&self) -> PyResult<Bound<'py, PyAny>>;
525
526 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
556 where
557 A: PyCallArgs<'py>;
558
559 fn call_method<N, A>(
597 &self,
598 name: N,
599 args: A,
600 kwargs: Option<&Bound<'py, PyDict>>,
601 ) -> PyResult<Bound<'py, PyAny>>
602 where
603 N: IntoPyObject<'py, Target = PyString>,
604 A: PyCallArgs<'py>;
605
606 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
640 where
641 N: IntoPyObject<'py, Target = PyString>;
642
643 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
678 where
679 N: IntoPyObject<'py, Target = PyString>,
680 A: PyCallArgs<'py>;
681
682 fn is_truthy(&self) -> PyResult<bool>;
686
687 fn is_none(&self) -> bool;
691
692 fn is_empty(&self) -> PyResult<bool>;
696
697 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
701 where
702 K: IntoPyObject<'py>;
703
704 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
708 where
709 K: IntoPyObject<'py>,
710 V: IntoPyObject<'py>;
711
712 fn del_item<K>(&self, key: K) -> PyResult<()>
716 where
717 K: IntoPyObject<'py>;
718
719 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>>;
744
745 fn get_type(&self) -> Bound<'py, PyType>;
747
748 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject;
750
751 fn extract<'a, T>(&'a self) -> Result<T, T::Error>
755 where
756 T: FromPyObject<'a, 'py>;
757
758 #[deprecated(
760 since = "0.29.0",
761 note = "use `pyo3::ffi::Py_REFCNT(obj.as_ptr())` instead"
762 )]
763 fn get_refcnt(&self) -> isize;
764
765 fn repr(&self) -> PyResult<Bound<'py, PyString>>;
769
770 fn str(&self) -> PyResult<Bound<'py, PyString>>;
774
775 fn hash(&self) -> PyResult<isize>;
779
780 fn len(&self) -> PyResult<usize>;
784
785 fn dir(&self) -> PyResult<Bound<'py, PyList>>;
789
790 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool>;
794
795 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool;
799
800 fn is_instance_of<T: PyTypeCheck>(&self) -> bool;
805
806 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool;
811
812 fn contains<V>(&self, value: V) -> PyResult<bool>
816 where
817 V: IntoPyObject<'py>;
818
819 fn py_super(&self) -> PyResult<Bound<'py, PySuper>>;
823}
824
825macro_rules! implement_binop {
826 ($name:ident, $c_api:ident, $op:expr) => {
827 #[doc = concat!("Computes `self ", $op, " other`.")]
828 fn $name<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
829 where
830 O: IntoPyObject<'py>,
831 {
832 let py = self.py();
833 let other = other.into_pyobject_or_pyerr(py)?;
834 unsafe { ffi::$c_api(self.as_ptr(), other.as_ptr()).assume_owned_or_err(py) }
835 }
836 };
837}
838
839impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> {
840 #[inline]
841 fn is<T: AsRef<Py<PyAny>>>(&self, other: T) -> bool {
842 ptr::eq(self.as_ptr(), other.as_ref().as_ptr())
843 }
844
845 fn hasattr<N>(&self, attr_name: N) -> PyResult<bool>
846 where
847 N: IntoPyObject<'py, Target = PyString>,
848 {
849 let py = self.py();
850 let attr_name = attr_name.into_pyobject(py).map_err(Into::into)?;
851 match unsafe { ffi::compat::PyObject_HasAttrWithError(self.as_ptr(), attr_name.as_ptr()) } {
852 1 => Ok(true),
853 0 => Ok(false),
854 _ => Err(PyErr::fetch(py)),
855 }
856 }
857
858 fn getattr<N>(&self, attr_name: N) -> PyResult<Bound<'py, PyAny>>
859 where
860 N: IntoPyObject<'py, Target = PyString>,
861 {
862 let py = self.py();
863 let attr_name = attr_name.into_pyobject(py).map_err(Into::into)?;
864 unsafe { ffi::PyObject_GetAttr(self.as_ptr(), attr_name.as_ptr()).assume_owned_or_err(py) }
865 }
866
867 fn getattr_opt<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
868 where
869 N: IntoPyObject<'py, Target = PyString>,
870 {
871 let py = self.py();
872 let attr_name = attr_name.into_pyobject_or_pyerr(py)?;
873 let mut resp_ptr: *mut ffi::PyObject = core::ptr::null_mut();
874 match unsafe {
875 ffi::compat::PyObject_GetOptionalAttr(self.as_ptr(), attr_name.as_ptr(), &mut resp_ptr)
876 } {
877 1 => Ok(Some(unsafe { resp_ptr.assume_owned_unchecked(py) })),
879 0 => Ok(None),
881 _ => Err(PyErr::fetch(py)),
883 }
884 }
885
886 fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
887 where
888 N: IntoPyObject<'py, Target = PyString>,
889 V: IntoPyObject<'py>,
890 {
891 let py = self.py();
892 let attr_name = attr_name.into_pyobject_or_pyerr(py)?;
893 let value = value.into_pyobject_or_pyerr(py)?;
894 err::error_on_negative(py, unsafe {
895 ffi::PyObject_SetAttr(self.as_ptr(), attr_name.as_ptr(), value.as_ptr())
896 })
897 }
898
899 fn delattr<N>(&self, attr_name: N) -> PyResult<()>
900 where
901 N: IntoPyObject<'py, Target = PyString>,
902 {
903 let py = self.py();
904 let attr_name = attr_name.into_pyobject_or_pyerr(py)?;
905 err::error_on_negative(py, unsafe {
906 ffi::PyObject_DelAttr(self.as_ptr(), attr_name.as_ptr())
907 })
908 }
909
910 fn compare<O>(&self, other: O) -> PyResult<Ordering>
911 where
912 O: IntoPyObject<'py>,
913 {
914 fn inner(any: &Bound<'_, PyAny>, other: Borrowed<'_, '_, PyAny>) -> PyResult<Ordering> {
915 let other = other.as_ptr();
916 let do_compare = |other, op| unsafe {
919 ffi::PyObject_RichCompare(any.as_ptr(), other, op)
920 .assume_owned_or_err(any.py())
921 .and_then(|obj| obj.is_truthy())
922 };
923 if do_compare(other, ffi::Py_EQ)? {
924 Ok(Ordering::Equal)
925 } else if do_compare(other, ffi::Py_LT)? {
926 Ok(Ordering::Less)
927 } else if do_compare(other, ffi::Py_GT)? {
928 Ok(Ordering::Greater)
929 } else {
930 Err(PyTypeError::new_err(
931 "PyAny::compare(): All comparisons returned false",
932 ))
933 }
934 }
935
936 let py = self.py();
937 inner(
938 self,
939 other.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
940 )
941 }
942
943 fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<Bound<'py, PyAny>>
944 where
945 O: IntoPyObject<'py>,
946 {
947 let py = self.py();
948 let other = other.into_pyobject_or_pyerr(py)?;
949 unsafe {
950 ffi::PyObject_RichCompare(self.as_ptr(), other.as_ptr(), compare_op as c_int)
951 .assume_owned_or_err(py)
952 }
953 }
954
955 fn neg(&self) -> PyResult<Bound<'py, PyAny>> {
956 unsafe { ffi::PyNumber_Negative(self.as_ptr()).assume_owned_or_err(self.py()) }
957 }
958
959 fn pos(&self) -> PyResult<Bound<'py, PyAny>> {
960 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
961 unsafe { ffi::PyNumber_Positive(any.as_ptr()).assume_owned_or_err(any.py()) }
962 }
963
964 inner(self)
965 }
966
967 fn abs(&self) -> PyResult<Bound<'py, PyAny>> {
968 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
969 unsafe { ffi::PyNumber_Absolute(any.as_ptr()).assume_owned_or_err(any.py()) }
970 }
971
972 inner(self)
973 }
974
975 fn bitnot(&self) -> PyResult<Bound<'py, PyAny>> {
976 fn inner<'py>(any: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
977 unsafe { ffi::PyNumber_Invert(any.as_ptr()).assume_owned_or_err(any.py()) }
978 }
979
980 inner(self)
981 }
982
983 fn lt<O>(&self, other: O) -> PyResult<bool>
984 where
985 O: IntoPyObject<'py>,
986 {
987 self.rich_compare(other, CompareOp::Lt)
988 .and_then(|any| any.is_truthy())
989 }
990
991 fn le<O>(&self, other: O) -> PyResult<bool>
992 where
993 O: IntoPyObject<'py>,
994 {
995 self.rich_compare(other, CompareOp::Le)
996 .and_then(|any| any.is_truthy())
997 }
998
999 fn eq<O>(&self, other: O) -> PyResult<bool>
1000 where
1001 O: IntoPyObject<'py>,
1002 {
1003 self.rich_compare(other, CompareOp::Eq)
1004 .and_then(|any| any.is_truthy())
1005 }
1006
1007 fn ne<O>(&self, other: O) -> PyResult<bool>
1008 where
1009 O: IntoPyObject<'py>,
1010 {
1011 self.rich_compare(other, CompareOp::Ne)
1012 .and_then(|any| any.is_truthy())
1013 }
1014
1015 fn gt<O>(&self, other: O) -> PyResult<bool>
1016 where
1017 O: IntoPyObject<'py>,
1018 {
1019 self.rich_compare(other, CompareOp::Gt)
1020 .and_then(|any| any.is_truthy())
1021 }
1022
1023 fn ge<O>(&self, other: O) -> PyResult<bool>
1024 where
1025 O: IntoPyObject<'py>,
1026 {
1027 self.rich_compare(other, CompareOp::Ge)
1028 .and_then(|any| any.is_truthy())
1029 }
1030
1031 implement_binop!(add, PyNumber_Add, "+");
1032 implement_binop!(sub, PyNumber_Subtract, "-");
1033 implement_binop!(mul, PyNumber_Multiply, "*");
1034 implement_binop!(matmul, PyNumber_MatrixMultiply, "@");
1035 implement_binop!(div, PyNumber_TrueDivide, "/");
1036 implement_binop!(floor_div, PyNumber_FloorDivide, "//");
1037 implement_binop!(rem, PyNumber_Remainder, "%");
1038 implement_binop!(lshift, PyNumber_Lshift, "<<");
1039 implement_binop!(rshift, PyNumber_Rshift, ">>");
1040 implement_binop!(bitand, PyNumber_And, "&");
1041 implement_binop!(bitor, PyNumber_Or, "|");
1042 implement_binop!(bitxor, PyNumber_Xor, "^");
1043
1044 fn divmod<O>(&self, other: O) -> PyResult<Bound<'py, PyAny>>
1046 where
1047 O: IntoPyObject<'py>,
1048 {
1049 let py = self.py();
1050 let other = other.into_pyobject_or_pyerr(py)?;
1051 unsafe { ffi::PyNumber_Divmod(self.as_ptr(), other.as_ptr()).assume_owned_or_err(py) }
1052 }
1053
1054 fn pow<O1, O2>(&self, other: O1, modulus: O2) -> PyResult<Bound<'py, PyAny>>
1057 where
1058 O1: IntoPyObject<'py>,
1059 O2: IntoPyObject<'py>,
1060 {
1061 let py = self.py();
1062 let other = other.into_pyobject_or_pyerr(py)?;
1063 let modulus = modulus.into_pyobject_or_pyerr(py)?;
1064 unsafe {
1065 ffi::PyNumber_Power(self.as_ptr(), other.as_ptr(), modulus.as_ptr())
1066 .assume_owned_or_err(py)
1067 }
1068 }
1069
1070 fn is_callable(&self) -> bool {
1071 unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 }
1072 }
1073
1074 fn call<A>(&self, args: A, kwargs: Option<&Bound<'py, PyDict>>) -> PyResult<Bound<'py, PyAny>>
1075 where
1076 A: PyCallArgs<'py>,
1077 {
1078 if let Some(kwargs) = kwargs {
1079 args.call(
1080 self.as_borrowed(),
1081 kwargs.as_borrowed(),
1082 crate::call::private::Token,
1083 )
1084 } else {
1085 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1086 }
1087 }
1088
1089 #[inline]
1090 fn call0(&self) -> PyResult<Bound<'py, PyAny>> {
1091 unsafe { ffi::compat::PyObject_CallNoArgs(self.as_ptr()).assume_owned_or_err(self.py()) }
1092 }
1093
1094 fn call1<A>(&self, args: A) -> PyResult<Bound<'py, PyAny>>
1095 where
1096 A: PyCallArgs<'py>,
1097 {
1098 args.call_positional(self.as_borrowed(), crate::call::private::Token)
1099 }
1100
1101 #[inline]
1102 fn call_method<N, A>(
1103 &self,
1104 name: N,
1105 args: A,
1106 kwargs: Option<&Bound<'py, PyDict>>,
1107 ) -> PyResult<Bound<'py, PyAny>>
1108 where
1109 N: IntoPyObject<'py, Target = PyString>,
1110 A: PyCallArgs<'py>,
1111 {
1112 if kwargs.is_none() {
1113 self.call_method1(name, args)
1114 } else {
1115 self.getattr(name)
1116 .and_then(|method| method.call(args, kwargs))
1117 }
1118 }
1119
1120 #[inline]
1121 fn call_method0<N>(&self, name: N) -> PyResult<Bound<'py, PyAny>>
1122 where
1123 N: IntoPyObject<'py, Target = PyString>,
1124 {
1125 let py = self.py();
1126 let name = name.into_pyobject_or_pyerr(py)?.into_bound();
1127 unsafe {
1128 ffi::compat::PyObject_CallMethodNoArgs(self.as_ptr(), name.as_ptr())
1129 .assume_owned_or_err(py)
1130 }
1131 }
1132
1133 fn call_method1<N, A>(&self, name: N, args: A) -> PyResult<Bound<'py, PyAny>>
1134 where
1135 N: IntoPyObject<'py, Target = PyString>,
1136 A: PyCallArgs<'py>,
1137 {
1138 let name = name.into_pyobject_or_pyerr(self.py())?;
1139 args.call_method_positional(
1140 self.as_borrowed(),
1141 name.as_borrowed(),
1142 crate::call::private::Token,
1143 )
1144 }
1145
1146 fn is_truthy(&self) -> PyResult<bool> {
1147 let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
1148 err::error_on_negative(self.py(), v)?;
1149 Ok(v != 0)
1150 }
1151
1152 #[inline]
1153 fn is_none(&self) -> bool {
1154 unsafe { ptr::eq(ffi::Py_None(), self.as_ptr()) }
1155 }
1156
1157 fn is_empty(&self) -> PyResult<bool> {
1158 self.len().map(|l| l == 0)
1159 }
1160
1161 fn get_item<K>(&self, key: K) -> PyResult<Bound<'py, PyAny>>
1162 where
1163 K: IntoPyObject<'py>,
1164 {
1165 let py = self.py();
1166 let key = key.into_pyobject_or_pyerr(py)?;
1167 unsafe { ffi::PyObject_GetItem(self.as_ptr(), key.as_ptr()).assume_owned_or_err(py) }
1168 }
1169
1170 fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
1171 where
1172 K: IntoPyObject<'py>,
1173 V: IntoPyObject<'py>,
1174 {
1175 let py = self.py();
1176 let key = key.into_pyobject_or_pyerr(py)?;
1177 let value = value.into_pyobject_or_pyerr(py)?;
1178 err::error_on_negative(py, unsafe {
1179 ffi::PyObject_SetItem(self.as_ptr(), key.as_ptr(), value.as_ptr())
1180 })
1181 }
1182
1183 fn del_item<K>(&self, key: K) -> PyResult<()>
1184 where
1185 K: IntoPyObject<'py>,
1186 {
1187 let py = self.py();
1188 let key = key.into_pyobject_or_pyerr(py)?;
1189 err::error_on_negative(py, unsafe {
1190 ffi::PyObject_DelItem(self.as_ptr(), key.as_ptr())
1191 })
1192 }
1193
1194 fn try_iter(&self) -> PyResult<Bound<'py, PyIterator>> {
1195 PyIterator::from_object(self)
1196 }
1197
1198 fn get_type(&self) -> Bound<'py, PyType> {
1199 unsafe { PyType::from_borrowed_type_ptr(self.py(), ffi::Py_TYPE(self.as_ptr())) }
1200 }
1201
1202 #[inline]
1203 fn get_type_ptr(&self) -> *mut ffi::PyTypeObject {
1204 unsafe { ffi::Py_TYPE(self.as_ptr()) }
1205 }
1206
1207 fn extract<'a, T>(&'a self) -> Result<T, T::Error>
1208 where
1209 T: FromPyObject<'a, 'py>,
1210 {
1211 FromPyObject::extract(self.as_borrowed())
1212 }
1213
1214 fn get_refcnt(&self) -> isize {
1215 self._get_refcnt()
1216 }
1217
1218 fn repr(&self) -> PyResult<Bound<'py, PyString>> {
1219 unsafe {
1220 ffi::PyObject_Repr(self.as_ptr())
1221 .assume_owned_or_err(self.py())
1222 .cast_into_unchecked()
1223 }
1224 }
1225
1226 fn str(&self) -> PyResult<Bound<'py, PyString>> {
1227 unsafe {
1228 ffi::PyObject_Str(self.as_ptr())
1229 .assume_owned_or_err(self.py())
1230 .cast_into_unchecked()
1231 }
1232 }
1233
1234 fn hash(&self) -> PyResult<isize> {
1235 match unsafe { ffi::PyObject_Hash(self.as_ptr()) } {
1237 -1 => Err(PyErr::fetch(self.py())),
1238 v => Ok(v),
1239 }
1240 }
1241
1242 fn len(&self) -> PyResult<usize> {
1243 let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
1244 err::error_on_negative(self.py(), v)?;
1245 Ok(v as usize)
1246 }
1247
1248 fn dir(&self) -> PyResult<Bound<'py, PyList>> {
1249 unsafe {
1250 ffi::PyObject_Dir(self.as_ptr())
1251 .assume_owned_or_err(self.py())
1252 .cast_into_unchecked()
1253 }
1254 }
1255
1256 #[inline]
1257 fn is_instance(&self, ty: &Bound<'py, PyAny>) -> PyResult<bool> {
1258 let result = unsafe { ffi::PyObject_IsInstance(self.as_ptr(), ty.as_ptr()) };
1259 err::error_on_negative(self.py(), result)?;
1260 Ok(result == 1)
1261 }
1262
1263 #[inline]
1264 fn is_exact_instance(&self, ty: &Bound<'py, PyAny>) -> bool {
1265 self.get_type().is(ty)
1266 }
1267
1268 #[inline]
1269 fn is_instance_of<T: PyTypeCheck>(&self) -> bool {
1270 T::type_check(self)
1271 }
1272
1273 #[inline]
1274 fn is_exact_instance_of<T: PyTypeInfo>(&self) -> bool {
1275 T::is_exact_type_of(self)
1276 }
1277
1278 fn contains<V>(&self, value: V) -> PyResult<bool>
1279 where
1280 V: IntoPyObject<'py>,
1281 {
1282 let py = self.py();
1283 let value = value.into_pyobject_or_pyerr(py)?;
1284 match unsafe { ffi::PySequence_Contains(self.as_ptr(), value.as_ptr()) } {
1285 0 => Ok(false),
1286 1 => Ok(true),
1287 _ => Err(PyErr::fetch(py)),
1288 }
1289 }
1290
1291 fn py_super(&self) -> PyResult<Bound<'py, PySuper>> {
1292 PySuper::new(&self.get_type(), self)
1293 }
1294}
1295
1296impl<'py> Bound<'py, PyAny> {
1297 #[allow(dead_code, reason = "currently only used with num-complex + abi3")]
1308 pub(crate) fn lookup_special<N>(&self, attr_name: N) -> PyResult<Option<Bound<'py, PyAny>>>
1309 where
1310 N: IntoPyObject<'py, Target = PyString>,
1311 {
1312 let py = self.py();
1313 let self_type = self.get_type();
1314 let attr = if let Ok(attr) = self_type.getattr(attr_name) {
1315 attr
1316 } else {
1317 return Ok(None);
1318 };
1319
1320 if let Some(descr_get) = attr.get_type().get_slot(TP_DESCR_GET) {
1322 unsafe {
1324 descr_get(attr.as_ptr(), self.as_ptr(), self_type.as_ptr())
1325 .assume_owned_or_err(py)
1326 .map(Some)
1327 }
1328 } else {
1329 Ok(Some(attr))
1330 }
1331 }
1332
1333 #[inline]
1334 pub(crate) fn _get_refcnt(&self) -> isize {
1335 unsafe { ffi::Py_REFCNT(self.as_ptr()) }
1336 }
1337}
1338
1339#[cfg(test)]
1340mod tests {
1341 use crate::platform::prelude::*;
1342 use crate::{
1343 Bound, BoundObject, IntoPyObject, PyTypeInfo, Python,
1344 basic::CompareOp,
1345 test_utils::generate_unique_module_name,
1346 types::{IntoPyDict, PyAny, PyAnyMethods, PyBool, PyInt, PyList, PyModule, PyTypeMethods},
1347 };
1348 use core::fmt::Debug;
1349 use pyo3_ffi::c_str;
1350
1351 #[test]
1352 fn test_lookup_special() {
1353 Python::attach(|py| {
1354 let module = PyModule::from_code(
1355 py,
1356 cr#"
1357class CustomCallable:
1358 def __call__(self):
1359 return 1
1360
1361class SimpleInt:
1362 def __int__(self):
1363 return 1
1364
1365class InheritedInt(SimpleInt): pass
1366
1367class NoInt: pass
1368
1369class NoDescriptorInt:
1370 __int__ = CustomCallable()
1371
1372class InstanceOverrideInt:
1373 def __int__(self):
1374 return 1
1375instance_override = InstanceOverrideInt()
1376instance_override.__int__ = lambda self: 2
1377
1378class ErrorInDescriptorInt:
1379 @property
1380 def __int__(self):
1381 raise ValueError("uh-oh!")
1382
1383class NonHeapNonDescriptorInt:
1384 # A static-typed callable that doesn't implement `__get__`. These are pretty hard to come by.
1385 __int__ = int
1386 "#,
1387 c"test.py",
1388 &generate_unique_module_name("test"),
1389 )
1390 .unwrap();
1391
1392 let int = crate::intern!(py, "__int__");
1393 let eval_int =
1394 |obj: Bound<'_, PyAny>| obj.lookup_special(int)?.unwrap().call0()?.extract::<u32>();
1395
1396 let simple = module.getattr("SimpleInt").unwrap().call0().unwrap();
1397 assert_eq!(eval_int(simple).unwrap(), 1);
1398 let inherited = module.getattr("InheritedInt").unwrap().call0().unwrap();
1399 assert_eq!(eval_int(inherited).unwrap(), 1);
1400 let no_descriptor = module.getattr("NoDescriptorInt").unwrap().call0().unwrap();
1401 assert_eq!(eval_int(no_descriptor).unwrap(), 1);
1402 let missing = module.getattr("NoInt").unwrap().call0().unwrap();
1403 assert!(missing.lookup_special(int).unwrap().is_none());
1404 let instance_override = module.getattr("instance_override").unwrap();
1407 assert_eq!(eval_int(instance_override).unwrap(), 1);
1408 let descriptor_error = module
1409 .getattr("ErrorInDescriptorInt")
1410 .unwrap()
1411 .call0()
1412 .unwrap();
1413 assert!(descriptor_error.lookup_special(int).is_err());
1414 let nonheap_nondescriptor = module
1415 .getattr("NonHeapNonDescriptorInt")
1416 .unwrap()
1417 .call0()
1418 .unwrap();
1419 assert_eq!(eval_int(nonheap_nondescriptor).unwrap(), 0);
1420 })
1421 }
1422
1423 #[test]
1424 fn test_getattr_opt() {
1425 Python::attach(|py| {
1426 let module = PyModule::from_code(
1427 py,
1428 cr#"
1429class Test:
1430 class_str_attribute = "class_string"
1431
1432 @property
1433 def error(self):
1434 raise ValueError("This is an intentional error")
1435 "#,
1436 c"test.py",
1437 &generate_unique_module_name("test"),
1438 )
1439 .unwrap();
1440
1441 let class_test = module.getattr_opt("Test").unwrap().unwrap();
1443
1444 let cls_attr_str = class_test
1446 .getattr_opt("class_str_attribute")
1447 .unwrap()
1448 .unwrap();
1449 assert_eq!(cls_attr_str.extract::<String>().unwrap(), "class_string");
1450
1451 let do_not_exist = class_test.getattr_opt("doNotExist").unwrap();
1453 assert!(do_not_exist.is_none());
1454
1455 let instance = class_test.call0().unwrap();
1457 let error = instance.getattr_opt("error");
1458 assert!(error.is_err());
1459 assert!(
1460 error
1461 .unwrap_err()
1462 .to_string()
1463 .contains("This is an intentional error")
1464 );
1465 });
1466 }
1467
1468 #[test]
1469 fn test_getattr_opt_attribute_error_subclass() {
1470 Python::attach(|py| {
1471 let module = PyModule::from_code(
1472 py,
1473 cr#"
1474class CustomAttrError(AttributeError):
1475 pass
1476
1477class Obj:
1478 @property
1479 def missing(self):
1480 raise CustomAttrError("not here")
1481 "#,
1482 c"test.py",
1483 &generate_unique_module_name("test"),
1484 )
1485 .unwrap();
1486
1487 let obj = module.getattr("Obj").unwrap().call0().unwrap();
1488
1489 let result = obj.getattr_opt("missing").unwrap();
1491 assert!(result.is_none());
1492 });
1493 }
1494
1495 #[test]
1496 fn test_call_for_non_existing_method() {
1497 Python::attach(|py| {
1498 let a = py.eval(c"42", None, None).unwrap();
1499 a.call_method0("__str__").unwrap(); assert!(a.call_method("nonexistent_method", (1,), None).is_err());
1501 assert!(a.call_method0("nonexistent_method").is_err());
1502 assert!(a.call_method1("nonexistent_method", (1,)).is_err());
1503 });
1504 }
1505
1506 #[test]
1507 fn test_call_with_kwargs() {
1508 Python::attach(|py| {
1509 let list = vec![3, 6, 5, 4, 7].into_pyobject(py).unwrap();
1510 let dict = vec![("reverse", true)].into_py_dict(py).unwrap();
1511 list.call_method("sort", (), Some(&dict)).unwrap();
1512 assert_eq!(list.extract::<Vec<i32>>().unwrap(), vec![7, 6, 5, 4, 3]);
1513 });
1514 }
1515
1516 #[test]
1517 fn test_call_method0() {
1518 Python::attach(|py| {
1519 let module = PyModule::from_code(
1520 py,
1521 cr#"
1522class SimpleClass:
1523 def foo(self):
1524 return 42
1525"#,
1526 c_str!(file!()),
1527 &generate_unique_module_name("test_module"),
1528 )
1529 .expect("module creation failed");
1530
1531 let simple_class = module.getattr("SimpleClass").unwrap().call0().unwrap();
1532 assert_eq!(
1533 simple_class
1534 .call_method0("foo")
1535 .unwrap()
1536 .extract::<u32>()
1537 .unwrap(),
1538 42
1539 );
1540 })
1541 }
1542
1543 #[test]
1544 fn test_type() {
1545 Python::attach(|py| {
1546 let obj = py.eval(c"42", None, None).unwrap();
1547 assert_eq!(obj.get_type().as_type_ptr(), obj.get_type_ptr());
1548 });
1549 }
1550
1551 #[test]
1552 fn test_dir() {
1553 Python::attach(|py| {
1554 let obj = py.eval(c"42", None, None).unwrap();
1555 let dir = py
1556 .eval(c"dir(42)", None, None)
1557 .unwrap()
1558 .cast_into::<PyList>()
1559 .unwrap();
1560 let a = obj
1561 .dir()
1562 .unwrap()
1563 .into_iter()
1564 .map(|x| x.extract::<String>().unwrap());
1565 let b = dir.into_iter().map(|x| x.extract::<String>().unwrap());
1566 assert!(a.eq(b));
1567 });
1568 }
1569
1570 #[test]
1571 fn test_hasattr() {
1572 Python::attach(|py| {
1573 let x = 5i32.into_pyobject(py).unwrap();
1574 assert!(x.is_instance_of::<PyInt>());
1575
1576 assert!(x.hasattr("to_bytes").unwrap());
1577 assert!(!x.hasattr("bbbbbbytes").unwrap());
1578 })
1579 }
1580
1581 #[cfg(feature = "macros")]
1582 #[test]
1583 #[allow(unknown_lints, non_local_definitions)]
1584 fn test_hasattr_error() {
1585 use crate::exceptions::PyValueError;
1586 use crate::prelude::*;
1587
1588 #[pyclass(crate = "crate")]
1589 struct GetattrFail;
1590
1591 #[pymethods(crate = "crate")]
1592 impl GetattrFail {
1593 fn __getattr__(&self, attr: Py<PyAny>) -> PyResult<Py<PyAny>> {
1594 Err(PyValueError::new_err(attr))
1595 }
1596 }
1597
1598 Python::attach(|py| {
1599 let obj = Py::new(py, GetattrFail).unwrap();
1600 let obj = obj.bind(py).as_any();
1601
1602 assert!(
1603 obj.hasattr("foo")
1604 .unwrap_err()
1605 .is_instance_of::<PyValueError>(py)
1606 );
1607 })
1608 }
1609
1610 #[test]
1611 fn test_nan_eq() {
1612 Python::attach(|py| {
1613 let nan = py.eval(c"float('nan')", None, None).unwrap();
1614 assert!(nan.compare(&nan).is_err());
1615 });
1616 }
1617
1618 #[test]
1619 fn test_any_is_instance_of() {
1620 Python::attach(|py| {
1621 let x = 5i32.into_pyobject(py).unwrap();
1622 assert!(x.is_instance_of::<PyInt>());
1623
1624 let l = vec![&x, &x].into_pyobject(py).unwrap();
1625 assert!(l.is_instance_of::<PyList>());
1626 });
1627 }
1628
1629 #[test]
1630 fn test_any_is_instance() {
1631 Python::attach(|py| {
1632 let l = vec![1i8, 2].into_pyobject(py).unwrap();
1633 assert!(l.is_instance(&py.get_type::<PyList>()).unwrap());
1634 });
1635 }
1636
1637 #[test]
1638 fn test_any_is_exact_instance_of() {
1639 Python::attach(|py| {
1640 let x = 5i32.into_pyobject(py).unwrap();
1641 assert!(x.is_exact_instance_of::<PyInt>());
1642
1643 let t = PyBool::new(py, true);
1644 assert!(t.is_instance_of::<PyInt>());
1645 assert!(!t.is_exact_instance_of::<PyInt>());
1646 assert!(t.is_exact_instance_of::<PyBool>());
1647
1648 let l = vec![&x, &x].into_pyobject(py).unwrap();
1649 assert!(l.is_exact_instance_of::<PyList>());
1650 });
1651 }
1652
1653 #[test]
1654 fn test_any_is_exact_instance() {
1655 Python::attach(|py| {
1656 let t = PyBool::new(py, true);
1657 assert!(t.is_instance(&py.get_type::<PyInt>()).unwrap());
1658 assert!(!t.is_exact_instance(&py.get_type::<PyInt>()));
1659 assert!(t.is_exact_instance(&py.get_type::<PyBool>()));
1660 });
1661 }
1662
1663 #[test]
1664 fn test_any_contains() {
1665 Python::attach(|py| {
1666 let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
1667 let ob = v.into_pyobject(py).unwrap();
1668
1669 let bad_needle = 7i32.into_pyobject(py).unwrap();
1670 assert!(!ob.contains(&bad_needle).unwrap());
1671
1672 let good_needle = 8i32.into_pyobject(py).unwrap();
1673 assert!(ob.contains(&good_needle).unwrap());
1674
1675 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
1676 assert!(ob.contains(&type_coerced_needle).unwrap());
1677
1678 let n: u32 = 42;
1679 let bad_haystack = n.into_pyobject(py).unwrap();
1680 let irrelevant_needle = 0i32.into_pyobject(py).unwrap();
1681 assert!(bad_haystack.contains(&irrelevant_needle).is_err());
1682 });
1683 }
1684
1685 fn test_eq_methods_generic<'a, T>(list: &'a [T])
1687 where
1688 T: PartialEq + PartialOrd,
1689 for<'py> &'a T: IntoPyObject<'py>,
1690 for<'py> <&'a T as IntoPyObject<'py>>::Error: Debug,
1691 {
1692 Python::attach(|py| {
1693 for a in list {
1694 for b in list {
1695 let a_py = a.into_pyobject(py).unwrap().into_any().into_bound();
1696 let b_py = b.into_pyobject(py).unwrap().into_any().into_bound();
1697
1698 assert_eq!(
1699 a.lt(b),
1700 a_py.lt(&b_py).unwrap(),
1701 "{} < {} should be {}.",
1702 a_py,
1703 b_py,
1704 a.lt(b)
1705 );
1706 assert_eq!(
1707 a.le(b),
1708 a_py.le(&b_py).unwrap(),
1709 "{} <= {} should be {}.",
1710 a_py,
1711 b_py,
1712 a.le(b)
1713 );
1714 assert_eq!(
1715 a.eq(b),
1716 a_py.eq(&b_py).unwrap(),
1717 "{} == {} should be {}.",
1718 a_py,
1719 b_py,
1720 a.eq(b)
1721 );
1722 assert_eq!(
1723 a.ne(b),
1724 a_py.ne(&b_py).unwrap(),
1725 "{} != {} should be {}.",
1726 a_py,
1727 b_py,
1728 a.ne(b)
1729 );
1730 assert_eq!(
1731 a.gt(b),
1732 a_py.gt(&b_py).unwrap(),
1733 "{} > {} should be {}.",
1734 a_py,
1735 b_py,
1736 a.gt(b)
1737 );
1738 assert_eq!(
1739 a.ge(b),
1740 a_py.ge(&b_py).unwrap(),
1741 "{} >= {} should be {}.",
1742 a_py,
1743 b_py,
1744 a.ge(b)
1745 );
1746 }
1747 }
1748 });
1749 }
1750
1751 #[test]
1752 fn test_eq_methods_integers() {
1753 let ints = [-4, -4, 1, 2, 0, -100, 1_000_000];
1754 test_eq_methods_generic::<i32>(&ints);
1755 }
1756
1757 #[test]
1758 fn test_eq_methods_strings() {
1759 let strings = ["Let's", "test", "some", "eq", "methods"];
1760 test_eq_methods_generic::<&str>(&strings);
1761 }
1762
1763 #[test]
1764 fn test_eq_methods_floats() {
1765 let floats = [
1766 -1.0,
1767 2.5,
1768 0.0,
1769 3.0,
1770 core::f64::consts::PI,
1771 10.0,
1772 10.0 / 3.0,
1773 -1_000_000.0,
1774 ];
1775 test_eq_methods_generic::<f64>(&floats);
1776 }
1777
1778 #[test]
1779 fn test_eq_methods_bools() {
1780 let bools = [true, false];
1781 test_eq_methods_generic::<bool>(&bools);
1782 }
1783
1784 #[test]
1785 fn test_rich_compare_type_error() {
1786 Python::attach(|py| {
1787 let py_int = 1i32.into_pyobject(py).unwrap();
1788 let py_str = "1".into_pyobject(py).unwrap();
1789
1790 assert!(py_int.rich_compare(&py_str, CompareOp::Lt).is_err());
1791 assert!(
1792 !py_int
1793 .rich_compare(py_str, CompareOp::Eq)
1794 .unwrap()
1795 .is_truthy()
1796 .unwrap()
1797 );
1798 })
1799 }
1800
1801 #[test]
1802 fn test_is_callable() {
1803 Python::attach(|py| {
1804 assert!(PyList::type_object(py).is_callable());
1805
1806 let not_callable = 5i32.into_pyobject(py).unwrap();
1807 assert!(!not_callable.is_callable());
1808 });
1809 }
1810
1811 #[test]
1812 fn test_is_empty() {
1813 Python::attach(|py| {
1814 let empty_list = PyList::empty(py).into_any();
1815 assert!(empty_list.is_empty().unwrap());
1816
1817 let list = PyList::new(py, vec![1, 2, 3]).unwrap().into_any();
1818 assert!(!list.is_empty().unwrap());
1819
1820 let not_container = 5i32.into_pyobject(py).unwrap();
1821 assert!(not_container.is_empty().is_err());
1822 });
1823 }
1824
1825 #[cfg(feature = "macros")]
1826 #[test]
1827 #[allow(unknown_lints, non_local_definitions)]
1828 fn test_fallible_dir() {
1829 use crate::exceptions::PyValueError;
1830 use crate::prelude::*;
1831
1832 #[pyclass(crate = "crate")]
1833 struct DirFail;
1834
1835 #[pymethods(crate = "crate")]
1836 impl DirFail {
1837 fn __dir__(&self) -> PyResult<Py<PyAny>> {
1838 Err(PyValueError::new_err("uh-oh!"))
1839 }
1840 }
1841
1842 Python::attach(|py| {
1843 let obj = Bound::new(py, DirFail).unwrap();
1844 assert!(obj.dir().unwrap_err().is_instance_of::<PyValueError>(py));
1845 })
1846 }
1847}