Skip to content

Commit 7c63f18

Browse files
committed
Introspection: Declare INPUT_TYPE and OUTPUT_TYPE nearly everywhere
Slice and lists are not done yet, it should be the focus of a specific MR (non-trivial support of the bytes special case)
1 parent d8e9a38 commit 7c63f18

File tree

26 files changed

+420
-45
lines changed

26 files changed

+420
-45
lines changed

newsfragments/5637.changed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Introspection: Fill INPUT_TYPE and OUTPUT_TYPE nearly everywhere

pytests/stubs/pyfunctions.pyi

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Any
22

3-
def args_kwargs(*args, **kwargs) -> Any: ...
3+
def args_kwargs(*args, **kwargs) -> tuple[Any, Any | None]: ...
44
def many_keyword_arguments(
55
*,
66
ant: object | None = None,
@@ -21,20 +21,22 @@ def many_keyword_arguments(
2121
penguin: object | None = None,
2222
) -> None: ...
2323
def none() -> None: ...
24-
def positional_only(a: object, /, b: object) -> Any: ...
25-
def simple(a: object, b: object | None = None, *, c: object | None = None) -> Any: ...
24+
def positional_only(a: object, /, b: object) -> tuple[Any, Any]: ...
25+
def simple(
26+
a: object, b: object | None = None, *, c: object | None = None
27+
) -> tuple[Any, Any | None, Any | None]: ...
2628
def simple_args(
2729
a: object, b: object | None = None, *args, c: object | None = None
28-
) -> Any: ...
30+
) -> tuple[Any, Any | None, Any, Any | None]: ...
2931
def simple_args_kwargs(
3032
a: object, b: object | None = None, *args, c: object | None = None, **kwargs
31-
) -> Any: ...
33+
) -> tuple[Any, Any | None, Any, Any | None, Any | None]: ...
3234
def simple_kwargs(
3335
a: object, b: object | None = None, c: object | None = None, **kwargs
34-
) -> Any: ...
36+
) -> tuple[Any, Any | None, Any | None, Any | None]: ...
3537
def with_custom_type_annotations(
3638
a: int, *_args: str, _b: int | None = None, **_kwargs: bool
3739
) -> int: ...
3840
def with_typed_args(
3941
a: bool = False, b: int = 0, c: float = 0.0, d: str = ""
40-
) -> Any: ...
42+
) -> tuple[bool, int, float, str]: ...

src/buffer.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
// DEALINGS IN THE SOFTWARE.
1919

2020
//! `PyBuffer` implementation
21+
#[cfg(feature = "experimental-inspect")]
22+
use crate::inspect::TypeHint;
2123
use crate::{err, exceptions::PyBufferError, ffi, FromPyObject, PyAny, PyResult, Python};
2224
use crate::{Borrowed, Bound, PyErr};
2325
use std::ffi::{
@@ -199,6 +201,9 @@ pub unsafe trait Element: Copy {
199201
impl<T: Element> FromPyObject<'_, '_> for PyBuffer<T> {
200202
type Error = PyErr;
201203

204+
#[cfg(feature = "experimental-inspect")]
205+
const INPUT_TYPE: TypeHint = TypeHint::module_attr("collections.abc", "Buffer");
206+
202207
fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result<PyBuffer<T>, Self::Error> {
203208
Self::get(&obj)
204209
}

src/conversions/chrono.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@
4343
4444
use crate::conversion::{FromPyObjectOwned, IntoPyObject};
4545
use crate::exceptions::{PyTypeError, PyUserWarning, PyValueError};
46+
#[cfg(feature = "experimental-inspect")]
47+
use crate::inspect::TypeHint;
4648
use crate::intern;
49+
#[cfg(feature = "experimental-inspect")]
50+
use crate::type_object::PyTypeInfo;
4751
use crate::types::any::PyAnyMethods;
4852
use crate::types::PyNone;
4953
use crate::types::{PyDate, PyDateTime, PyDelta, PyTime, PyTzInfo, PyTzInfoAccess};
@@ -70,6 +74,9 @@ impl<'py> IntoPyObject<'py> for Duration {
7074
type Output = Bound<'py, Self::Target>;
7175
type Error = PyErr;
7276

77+
#[cfg(feature = "experimental-inspect")]
78+
const OUTPUT_TYPE: TypeHint = PyDelta::TYPE_HINT;
79+
7380
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
7481
// Total number of days
7582
let days = self.num_days();
@@ -102,6 +109,9 @@ impl<'py> IntoPyObject<'py> for &Duration {
102109
type Output = Bound<'py, Self::Target>;
103110
type Error = PyErr;
104111

112+
#[cfg(feature = "experimental-inspect")]
113+
const OUTPUT_TYPE: TypeHint = Duration::OUTPUT_TYPE;
114+
105115
#[inline]
106116
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
107117
(*self).into_pyobject(py)
@@ -111,6 +121,9 @@ impl<'py> IntoPyObject<'py> for &Duration {
111121
impl FromPyObject<'_, '_> for Duration {
112122
type Error = PyErr;
113123

124+
#[cfg(feature = "experimental-inspect")]
125+
const INPUT_TYPE: TypeHint = PyDelta::TYPE_HINT;
126+
114127
fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result<Self, Self::Error> {
115128
let delta = ob.cast::<PyDelta>()?;
116129
// 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 {
147160
type Output = Bound<'py, Self::Target>;
148161
type Error = PyErr;
149162

163+
#[cfg(feature = "experimental-inspect")]
164+
const OUTPUT_TYPE: TypeHint = PyDate::TYPE_HINT;
165+
150166
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
151167
let DateArgs { year, month, day } = (&self).into();
152168
PyDate::new(py, year, month, day)
@@ -158,6 +174,9 @@ impl<'py> IntoPyObject<'py> for &NaiveDate {
158174
type Output = Bound<'py, Self::Target>;
159175
type Error = PyErr;
160176

177+
#[cfg(feature = "experimental-inspect")]
178+
const OUTPUT_TYPE: TypeHint = NaiveDate::OUTPUT_TYPE;
179+
161180
#[inline]
162181
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
163182
(*self).into_pyobject(py)
@@ -167,6 +186,9 @@ impl<'py> IntoPyObject<'py> for &NaiveDate {
167186
impl FromPyObject<'_, '_> for NaiveDate {
168187
type Error = PyErr;
169188

189+
#[cfg(feature = "experimental-inspect")]
190+
const INPUT_TYPE: TypeHint = PyDate::TYPE_HINT;
191+
170192
fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result<Self, Self::Error> {
171193
let date = &*ob.cast::<PyDate>()?;
172194
py_date_to_naive_date(date)
@@ -178,6 +200,9 @@ impl<'py> IntoPyObject<'py> for NaiveTime {
178200
type Output = Bound<'py, Self::Target>;
179201
type Error = PyErr;
180202

203+
#[cfg(feature = "experimental-inspect")]
204+
const OUTPUT_TYPE: TypeHint = PyTime::TYPE_HINT;
205+
181206
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
182207
let TimeArgs {
183208
hour,
@@ -202,6 +227,9 @@ impl<'py> IntoPyObject<'py> for &NaiveTime {
202227
type Output = Bound<'py, Self::Target>;
203228
type Error = PyErr;
204229

230+
#[cfg(feature = "experimental-inspect")]
231+
const OUTPUT_TYPE: TypeHint = NaiveTime::OUTPUT_TYPE;
232+
205233
#[inline]
206234
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
207235
(*self).into_pyobject(py)
@@ -211,6 +239,9 @@ impl<'py> IntoPyObject<'py> for &NaiveTime {
211239
impl FromPyObject<'_, '_> for NaiveTime {
212240
type Error = PyErr;
213241

242+
#[cfg(feature = "experimental-inspect")]
243+
const INPUT_TYPE: TypeHint = PyTime::TYPE_HINT;
244+
214245
fn extract(ob: Borrowed<'_, '_, PyAny>) -> Result<Self, Self::Error> {
215246
let time = &*ob.cast::<PyTime>()?;
216247
py_time_to_naive_time(time)
@@ -222,6 +253,9 @@ impl<'py> IntoPyObject<'py> for NaiveDateTime {
222253
type Output = Bound<'py, Self::Target>;
223254
type Error = PyErr;
224255

256+
#[cfg(feature = "experimental-inspect")]
257+
const OUTPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT;
258+
225259
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
226260
let DateArgs { year, month, day } = (&self.date()).into();
227261
let TimeArgs {
@@ -247,6 +281,9 @@ impl<'py> IntoPyObject<'py> for &NaiveDateTime {
247281
type Output = Bound<'py, Self::Target>;
248282
type Error = PyErr;
249283

284+
#[cfg(feature = "experimental-inspect")]
285+
const OUTPUT_TYPE: TypeHint = NaiveDateTime::OUTPUT_TYPE;
286+
250287
#[inline]
251288
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
252289
(*self).into_pyobject(py)
@@ -256,6 +293,9 @@ impl<'py> IntoPyObject<'py> for &NaiveDateTime {
256293
impl FromPyObject<'_, '_> for NaiveDateTime {
257294
type Error = PyErr;
258295

296+
#[cfg(feature = "experimental-inspect")]
297+
const INPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT;
298+
259299
fn extract(dt: Borrowed<'_, '_, PyAny>) -> Result<Self, Self::Error> {
260300
let dt = &*dt.cast::<PyDateTime>()?;
261301

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

323+
#[cfg(feature = "experimental-inspect")]
324+
const OUTPUT_TYPE: TypeHint = <&DateTime<Tz>>::OUTPUT_TYPE;
325+
283326
#[inline]
284327
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
285328
(&self).into_pyobject(py)
@@ -294,6 +337,9 @@ where
294337
type Output = Bound<'py, Self::Target>;
295338
type Error = PyErr;
296339

340+
#[cfg(feature = "experimental-inspect")]
341+
const OUTPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT;
342+
297343
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
298344
let tz = self.timezone().into_bound_py_any(py)?.cast_into()?;
299345

@@ -338,6 +384,9 @@ where
338384
{
339385
type Error = PyErr;
340386

387+
#[cfg(feature = "experimental-inspect")]
388+
const INPUT_TYPE: TypeHint = PyDateTime::TYPE_HINT;
389+
341390
fn extract(dt: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
342391
let dt = &*dt.cast::<PyDateTime>()?;
343392
let tzinfo = dt.get_tzinfo();
@@ -365,6 +414,9 @@ impl<'py> IntoPyObject<'py> for FixedOffset {
365414
type Output = Bound<'py, Self::Target>;
366415
type Error = PyErr;
367416

417+
#[cfg(feature = "experimental-inspect")]
418+
const OUTPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT;
419+
368420
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
369421
let seconds_offset = self.local_minus_utc();
370422
let td = PyDelta::new(py, 0, seconds_offset, 0, true)?;
@@ -377,6 +429,9 @@ impl<'py> IntoPyObject<'py> for &FixedOffset {
377429
type Output = Bound<'py, Self::Target>;
378430
type Error = PyErr;
379431

432+
#[cfg(feature = "experimental-inspect")]
433+
const OUTPUT_TYPE: TypeHint = FixedOffset::OUTPUT_TYPE;
434+
380435
#[inline]
381436
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
382437
(*self).into_pyobject(py)
@@ -386,6 +441,9 @@ impl<'py> IntoPyObject<'py> for &FixedOffset {
386441
impl FromPyObject<'_, '_> for FixedOffset {
387442
type Error = PyErr;
388443

444+
#[cfg(feature = "experimental-inspect")]
445+
const INPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT;
446+
389447
/// Convert python tzinfo to rust [`FixedOffset`].
390448
///
391449
/// Note that the conversion will result in precision lost in microseconds as chrono offset
@@ -418,6 +476,9 @@ impl<'py> IntoPyObject<'py> for Utc {
418476
type Output = Borrowed<'static, 'py, Self::Target>;
419477
type Error = PyErr;
420478

479+
#[cfg(feature = "experimental-inspect")]
480+
const OUTPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT;
481+
421482
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
422483
PyTzInfo::utc(py)
423484
}
@@ -428,6 +489,9 @@ impl<'py> IntoPyObject<'py> for &Utc {
428489
type Output = Borrowed<'static, 'py, Self::Target>;
429490
type Error = PyErr;
430491

492+
#[cfg(feature = "experimental-inspect")]
493+
const OUTPUT_TYPE: TypeHint = Utc::OUTPUT_TYPE;
494+
431495
#[inline]
432496
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
433497
(*self).into_pyobject(py)
@@ -453,6 +517,9 @@ impl<'py> IntoPyObject<'py> for Local {
453517
type Output = Borrowed<'static, 'py, Self::Target>;
454518
type Error = PyErr;
455519

520+
#[cfg(feature = "experimental-inspect")]
521+
const OUTPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT;
522+
456523
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
457524
static LOCAL_TZ: PyOnceLock<Py<PyTzInfo>> = PyOnceLock::new();
458525
let tz = LOCAL_TZ
@@ -473,6 +540,9 @@ impl<'py> IntoPyObject<'py> for &Local {
473540
type Output = Borrowed<'static, 'py, Self::Target>;
474541
type Error = PyErr;
475542

543+
#[cfg(feature = "experimental-inspect")]
544+
const OUTPUT_TYPE: TypeHint = Local::OUTPUT_TYPE;
545+
476546
#[inline]
477547
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
478548
(*self).into_pyobject(py)

src/conversions/chrono_tz.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@
3636
//! ```
3737
use crate::conversion::IntoPyObject;
3838
use crate::exceptions::PyValueError;
39+
#[cfg(feature = "experimental-inspect")]
40+
use crate::inspect::TypeHint;
3941
use crate::pybacked::PyBackedStr;
42+
#[cfg(feature = "experimental-inspect")]
43+
use crate::type_object::PyTypeInfo;
4044
use crate::types::{any::PyAnyMethods, PyTzInfo};
4145
use crate::{intern, Borrowed, Bound, FromPyObject, PyAny, PyErr, Python};
4246
use chrono_tz::Tz;
@@ -47,6 +51,9 @@ impl<'py> IntoPyObject<'py> for Tz {
4751
type Output = Bound<'py, Self::Target>;
4852
type Error = PyErr;
4953

54+
#[cfg(feature = "experimental-inspect")]
55+
const OUTPUT_TYPE: TypeHint = PyTzInfo::TYPE_HINT;
56+
5057
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
5158
PyTzInfo::timezone(py, self.name())
5259
}
@@ -57,6 +64,9 @@ impl<'py> IntoPyObject<'py> for &Tz {
5764
type Output = Bound<'py, Self::Target>;
5865
type Error = PyErr;
5966

67+
#[cfg(feature = "experimental-inspect")]
68+
const OUTPUT_TYPE: TypeHint = Tz::OUTPUT_TYPE;
69+
6070
#[inline]
6171
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
6272
(*self).into_pyobject(py)

src/conversions/std/array.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::conversion::{FromPyObjectOwned, FromPyObjectSequence, IntoPyObject};
2+
#[cfg(feature = "experimental-inspect")]
3+
use crate::inspect::TypeHint;
24
use crate::types::any::PyAnyMethods;
35
use crate::types::PySequence;
46
use crate::{err::CastError, ffi, FromPyObject, PyAny, PyResult, PyTypeInfo, Python};
@@ -30,6 +32,9 @@ where
3032
type Output = Bound<'py, Self::Target>;
3133
type Error = PyErr;
3234

35+
#[cfg(feature = "experimental-inspect")]
36+
const OUTPUT_TYPE: TypeHint = <&[T]>::OUTPUT_TYPE;
37+
3338
#[inline]
3439
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
3540
self.as_slice().into_pyobject(py)

0 commit comments

Comments
 (0)