diff --git a/newsfragments/5637.changed.md b/newsfragments/5637.changed.md new file mode 100644 index 00000000000..a93ea170b59 --- /dev/null +++ b/newsfragments/5637.changed.md @@ -0,0 +1 @@ +Introspection: Fill INPUT_TYPE and OUTPUT_TYPE nearly everywhere \ No newline at end of file diff --git a/pytests/stubs/pyfunctions.pyi b/pytests/stubs/pyfunctions.pyi index 9164badcf6a..c8a3f610da9 100644 --- a/pytests/stubs/pyfunctions.pyi +++ b/pytests/stubs/pyfunctions.pyi @@ -1,6 +1,6 @@ from typing import Any -def args_kwargs(*args, **kwargs) -> Any: ... +def args_kwargs(*args, **kwargs) -> tuple[Any, Any | None]: ... def many_keyword_arguments( *, ant: object | None = None, @@ -21,20 +21,22 @@ def many_keyword_arguments( penguin: object | None = None, ) -> None: ... def none() -> None: ... -def positional_only(a: object, /, b: object) -> Any: ... -def simple(a: object, b: object | None = None, *, c: object | None = None) -> Any: ... +def positional_only(a: object, /, b: object) -> tuple[Any, Any]: ... +def simple( + a: object, b: object | None = None, *, c: object | None = None +) -> tuple[Any, Any | None, Any | None]: ... def simple_args( a: object, b: object | None = None, *args, c: object | None = None -) -> Any: ... +) -> tuple[Any, Any | None, Any, Any | None]: ... def simple_args_kwargs( a: object, b: object | None = None, *args, c: object | None = None, **kwargs -) -> Any: ... +) -> tuple[Any, Any | None, Any, Any | None, Any | None]: ... def simple_kwargs( a: object, b: object | None = None, c: object | None = None, **kwargs -) -> Any: ... +) -> tuple[Any, Any | None, Any | None, Any | None]: ... def with_custom_type_annotations( a: int, *_args: str, _b: int | None = None, **_kwargs: bool ) -> int: ... def with_typed_args( a: bool = False, b: int = 0, c: float = 0.0, d: str = "" -) -> Any: ... +) -> tuple[bool, int, float, str]: ... diff --git a/src/buffer.rs b/src/buffer.rs index 081f520e795..fce3f610f0a 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -18,6 +18,8 @@ // DEALINGS IN THE SOFTWARE. //! `PyBuffer` implementation +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::{err, exceptions::PyBufferError, ffi, FromPyObject, PyAny, PyResult, Python}; use crate::{Borrowed, Bound, PyErr}; use std::ffi::{ @@ -199,6 +201,9 @@ pub unsafe trait Element: Copy { impl FromPyObject<'_, '_> for PyBuffer { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = TypeHint::module_attr("collections.abc", "Buffer"); + fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result, Self::Error> { Self::get(&obj) } diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index 7d67f504ad5..4e2eff64210 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -43,7 +43,11 @@ use crate::conversion::{FromPyObjectOwned, IntoPyObject}; use crate::exceptions::{PyTypeError, PyUserWarning, PyValueError}; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::intern; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::types::any::PyAnyMethods; use crate::types::PyNone; use crate::types::{PyDate, PyDateTime, PyDelta, PyTime, PyTzInfo, PyTzInfoAccess}; @@ -70,6 +74,9 @@ impl<'py> IntoPyObject<'py> for Duration { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyDelta::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { // Total number of days let days = self.num_days(); @@ -102,6 +109,9 @@ impl<'py> IntoPyObject<'py> for &Duration { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = Duration::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -111,6 +121,9 @@ impl<'py> IntoPyObject<'py> for &Duration { impl FromPyObject<'_, '_> for Duration { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyDelta::TYPE_HINT; + fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result { let delta = ob.cast::()?; // Python size are much lower than rust size so we do not need bound checks. @@ -147,6 +160,9 @@ impl<'py> IntoPyObject<'py> for NaiveDate { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyDate::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { let DateArgs { year, month, day } = (&self).into(); PyDate::new(py, year, month, day) @@ -158,6 +174,9 @@ impl<'py> IntoPyObject<'py> for &NaiveDate { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = NaiveDate::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -167,6 +186,9 @@ impl<'py> IntoPyObject<'py> for &NaiveDate { impl FromPyObject<'_, '_> for NaiveDate { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyDate::TYPE_HINT; + fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result { let date = &*ob.cast::()?; py_date_to_naive_date(date) @@ -178,6 +200,9 @@ impl<'py> IntoPyObject<'py> for NaiveTime { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyTime::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { let TimeArgs { hour, @@ -202,6 +227,9 @@ impl<'py> IntoPyObject<'py> for &NaiveTime { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = NaiveTime::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -211,6 +239,9 @@ impl<'py> IntoPyObject<'py> for &NaiveTime { impl FromPyObject<'_, '_> for NaiveTime { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyTime::TYPE_HINT; + fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result { let time = &*ob.cast::()?; py_time_to_naive_time(time) @@ -222,6 +253,9 @@ impl<'py> IntoPyObject<'py> for NaiveDateTime { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { let DateArgs { year, month, day } = (&self.date()).into(); let TimeArgs { @@ -247,6 +281,9 @@ impl<'py> IntoPyObject<'py> for &NaiveDateTime { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = NaiveDateTime::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -256,6 +293,9 @@ impl<'py> IntoPyObject<'py> for &NaiveDateTime { impl FromPyObject<'_, '_> for NaiveDateTime { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT; + fn extract(dt: Borrowed<'_, '_, PyAny>) -> Result { let dt = &*dt.cast::()?; @@ -280,6 +320,9 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&DateTime>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (&self).into_pyobject(py) @@ -294,6 +337,9 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { let tz = self.timezone().into_bound_py_any(py)?.cast_into()?; @@ -338,6 +384,9 @@ where { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT; + fn extract(dt: Borrowed<'_, 'py, PyAny>) -> Result { let dt = &*dt.cast::()?; let tzinfo = dt.get_tzinfo(); @@ -365,6 +414,9 @@ impl<'py> IntoPyObject<'py> for FixedOffset { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { let seconds_offset = self.local_minus_utc(); let td = PyDelta::new(py, 0, seconds_offset, 0, true)?; @@ -377,6 +429,9 @@ impl<'py> IntoPyObject<'py> for &FixedOffset { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = FixedOffset::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -386,6 +441,9 @@ impl<'py> IntoPyObject<'py> for &FixedOffset { impl FromPyObject<'_, '_> for FixedOffset { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT; + /// Convert python tzinfo to rust [`FixedOffset`]. /// /// Note that the conversion will result in precision lost in microseconds as chrono offset @@ -418,6 +476,9 @@ impl<'py> IntoPyObject<'py> for Utc { type Output = Borrowed<'static, 'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { PyTzInfo::utc(py) } @@ -428,6 +489,9 @@ impl<'py> IntoPyObject<'py> for &Utc { type Output = Borrowed<'static, 'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = Utc::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -453,6 +517,9 @@ impl<'py> IntoPyObject<'py> for Local { type Output = Borrowed<'static, 'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { static LOCAL_TZ: PyOnceLock> = PyOnceLock::new(); let tz = LOCAL_TZ @@ -473,6 +540,9 @@ impl<'py> IntoPyObject<'py> for &Local { type Output = Borrowed<'static, 'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = Local::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) diff --git a/src/conversions/chrono_tz.rs b/src/conversions/chrono_tz.rs index 433a56b4ebf..e9c7e271ccd 100644 --- a/src/conversions/chrono_tz.rs +++ b/src/conversions/chrono_tz.rs @@ -36,7 +36,11 @@ //! ``` use crate::conversion::IntoPyObject; use crate::exceptions::PyValueError; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::pybacked::PyBackedStr; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::types::{any::PyAnyMethods, PyTzInfo}; use crate::{intern, Borrowed, Bound, FromPyObject, PyAny, PyErr, Python}; use chrono_tz::Tz; @@ -47,6 +51,9 @@ impl<'py> IntoPyObject<'py> for Tz { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { PyTzInfo::timezone(py, self.name()) } @@ -57,6 +64,9 @@ impl<'py> IntoPyObject<'py> for &Tz { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = Tz::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) diff --git a/src/conversions/std/array.rs b/src/conversions/std/array.rs index c8cb3b534e1..5bf6e1a00fb 100644 --- a/src/conversions/std/array.rs +++ b/src/conversions/std/array.rs @@ -1,4 +1,6 @@ use crate::conversion::{FromPyObjectOwned, FromPyObjectSequence, IntoPyObject}; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::types::any::PyAnyMethods; use crate::types::PySequence; use crate::{err::CastError, ffi, FromPyObject, PyAny, PyResult, PyTypeInfo, Python}; @@ -30,6 +32,9 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&[T]>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { self.as_slice().into_pyobject(py) diff --git a/src/conversions/std/cstring.rs b/src/conversions/std/cstring.rs index 3e13619f0c5..e0b2a22f076 100644 --- a/src/conversions/std/cstring.rs +++ b/src/conversions/std/cstring.rs @@ -1,3 +1,7 @@ +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::types::PyString; use crate::{Borrowed, Bound, FromPyObject, IntoPyObject, PyAny, PyErr, Python}; use std::borrow::Cow; @@ -14,6 +18,9 @@ impl<'py> IntoPyObject<'py> for &CStr { type Output = Bound<'py, Self::Target>; type Error = Utf8Error; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&str>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { self.to_str()?.into_pyobject(py).map_err(|err| match err {}) @@ -25,6 +32,9 @@ impl<'py> IntoPyObject<'py> for CString { type Output = Bound<'py, Self::Target>; type Error = Utf8Error; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&CStr>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (&*self).into_pyobject(py) @@ -36,6 +46,9 @@ impl<'py> IntoPyObject<'py> for &CString { type Output = Bound<'py, Self::Target>; type Error = Utf8Error; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&CStr>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (&**self).into_pyobject(py) @@ -47,6 +60,9 @@ impl<'py> IntoPyObject<'py> for Cow<'_, CStr> { type Output = Bound<'py, Self::Target>; type Error = Utf8Error; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&CStr>::OUTPUT_TYPE; + fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) } @@ -57,6 +73,9 @@ impl<'py> IntoPyObject<'py> for &Cow<'_, CStr> { type Output = Bound<'py, Self::Target>; type Error = Utf8Error; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&CStr>::OUTPUT_TYPE; + fn into_pyobject(self, py: Python<'py>) -> Result { (&**self).into_pyobject(py) } @@ -66,6 +85,9 @@ impl<'py> IntoPyObject<'py> for &Cow<'_, CStr> { impl<'a> FromPyObject<'a, '_> for &'a CStr { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; + fn extract(obj: Borrowed<'a, '_, PyAny>) -> Result { let obj = obj.cast::()?; let mut size = 0; @@ -87,6 +109,9 @@ impl<'a> FromPyObject<'a, '_> for &'a CStr { impl<'a> FromPyObject<'a, '_> for Cow<'a, CStr> { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; + fn extract(obj: Borrowed<'a, '_, PyAny>) -> Result { #[cfg(any(Py_3_10, not(Py_LIMITED_API)))] { @@ -102,6 +127,9 @@ impl<'a> FromPyObject<'a, '_> for Cow<'a, CStr> { impl FromPyObject<'_, '_> for CString { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; + fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result { #[cfg(any(Py_3_10, not(Py_LIMITED_API)))] { diff --git a/src/conversions/std/ipaddr.rs b/src/conversions/std/ipaddr.rs index 6fb1859d196..acfab176a1a 100644 --- a/src/conversions/std/ipaddr.rs +++ b/src/conversions/std/ipaddr.rs @@ -1,16 +1,23 @@ -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - use crate::conversion::IntoPyObject; use crate::exceptions::PyValueError; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::sync::PyOnceLock; use crate::types::any::PyAnyMethods; use crate::types::string::PyStringMethods; use crate::types::PyType; use crate::{intern, Borrowed, Bound, FromPyObject, Py, PyAny, PyErr, Python}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; impl FromPyObject<'_, '_> for IpAddr { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = TypeHint::union(&[ + TypeHint::module_attr("ipaddress", "IPv4Address"), + TypeHint::module_attr("ipaddress", "IPv6Address"), + ]); + fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result { match obj.getattr(intern!(obj.py(), "packed")) { Ok(packed) => { @@ -35,6 +42,9 @@ impl<'py> IntoPyObject<'py> for Ipv4Addr { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::module_attr("ipaddress", "IPv4Address"); + fn into_pyobject(self, py: Python<'py>) -> Result { static IPV4_ADDRESS: PyOnceLock> = PyOnceLock::new(); IPV4_ADDRESS @@ -48,6 +58,9 @@ impl<'py> IntoPyObject<'py> for &Ipv4Addr { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = Ipv4Addr::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -59,6 +72,9 @@ impl<'py> IntoPyObject<'py> for Ipv6Addr { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::module_attr("ipaddress", "IPv6Address"); + fn into_pyobject(self, py: Python<'py>) -> Result { static IPV6_ADDRESS: PyOnceLock> = PyOnceLock::new(); IPV6_ADDRESS @@ -72,6 +88,9 @@ impl<'py> IntoPyObject<'py> for &Ipv6Addr { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = Ipv6Addr::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -83,6 +102,9 @@ impl<'py> IntoPyObject<'py> for IpAddr { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::union(&[Ipv4Addr::OUTPUT_TYPE, Ipv6Addr::OUTPUT_TYPE]); + fn into_pyobject(self, py: Python<'py>) -> Result { match self { IpAddr::V4(ip) => ip.into_pyobject(py), @@ -96,6 +118,9 @@ impl<'py> IntoPyObject<'py> for &IpAddr { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = IpAddr::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) diff --git a/src/conversions/std/map.rs b/src/conversions/std/map.rs index ad9282bc720..7863530336d 100644 --- a/src/conversions/std/map.rs +++ b/src/conversions/std/map.rs @@ -1,13 +1,16 @@ -use std::{cmp, collections, hash}; - #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::{ conversion::{FromPyObjectOwned, IntoPyObject}, instance::Bound, types::{any::PyAnyMethods, dict::PyDictMethods, PyDict}, Borrowed, FromPyObject, PyAny, PyErr, Python, }; +use std::{cmp, collections, hash}; impl<'py, K, V, H> IntoPyObject<'py> for collections::HashMap where @@ -19,6 +22,10 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = + TypeHint::subscript(&PyDict::TYPE_HINT, &[K::OUTPUT_TYPE, V::OUTPUT_TYPE]); + fn into_pyobject(self, py: Python<'py>) -> Result { let dict = PyDict::new(py); for (k, v) in self { @@ -43,6 +50,10 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = + TypeHint::subscript(&PyDict::TYPE_HINT, &[<&K>::OUTPUT_TYPE, <&V>::OUTPUT_TYPE]); + fn into_pyobject(self, py: Python<'py>) -> Result { let dict = PyDict::new(py); for (k, v) in self { @@ -66,6 +77,10 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = + TypeHint::subscript(&PyDict::TYPE_HINT, &[K::OUTPUT_TYPE, V::OUTPUT_TYPE]); + fn into_pyobject(self, py: Python<'py>) -> Result { let dict = PyDict::new(py); for (k, v) in self { @@ -91,6 +106,10 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = + TypeHint::subscript(&PyDict::TYPE_HINT, &[<&K>::OUTPUT_TYPE, <&V>::OUTPUT_TYPE]); + fn into_pyobject(self, py: Python<'py>) -> Result { let dict = PyDict::new(py); for (k, v) in self { @@ -113,6 +132,10 @@ where { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = + TypeHint::subscript(&PyDict::TYPE_HINT, &[K::INPUT_TYPE, V::INPUT_TYPE]); + fn extract(ob: Borrowed<'_, 'py, PyAny>) -> Result { let dict = ob.cast::()?; let mut ret = collections::HashMap::with_capacity_and_hasher(dict.len(), S::default()); @@ -138,6 +161,10 @@ where { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = + TypeHint::subscript(&PyDict::TYPE_HINT, &[K::INPUT_TYPE, V::INPUT_TYPE]); + fn extract(ob: Borrowed<'_, 'py, PyAny>) -> Result { let dict = ob.cast::()?; let mut ret = collections::BTreeMap::new(); diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index 2697069b6b5..3f24971f929 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -6,6 +6,8 @@ use crate::inspect::types::TypeInfo; #[cfg(feature = "experimental-inspect")] use crate::inspect::TypeHint; use crate::py_result_ext::PyResultExt; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::types::{PyByteArray, PyByteArrayMethods, PyBytes, PyInt}; use crate::{exceptions, ffi, Borrowed, Bound, FromPyObject, PyAny, PyErr, PyResult, Python}; use std::convert::Infallible; @@ -109,7 +111,7 @@ macro_rules! int_convert_u64_or_i64 { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const OUTPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn into_pyobject(self, py: Python<'py>) -> Result { unsafe { @@ -141,7 +143,7 @@ macro_rules! int_convert_u64_or_i64 { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const INPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result<$rust_type, Self::Error> { extract_int!(obj, !0, $pylong_as_ll_or_ull, $force_index_call) @@ -163,7 +165,7 @@ macro_rules! int_fits_c_long { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const OUTPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn into_pyobject(self, py: Python<'py>) -> Result { unsafe { @@ -202,7 +204,7 @@ macro_rules! int_fits_c_long { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const INPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result { let val: c_long = extract_int!(obj, -1, ffi::PyLong_AsLong)?; @@ -224,7 +226,7 @@ impl<'py> IntoPyObject<'py> for u8 { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const OUTPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn into_pyobject(self, py: Python<'py>) -> Result { unsafe { @@ -287,7 +289,7 @@ impl<'py> FromPyObject<'_, 'py> for u8 { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const INPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result { let val: c_long = extract_int!(obj, -1, ffi::PyLong_AsLong)?; @@ -413,7 +415,7 @@ mod fast_128bit_int_conversion { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const OUTPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn into_pyobject(self, py: Python<'py>) -> Result { #[cfg(Py_3_13)] @@ -457,7 +459,7 @@ mod fast_128bit_int_conversion { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const INPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result<$rust_type, Self::Error> { let num = nb_index(&ob)?; @@ -566,7 +568,7 @@ mod slow_128bit_int_conversion { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const OUTPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn into_pyobject(self, py: Python<'py>) -> Result { let lower = (self as u64).into_pyobject(py)?; @@ -611,7 +613,7 @@ mod slow_128bit_int_conversion { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const INPUT_TYPE: TypeHint = PyInt::TYPE_HINT; fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result<$rust_type, Self::Error> { let py = ob.py(); @@ -665,7 +667,7 @@ macro_rules! nonzero_int_impl { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("int"); + const OUTPUT_TYPE: TypeHint = PyInt::TYPE_HINT; #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { diff --git a/src/conversions/std/option.rs b/src/conversions/std/option.rs index 8cec88b4e6b..729fcc56668 100644 --- a/src/conversions/std/option.rs +++ b/src/conversions/std/option.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::{ conversion::IntoPyObject, types::any::PyAnyMethods, BoundObject, FromPyObject, PyAny, Python, }; @@ -10,6 +12,8 @@ where type Target = PyAny; type Output = Bound<'py, Self::Target>; type Error = T::Error; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::union(&[T::OUTPUT_TYPE, TypeHint::builtin("None")]); fn into_pyobject(self, py: Python<'py>) -> Result { self.map_or_else( @@ -30,6 +34,8 @@ where type Target = PyAny; type Output = Bound<'py, Self::Target>; type Error = <&'a T as IntoPyObject<'py>>::Error; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = >::OUTPUT_TYPE; #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { @@ -42,6 +48,8 @@ where T: FromPyObject<'a, 'py>, { type Error = T::Error; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = TypeHint::union(&[T::INPUT_TYPE, TypeHint::builtin("None")]); fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result { if obj.is_none() { diff --git a/src/conversions/std/osstr.rs b/src/conversions/std/osstr.rs index 19383a63128..1efd1f5161d 100644 --- a/src/conversions/std/osstr.rs +++ b/src/conversions/std/osstr.rs @@ -1,6 +1,10 @@ use crate::conversion::IntoPyObject; use crate::ffi_ptr_ext::FfiPtrExt; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::instance::Bound; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::types::PyString; use crate::{ffi, Borrowed, FromPyObject, PyAny, PyErr, Python}; use std::borrow::Cow; @@ -12,6 +16,9 @@ impl<'py> IntoPyObject<'py> for &OsStr { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyString::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { // If the string is UTF-8, take the quick and easy shortcut if let Some(valid_utf8_path) = self.to_str() { @@ -61,6 +68,9 @@ impl<'py> IntoPyObject<'py> for &&OsStr { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&OsStr>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -70,6 +80,9 @@ impl<'py> IntoPyObject<'py> for &&OsStr { impl FromPyObject<'_, '_> for OsString { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; + fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result { let pystring = ob.cast::()?; @@ -135,6 +148,9 @@ impl<'py> IntoPyObject<'py> for Cow<'_, OsStr> { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&OsStr>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -146,6 +162,9 @@ impl<'py> IntoPyObject<'py> for &Cow<'_, OsStr> { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&OsStr>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (&**self).into_pyobject(py) @@ -155,6 +174,9 @@ impl<'py> IntoPyObject<'py> for &Cow<'_, OsStr> { impl<'a> FromPyObject<'a, '_> for Cow<'a, OsStr> { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = OsString::INPUT_TYPE; + fn extract(obj: Borrowed<'a, '_, PyAny>) -> Result { #[cfg(any(Py_3_10, not(Py_LIMITED_API)))] if let Ok(s) = obj.extract::<&str>() { @@ -170,6 +192,9 @@ impl<'py> IntoPyObject<'py> for OsString { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&OsStr>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { self.as_os_str().into_pyobject(py) @@ -181,6 +206,9 @@ impl<'py> IntoPyObject<'py> for &OsString { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&OsStr>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { self.as_os_str().into_pyobject(py) diff --git a/src/conversions/std/path.rs b/src/conversions/std/path.rs index 7a92ca860c4..dd4730cc701 100644 --- a/src/conversions/std/path.rs +++ b/src/conversions/std/path.rs @@ -1,5 +1,7 @@ use crate::conversion::IntoPyObject; use crate::ffi_ptr_ext::FfiPtrExt; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::sync::PyOnceLock; use crate::types::any::PyAnyMethods; use crate::{ffi, Borrowed, Bound, FromPyObject, Py, PyAny, PyErr, Python}; @@ -10,6 +12,12 @@ use std::path::{Path, PathBuf}; impl FromPyObject<'_, '_> for PathBuf { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = TypeHint::union(&[ + OsString::INPUT_TYPE, + TypeHint::module_attr("os", "PathLike"), + ]); + fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result { // We use os.fspath to get the underlying path as bytes or str let path = unsafe { ffi::PyOS_FSPath(ob.as_ptr()).assume_owned_or_err(ob.py())? }; @@ -22,6 +30,9 @@ impl<'py> IntoPyObject<'py> for &Path { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::module_attr("pathlib", "Path"); + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { static PY_PATH: PyOnceLock> = PyOnceLock::new(); @@ -36,6 +47,9 @@ impl<'py> IntoPyObject<'py> for &&Path { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&Path>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -47,6 +61,9 @@ impl<'py> IntoPyObject<'py> for Cow<'_, Path> { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&Path>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -58,6 +75,9 @@ impl<'py> IntoPyObject<'py> for &Cow<'_, Path> { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&Path>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (&**self).into_pyobject(py) @@ -67,6 +87,9 @@ impl<'py> IntoPyObject<'py> for &Cow<'_, Path> { impl<'a> FromPyObject<'a, '_> for Cow<'a, Path> { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PathBuf::INPUT_TYPE; + fn extract(obj: Borrowed<'a, '_, PyAny>) -> Result { #[cfg(any(Py_3_10, not(Py_LIMITED_API)))] if let Ok(s) = obj.extract::<&str>() { @@ -82,6 +105,9 @@ impl<'py> IntoPyObject<'py> for PathBuf { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&Path>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (&self).into_pyobject(py) @@ -93,6 +119,9 @@ impl<'py> IntoPyObject<'py> for &PathBuf { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&Path>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (&**self).into_pyobject(py) diff --git a/src/conversions/std/set.rs b/src/conversions/std/set.rs index f741f02f8d0..584be71b1c9 100644 --- a/src/conversions/std/set.rs +++ b/src/conversions/std/set.rs @@ -2,6 +2,10 @@ use std::{cmp, collections, hash}; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::{ conversion::{FromPyObjectOwned, IntoPyObject}, types::{ @@ -22,6 +26,9 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::subscript(&PySet::TYPE_HINT, &[K::OUTPUT_TYPE]); + fn into_pyobject(self, py: Python<'py>) -> Result { try_new_from_iter(py, self) } @@ -40,6 +47,8 @@ where type Target = PySet; type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::subscript(&PySet::TYPE_HINT, &[<&K>::OUTPUT_TYPE]); fn into_pyobject(self, py: Python<'py>) -> Result { try_new_from_iter(py, self.iter()) @@ -58,6 +67,9 @@ where { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = TypeHint::subscript(&PySet::TYPE_HINT, &[K::INPUT_TYPE]); + fn extract(ob: Borrowed<'_, 'py, PyAny>) -> Result { match ob.cast::() { Ok(set) => set @@ -91,6 +103,9 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::subscript(&PySet::TYPE_HINT, &[K::OUTPUT_TYPE]); + fn into_pyobject(self, py: Python<'py>) -> Result { try_new_from_iter(py, self) } @@ -110,6 +125,9 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = TypeHint::subscript(&PySet::TYPE_HINT, &[<&K>::OUTPUT_TYPE]); + fn into_pyobject(self, py: Python<'py>) -> Result { try_new_from_iter(py, self.iter()) } @@ -126,6 +144,9 @@ where { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = TypeHint::subscript(&PySet::TYPE_HINT, &[K::INPUT_TYPE]); + fn extract(ob: Borrowed<'_, 'py, PyAny>) -> Result { match ob.cast::() { Ok(set) => set diff --git a/src/conversions/std/slice.rs b/src/conversions/std/slice.rs index c9598d1fd31..63ffb6ee368 100644 --- a/src/conversions/std/slice.rs +++ b/src/conversions/std/slice.rs @@ -2,6 +2,10 @@ use std::borrow::Cow; #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::{ conversion::IntoPyObject, types::{PyByteArray, PyByteArrayMethods, PyBytes}, @@ -37,6 +41,9 @@ where impl<'a, 'py> crate::conversion::FromPyObject<'a, 'py> for &'a [u8] { type Error = CastError<'a, 'py>; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyBytes::TYPE_HINT; + fn extract(obj: crate::Borrowed<'a, 'py, PyAny>) -> Result { Ok(obj.cast::()?.as_bytes()) } @@ -55,6 +62,9 @@ impl<'a, 'py> crate::conversion::FromPyObject<'a, 'py> for &'a [u8] { impl<'a, 'py> crate::conversion::FromPyObject<'a, 'py> for Cow<'a, [u8]> { type Error = CastError<'a, 'py>; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = TypeHint::union(&[PyBytes::TYPE_HINT, PyByteArray::TYPE_HINT]); + fn extract(ob: crate::Borrowed<'a, 'py, PyAny>) -> Result { if let Ok(bytes) = ob.cast::() { return Ok(Cow::Borrowed(bytes.as_bytes())); @@ -79,6 +89,9 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&[T]>::OUTPUT_TYPE; + /// Turns `Cow<[u8]>` into [`PyBytes`], all other `T`s will be turned into a [`PyList`] /// /// [`PyBytes`]: crate::types::PyBytes diff --git a/src/conversions/std/string.rs b/src/conversions/std/string.rs index f46c159967d..e6e57def1d2 100644 --- a/src/conversions/std/string.rs +++ b/src/conversions/std/string.rs @@ -2,6 +2,8 @@ use crate::inspect::types::TypeInfo; #[cfg(feature = "experimental-inspect")] use crate::inspect::TypeHint; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::{ conversion::IntoPyObject, instance::Bound, types::PyString, Borrowed, FromPyObject, PyAny, PyErr, Python, @@ -128,7 +130,7 @@ impl<'py> IntoPyObject<'py> for String { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("str"); + const OUTPUT_TYPE: TypeHint = PyString::TYPE_HINT; fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PyString::new(py, &self)) @@ -164,7 +166,7 @@ impl<'a> crate::conversion::FromPyObject<'a, '_> for &'a str { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("str"); + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; fn extract(ob: crate::Borrowed<'a, '_, PyAny>) -> Result { ob.cast::()?.to_str() @@ -180,7 +182,7 @@ impl<'a> crate::conversion::FromPyObject<'a, '_> for Cow<'a, str> { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("str"); + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; fn extract(ob: crate::Borrowed<'a, '_, PyAny>) -> Result { ob.cast::()?.to_cow() @@ -198,7 +200,7 @@ impl FromPyObject<'_, '_> for String { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("str"); + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result { obj.cast::()?.to_cow().map(Cow::into_owned) @@ -214,7 +216,7 @@ impl FromPyObject<'_, '_> for char { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("str"); + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result { let s = obj.cast::()?.to_cow()?; diff --git a/src/conversions/std/time.rs b/src/conversions/std/time.rs index 2081481f8a0..8f36aea14bd 100644 --- a/src/conversions/std/time.rs +++ b/src/conversions/std/time.rs @@ -1,8 +1,12 @@ use crate::conversion::IntoPyObject; use crate::exceptions::{PyOverflowError, PyValueError}; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; #[cfg(Py_LIMITED_API)] use crate::intern; use crate::sync::PyOnceLock; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::types::any::PyAnyMethods; #[cfg(not(Py_LIMITED_API))] use crate::types::PyDeltaAccess; @@ -15,6 +19,9 @@ const SECONDS_PER_DAY: u64 = 24 * 60 * 60; impl FromPyObject<'_, '_> for Duration { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyDelta::TYPE_HINT; + fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result { let delta = obj.cast::()?; #[cfg(not(Py_LIMITED_API))] @@ -57,6 +64,9 @@ impl<'py> IntoPyObject<'py> for Duration { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyDelta::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { let days = self.as_secs() / SECONDS_PER_DAY; let seconds = self.as_secs() % SECONDS_PER_DAY; @@ -77,6 +87,9 @@ impl<'py> IntoPyObject<'py> for &Duration { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = Duration::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) @@ -92,6 +105,9 @@ impl<'py> IntoPyObject<'py> for &Duration { impl FromPyObject<'_, '_> for SystemTime { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT; + fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result { let duration_since_unix_epoch: Duration = obj.sub(unix_epoch_py(obj.py())?)?.extract()?; UNIX_EPOCH @@ -107,6 +123,9 @@ impl<'py> IntoPyObject<'py> for SystemTime { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { let duration_since_unix_epoch = self.duration_since(UNIX_EPOCH).unwrap().into_pyobject(py)?; @@ -122,6 +141,9 @@ impl<'py> IntoPyObject<'py> for &SystemTime { type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = SystemTime::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { (*self).into_pyobject(py) diff --git a/src/conversions/std/vec.rs b/src/conversions/std/vec.rs index c62aa7f1d56..dce39bddf3e 100644 --- a/src/conversions/std/vec.rs +++ b/src/conversions/std/vec.rs @@ -1,5 +1,7 @@ #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::{ conversion::{FromPyObject, FromPyObjectOwned, FromPyObjectSequence, IntoPyObject}, exceptions::PyTypeError, @@ -40,6 +42,9 @@ where type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = <&[T]>::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { // NB: we could actually not cast to `PyAny`, which would be nice for diff --git a/src/err/mod.rs b/src/err/mod.rs index a9686043633..e2ec0660561 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -1,4 +1,7 @@ +use crate::conversion::IntoPyObject; use crate::ffi_ptr_ext::FfiPtrExt; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::instance::Bound; #[cfg(Py_3_11)] use crate::intern; @@ -14,18 +17,16 @@ use crate::types::{ }; use crate::{exceptions::PyBaseException, ffi}; use crate::{BoundObject, Py, PyAny, Python}; +use err_state::{PyErrState, PyErrStateLazyFnOutput, PyErrStateNormalized}; +use std::convert::Infallible; use std::ffi::CStr; +use std::ptr; mod cast_error; mod downcast_error; mod err_state; mod impls; -use crate::conversion::IntoPyObject; -use err_state::{PyErrState, PyErrStateLazyFnOutput, PyErrStateNormalized}; -use std::convert::Infallible; -use std::ptr; - pub use cast_error::{CastError, CastIntoError}; #[allow(deprecated)] pub use downcast_error::{DowncastError, DowncastIntoError}; @@ -674,6 +675,9 @@ impl<'py> IntoPyObject<'py> for PyErr { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyBaseException::TYPE_HINT; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { Ok(self.into_value(py).into_bound(py)) @@ -685,6 +689,9 @@ impl<'py> IntoPyObject<'py> for &PyErr { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyErr::OUTPUT_TYPE; + #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { self.clone_ref(py).into_pyobject(py) diff --git a/src/impl_/extract_argument.rs b/src/impl_/extract_argument.rs index 8b5f94ad4dd..b0aa3adf400 100644 --- a/src/impl_/extract_argument.rs +++ b/src/impl_/extract_argument.rs @@ -1,5 +1,7 @@ #[cfg(feature = "experimental-inspect")] use crate::inspect::TypeHint; +#[cfg(any(Py_3_10, not(Py_LIMITED_API), feature = "experimental-inspect"))] +use crate::types::PyString; use crate::{ exceptions::PyTypeError, ffi, @@ -108,10 +110,7 @@ where type Error = T::Error; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::union(&[ - TypeHint::module_attr("typing", "Any"), - TypeHint::builtin("None"), - ]); + const INPUT_TYPE: TypeHint = TypeHint::union(&[T::INPUT_TYPE, TypeHint::builtin("None")]); #[inline] fn extract( @@ -132,7 +131,7 @@ impl<'a, 'holder, 'py> PyFunctionArgument<'a, 'holder, 'py, false> for &'holder type Error = as FromPyObject<'a, 'py>>::Error; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("str"); + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; #[inline] fn extract( @@ -504,8 +503,7 @@ impl FunctionDescription { // Safety: All keyword arguments should be UTF-8 strings, but if it's not, `.to_str()` // will return an error anyway. #[cfg(any(Py_3_10, not(Py_LIMITED_API)))] - let kwarg_name = - unsafe { kwarg_name_py.cast_unchecked::() }.to_str(); + let kwarg_name = unsafe { kwarg_name_py.cast_unchecked::() }.to_str(); #[cfg(all(not(Py_3_10), Py_LIMITED_API))] let kwarg_name = kwarg_name_py.extract::(); diff --git a/src/pybacked.rs b/src/pybacked.rs index 44aae83dc17..ba891c90012 100644 --- a/src/pybacked.rs +++ b/src/pybacked.rs @@ -1,7 +1,7 @@ //! Contains types for working with Python objects that own the underlying data. -use std::{convert::Infallible, ops::Deref, ptr::NonNull, sync::Arc}; - +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; use crate::{ types::{ bytearray::PyByteArrayMethods, bytes::PyBytesMethods, string::PyStringMethods, PyByteArray, @@ -9,6 +9,7 @@ use crate::{ }, Borrowed, Bound, CastError, FromPyObject, IntoPyObject, Py, PyAny, PyErr, PyTypeInfo, Python, }; +use std::{convert::Infallible, ops::Deref, ptr::NonNull, sync::Arc}; /// A wrapper around `str` where the storage is owned by a Python `bytes` or `str` object. /// @@ -84,6 +85,9 @@ impl TryFrom> for PyBackedStr { impl FromPyObject<'_, '_> for PyBackedStr { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyString::TYPE_HINT; + fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result { let py_string = obj.cast::()?.to_owned(); Self::try_from(py_string) @@ -95,6 +99,9 @@ impl<'py> IntoPyObject<'py> for PyBackedStr { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyString::TYPE_HINT; + #[cfg(any(Py_3_10, not(Py_LIMITED_API)))] fn into_pyobject(self, py: Python<'py>) -> Result { Ok(self.storage.into_bound(py)) @@ -111,6 +118,9 @@ impl<'py> IntoPyObject<'py> for &PyBackedStr { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyString::TYPE_HINT; + #[cfg(any(Py_3_10, not(Py_LIMITED_API)))] fn into_pyobject(self, py: Python<'py>) -> Result { Ok(self.storage.bind(py).to_owned()) @@ -207,6 +217,9 @@ impl From> for PyBackedBytes { impl<'a, 'py> FromPyObject<'a, 'py> for PyBackedBytes { type Error = CastError<'a, 'py>; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = PyBytes::TYPE_HINT; + fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result { if let Ok(bytes) = obj.cast::() { Ok(Self::from(bytes.to_owned())) @@ -234,6 +247,9 @@ impl<'py> IntoPyObject<'py> for PyBackedBytes { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyBytes::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { match self.storage { PyBackedBytesStorage::Python(bytes) => Ok(bytes.into_bound(py)), @@ -247,6 +263,9 @@ impl<'py> IntoPyObject<'py> for &PyBackedBytes { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PyBytes::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { match &self.storage { PyBackedBytesStorage::Python(bytes) => Ok(bytes.bind(py).clone()), diff --git a/src/pyclass/guard.rs b/src/pyclass/guard.rs index 324d435f705..96ffaac10a3 100644 --- a/src/pyclass/guard.rs +++ b/src/pyclass/guard.rs @@ -282,6 +282,9 @@ impl Deref for PyClassGuard<'_, T> { impl<'a, 'py, T: PyClass> FromPyObject<'a, 'py> for PyClassGuard<'a, T> { type Error = PyClassGuardError<'a, 'py>; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = T::TYPE_HINT; + fn extract(obj: Borrowed<'a, 'py, crate::PyAny>) -> Result { Self::try_from_class_object( obj.cast() @@ -297,6 +300,9 @@ impl<'a, 'py, T: PyClass> IntoPyObject<'py> for PyClassGuard<'a, T> { type Output = Borrowed<'a, 'py, T>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = T::TYPE_HINT; + #[inline] fn into_pyobject(self, py: crate::Python<'py>) -> Result { (&self).into_pyobject(py) @@ -684,6 +690,9 @@ impl> DerefMut for PyClassGuardMut<'_, T> { impl<'a, 'py, T: PyClass> FromPyObject<'a, 'py> for PyClassGuardMut<'a, T> { type Error = PyClassGuardMutError<'a, 'py>; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: TypeHint = T::TYPE_HINT; + fn extract(obj: Borrowed<'a, 'py, crate::PyAny>) -> Result { Self::try_from_class_object( obj.cast() @@ -699,6 +708,9 @@ impl<'a, 'py, T: PyClass> IntoPyObject<'py> for PyClassGuardMut< type Output = Borrowed<'a, 'py, T>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = T::TYPE_HINT; + #[inline] fn into_pyobject(self, py: crate::Python<'py>) -> Result { (&self).into_pyobject(py) @@ -710,6 +722,9 @@ impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &PyClassGuardMut type Output = Borrowed<'a, 'py, T>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = T::TYPE_HINT; + #[inline] fn into_pyobject(self, py: crate::Python<'py>) -> Result { // SAFETY: `ptr` is guaranteed to be valid for 'a and points to an diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 8dec681c56c..cc33932a724 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -4,6 +4,8 @@ use crate::conversion::IntoPyObject; use crate::inspect::types::TypeInfo; #[cfg(feature = "experimental-inspect")] use crate::inspect::TypeHint; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::PyErr; use crate::{ exceptions::PyTypeError, ffi, ffi_ptr_ext::FfiPtrExt, instance::Bound, @@ -145,7 +147,7 @@ impl<'py> IntoPyObject<'py> for bool { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("bool"); + const OUTPUT_TYPE: TypeHint = PyBool::TYPE_HINT; #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { @@ -184,7 +186,7 @@ impl FromPyObject<'_, '_> for bool { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("bool"); + const INPUT_TYPE: TypeHint = PyBool::TYPE_HINT; fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result { let err = match obj.cast::() { diff --git a/src/types/float.rs b/src/types/float.rs index 7e5b2e45ab0..daaebea4d66 100644 --- a/src/types/float.rs +++ b/src/types/float.rs @@ -3,6 +3,8 @@ use crate::conversion::IntoPyObject; use crate::inspect::types::TypeInfo; #[cfg(feature = "experimental-inspect")] use crate::inspect::TypeHint; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::{ ffi, ffi_ptr_ext::FfiPtrExt, instance::Bound, Borrowed, FromPyObject, PyAny, PyErr, Python, }; @@ -77,7 +79,7 @@ impl<'py> IntoPyObject<'py> for f64 { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("float"); + const OUTPUT_TYPE: TypeHint = PyFloat::TYPE_HINT; #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { @@ -113,7 +115,7 @@ impl<'py> FromPyObject<'_, 'py> for f64 { type Error = PyErr; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("float"); + const INPUT_TYPE: TypeHint = PyFloat::TYPE_HINT; // PyFloat_AsDouble returns -1.0 upon failure #[allow(clippy::float_cmp)] @@ -150,7 +152,7 @@ impl<'py> IntoPyObject<'py> for f32 { type Error = Infallible; #[cfg(feature = "experimental-inspect")] - const OUTPUT_TYPE: TypeHint = TypeHint::builtin("float"); + const OUTPUT_TYPE: TypeHint = PyFloat::TYPE_HINT; #[inline] fn into_pyobject(self, py: Python<'py>) -> Result { @@ -186,7 +188,7 @@ impl<'a, 'py> FromPyObject<'a, 'py> for f32 { type Error = >::Error; #[cfg(feature = "experimental-inspect")] - const INPUT_TYPE: TypeHint = TypeHint::builtin("float"); + const INPUT_TYPE: TypeHint = PyFloat::TYPE_HINT; fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result { Ok(obj.extract::()? as f32) diff --git a/src/types/slice.rs b/src/types/slice.rs index 89af67687de..4203c37b890 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -1,6 +1,10 @@ use crate::err::{PyErr, PyResult}; use crate::ffi; use crate::ffi_ptr_ext::FfiPtrExt; +#[cfg(feature = "experimental-inspect")] +use crate::inspect::TypeHint; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::types::{PyRange, PyRangeMethods}; use crate::{Bound, IntoPyObject, PyAny, Python}; use std::convert::Infallible; @@ -127,6 +131,9 @@ impl<'py> IntoPyObject<'py> for PySliceIndices { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PySlice::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PySlice::new(py, self.start, self.stop, self.step)) } @@ -137,6 +144,9 @@ impl<'py> IntoPyObject<'py> for &PySliceIndices { type Output = Bound<'py, Self::Target>; type Error = Infallible; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: TypeHint = PySlice::TYPE_HINT; + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(PySlice::new(py, self.start, self.stop, self.step)) } diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 8dab7d5ffba..76612b94271 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -4,6 +4,8 @@ use crate::ffi_ptr_ext::FfiPtrExt; use crate::inspect::types::TypeInfo; use crate::instance::Borrowed; use crate::internal_tricks::get_ssize_index; +#[cfg(feature = "experimental-inspect")] +use crate::type_object::PyTypeInfo; use crate::types::{sequence::PySequenceMethods, PyList, PySequence}; use crate::{ exceptions, Bound, FromPyObject, IntoPyObject, IntoPyObjectExt, PyAny, PyErr, PyResult, Python, @@ -611,6 +613,12 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: crate::inspect::TypeHint = crate::inspect::TypeHint::subscript( + &PyTuple::TYPE_HINT, + &[$($T::OUTPUT_TYPE ),+] + ); + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(array_into_tuple(py, [$(self.$n.into_bound_py_any(py)?),+])) } @@ -629,6 +637,12 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ type Output = Bound<'py, Self::Target>; type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const OUTPUT_TYPE: crate::inspect::TypeHint = crate::inspect::TypeHint::subscript( + &PyTuple::TYPE_HINT, + &[$(<&$T>::OUTPUT_TYPE ),+] + ); + fn into_pyobject(self, py: Python<'py>) -> Result { Ok(array_into_tuple(py, [$(self.$n.into_bound_py_any(py)?),+])) } @@ -899,6 +913,12 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ impl<'a, 'py, $($T: FromPyObject<'a, 'py>),+> FromPyObject<'a, 'py> for ($($T,)+) { type Error = PyErr; + #[cfg(feature = "experimental-inspect")] + const INPUT_TYPE: crate::inspect::TypeHint = crate::inspect::TypeHint::subscript( + &PyTuple::TYPE_HINT, + &[$($T::INPUT_TYPE ),+] + ); + fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result { let t = obj.cast::()?;