diff --git a/src/inspect/types.rs b/src/inspect/types.rs index 6dfe88477f8..eb7bdd40cb6 100644 --- a/src/inspect/types.rs +++ b/src/inspect/types.rs @@ -399,6 +399,7 @@ mod test { mod conversion { use crate::inspect::types::test::assert_display; use crate::{FromPyObject, IntoPy}; + use std::collections::{HashMap, HashSet}; #[test] fn unsigned_int() { @@ -459,4 +460,18 @@ mod conversion { assert_display(&<&[u8]>::type_output(), "bytes"); assert_display(&<&[u8]>::type_input(), "bytes"); } + + #[test] + fn collections() { + assert_display(&>::type_output(), "List[int]"); + assert_display(&>::type_input(), "Sequence[int]"); + + assert_display(&>::type_output(), "Set[int]"); + assert_display(&>::type_input(), "Set[int]"); + + assert_display(&>::type_output(), "Dict[int, float]"); + assert_display(&>::type_input(), "Mapping[int, float]"); + + assert_display(&<(usize, f32)>::type_input(), "Tuple[int, float]"); + } } diff --git a/src/types/dict.rs b/src/types/dict.rs index bd75d89722b..3bfd3b84813 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -3,6 +3,7 @@ use super::PyMapping; use crate::err::{self, PyErr, PyResult}; use crate::ffi::Py_ssize_t; +use crate::inspect::types::TypeInfo; use crate::types::{PyAny, PyList}; #[cfg(not(PyPy))] use crate::IntoPyPointer; @@ -361,6 +362,10 @@ where .map(|(k, v)| (k.into_py(py), v.into_py(py))); IntoPyDict::into_py_dict(iter, py).into() } + + fn type_output() -> TypeInfo { + TypeInfo::dict_of(K::type_output(), V::type_output()) + } } impl IntoPy for collections::BTreeMap @@ -374,6 +379,10 @@ where .map(|(k, v)| (k.into_py(py), v.into_py(py))); IntoPyDict::into_py_dict(iter, py).into() } + + fn type_output() -> TypeInfo { + TypeInfo::dict_of(K::type_output(), V::type_output()) + } } /// Conversion trait that allows a sequence of tuples to be converted into `PyDict` @@ -451,6 +460,10 @@ where } Ok(ret) } + + fn type_input() -> TypeInfo { + TypeInfo::mapping_of(K::type_input(), V::type_input()) + } } impl<'source, K, V> FromPyObject<'source> for BTreeMap @@ -466,6 +479,10 @@ where } Ok(ret) } + + fn type_input() -> TypeInfo { + TypeInfo::mapping_of(K::type_input(), V::type_input()) + } } #[cfg(test)] diff --git a/src/types/list.rs b/src/types/list.rs index 2538833dec7..40e717ef9a7 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -6,6 +6,7 @@ use std::convert::TryInto; use crate::err::{self, PyResult}; use crate::ffi::{self, Py_ssize_t}; +use crate::inspect::types::TypeInfo; use crate::internal_tricks::get_ssize_index; use crate::types::PySequence; use crate::{ @@ -368,6 +369,10 @@ where let list = new_from_iter(py, &mut iter); list.into() } + + fn type_output() -> TypeInfo { + TypeInfo::list_of(T::type_output()) + } } #[cfg(test)] diff --git a/src/types/sequence.rs b/src/types/sequence.rs index dcc4a2e729c..b6b9e4429e8 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -1,6 +1,7 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions::PyValueError; +use crate::inspect::types::TypeInfo; use crate::internal_tricks::get_ssize_index; use crate::types::{PyAny, PyList, PyString, PyTuple}; use crate::{ffi, PyNativeType, ToPyObject}; @@ -275,6 +276,10 @@ where } extract_sequence(obj) } + + fn type_input() -> TypeInfo { + TypeInfo::sequence_of(T::type_input()) + } } fn extract_sequence<'s, T>(obj: &'s PyAny) -> PyResult> diff --git a/src/types/set.rs b/src/types/set.rs index cf97eb484f0..6f425559578 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -2,6 +2,7 @@ // use crate::err::{self, PyErr, PyResult}; +use crate::inspect::types::TypeInfo; #[cfg(Py_LIMITED_API)] use crate::types::PyIterator; use crate::{ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, Python, ToPyObject}; @@ -271,6 +272,10 @@ where } set.into() } + + fn type_output() -> TypeInfo { + TypeInfo::set_of(K::type_output()) + } } impl<'source, K, S> FromPyObject<'source> for HashSet @@ -282,6 +287,10 @@ where let set: &PySet = ob.downcast()?; set.iter().map(K::extract).collect() } + + fn type_input() -> TypeInfo { + TypeInfo::set_of(K::type_input()) + } } impl IntoPy for BTreeSet @@ -297,6 +306,10 @@ where } set.into() } + + fn type_output() -> TypeInfo { + TypeInfo::set_of(K::type_output()) + } } impl<'source, K> FromPyObject<'source> for BTreeSet @@ -307,6 +320,10 @@ where let set: &PySet = ob.downcast()?; set.iter().map(K::extract).collect() } + + fn type_input() -> TypeInfo { + TypeInfo::set_of(K::type_input()) + } } #[cfg(test)] diff --git a/src/types/tuple.rs b/src/types/tuple.rs index b198da72bdd..84165e1fce3 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -3,6 +3,7 @@ use std::convert::TryInto; use crate::ffi::{self, Py_ssize_t}; +use crate::inspect::types::TypeInfo; use crate::internal_tricks::get_ssize_index; use crate::types::PySequence; use crate::{ @@ -293,6 +294,10 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ ret } } + + fn type_output() -> TypeInfo { + TypeInfo::Tuple(Some(vec![$( $T::type_output() ),+])) + } } impl <$($T: IntoPy),+> IntoPy> for ($($T,)+) { @@ -304,6 +309,10 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ ret } } + + fn type_output() -> TypeInfo { + TypeInfo::Tuple(Some(vec![$( $T::type_output() ),+])) + } } impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) { @@ -320,6 +329,10 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ Err(wrong_tuple_length(t, $length)) } } + + fn type_input() -> TypeInfo { + TypeInfo::Tuple(Some(vec![$( $T::type_input() ),+])) + } } });