Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/5637.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Introspection: Fill INPUT_TYPE and OUTPUT_TYPE nearly everywhere
16 changes: 9 additions & 7 deletions pytests/stubs/pyfunctions.pyi
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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]: ...
5 changes: 5 additions & 0 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -199,6 +201,9 @@ pub unsafe trait Element: Copy {
impl<T: Element> FromPyObject<'_, '_> for PyBuffer<T> {
type Error = PyErr;

#[cfg(feature = "experimental-inspect")]
const INPUT_TYPE: TypeHint = TypeHint::module_attr("collections.abc", "Buffer");

fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result<PyBuffer<T>, Self::Error> {
Self::get(&obj)
}
Expand Down
70 changes: 70 additions & 0 deletions src/conversions/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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<Self::Output, Self::Error> {
// Total number of days
let days = self.num_days();
Expand Down Expand Up @@ -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::Output, Self::Error> {
(*self).into_pyobject(py)
Expand All @@ -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<Self, Self::Error> {
let delta = ob.cast::<PyDelta>()?;
// Python size are much lower than rust size so we do not need bound checks.
Expand Down Expand Up @@ -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<Self::Output, Self::Error> {
let DateArgs { year, month, day } = (&self).into();
PyDate::new(py, year, month, day)
Expand All @@ -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::Output, Self::Error> {
(*self).into_pyobject(py)
Expand All @@ -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<Self, Self::Error> {
let date = &*ob.cast::<PyDate>()?;
py_date_to_naive_date(date)
Expand All @@ -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<Self::Output, Self::Error> {
let TimeArgs {
hour,
Expand All @@ -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::Output, Self::Error> {
(*self).into_pyobject(py)
Expand All @@ -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<Self, Self::Error> {
let time = &*ob.cast::<PyTime>()?;
py_time_to_naive_time(time)
Expand All @@ -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<Self::Output, Self::Error> {
let DateArgs { year, month, day } = (&self.date()).into();
let TimeArgs {
Expand All @@ -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::Output, Self::Error> {
(*self).into_pyobject(py)
Expand All @@ -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<Self, Self::Error> {
let dt = &*dt.cast::<PyDateTime>()?;

Expand All @@ -280,6 +320,9 @@ where
type Output = Bound<'py, Self::Target>;
type Error = PyErr;

#[cfg(feature = "experimental-inspect")]
const OUTPUT_TYPE: TypeHint = <&DateTime<Tz>>::OUTPUT_TYPE;

#[inline]
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
(&self).into_pyobject(py)
Expand All @@ -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<Self::Output, Self::Error> {
let tz = self.timezone().into_bound_py_any(py)?.cast_into()?;

Expand Down Expand Up @@ -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<Self, Self::Error> {
let dt = &*dt.cast::<PyDateTime>()?;
let tzinfo = dt.get_tzinfo();
Expand Down Expand Up @@ -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<Self::Output, Self::Error> {
let seconds_offset = self.local_minus_utc();
let td = PyDelta::new(py, 0, seconds_offset, 0, true)?;
Expand All @@ -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::Output, Self::Error> {
(*self).into_pyobject(py)
Expand All @@ -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
Expand Down Expand Up @@ -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<Self::Output, Self::Error> {
PyTzInfo::utc(py)
}
Expand All @@ -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::Output, Self::Error> {
(*self).into_pyobject(py)
Expand All @@ -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<Self::Output, Self::Error> {
static LOCAL_TZ: PyOnceLock<Py<PyTzInfo>> = PyOnceLock::new();
let tz = LOCAL_TZ
Expand All @@ -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::Output, Self::Error> {
(*self).into_pyobject(py)
Expand Down
10 changes: 10 additions & 0 deletions src/conversions/chrono_tz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Self::Output, Self::Error> {
PyTzInfo::timezone(py, self.name())
}
Expand All @@ -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::Output, Self::Error> {
(*self).into_pyobject(py)
Expand Down
5 changes: 5 additions & 0 deletions src/conversions/std/array.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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::Output, Self::Error> {
self.as_slice().into_pyobject(py)
Expand Down
Loading
Loading