pyo3/types/
notimplemented.rs

1#[cfg(feature = "experimental-inspect")]
2use crate::inspect::TypeHint;
3use crate::{
4    ffi, ffi_ptr_ext::FfiPtrExt, types::any::PyAnyMethods, Borrowed, Bound, PyAny, PyTypeInfo,
5    Python,
6};
7
8/// Represents the Python `NotImplemented` object.
9///
10/// Values of this type are accessed via PyO3's smart pointers, e.g. as
11/// [`Py<PyNotImplemented>`][crate::Py] or [`Bound<'py, PyNotImplemented>`][Bound].
12#[repr(transparent)]
13pub struct PyNotImplemented(PyAny);
14
15pyobject_native_type_named!(PyNotImplemented);
16
17impl PyNotImplemented {
18    /// Returns the `NotImplemented` object.
19    #[inline]
20    pub fn get(py: Python<'_>) -> Borrowed<'_, '_, PyNotImplemented> {
21        // SAFETY: `Py_NotImplemented` is a global singleton which is known to be the NotImplemented object
22        unsafe {
23            ffi::Py_NotImplemented()
24                .assume_borrowed_unchecked(py)
25                .cast_unchecked()
26        }
27    }
28}
29
30unsafe impl PyTypeInfo for PyNotImplemented {
31    const NAME: &'static str = "NotImplementedType";
32    const MODULE: Option<&'static str> = None;
33
34    #[cfg(feature = "experimental-inspect")]
35    const TYPE_HINT: TypeHint = TypeHint::module_attr("types", "NotImplementedType");
36
37    fn type_object_raw(_py: Python<'_>) -> *mut ffi::PyTypeObject {
38        unsafe { ffi::Py_TYPE(ffi::Py_NotImplemented()) }
39    }
40
41    #[inline]
42    fn is_type_of(object: &Bound<'_, PyAny>) -> bool {
43        // NotImplementedType is not usable as a base type
44        Self::is_exact_type_of(object)
45    }
46
47    #[inline]
48    fn is_exact_type_of(object: &Bound<'_, PyAny>) -> bool {
49        object.is(&**Self::get(object.py()))
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use crate::types::any::PyAnyMethods;
56    use crate::types::{PyDict, PyNotImplemented};
57    use crate::{PyTypeInfo, Python};
58
59    #[test]
60    fn test_notimplemented_is_itself() {
61        Python::attach(|py| {
62            assert!(PyNotImplemented::get(py).is_instance_of::<PyNotImplemented>());
63            assert!(PyNotImplemented::get(py).is_exact_instance_of::<PyNotImplemented>());
64        })
65    }
66
67    #[test]
68    fn test_notimplemented_type_object_consistent() {
69        Python::attach(|py| {
70            assert!(PyNotImplemented::get(py)
71                .get_type()
72                .is(PyNotImplemented::type_object(py)));
73        })
74    }
75
76    #[test]
77    fn test_dict_is_not_notimplemented() {
78        Python::attach(|py| {
79            assert!(PyDict::new(py).cast::<PyNotImplemented>().is_err());
80        })
81    }
82}