Skip to content

Commit

Permalink
migrate IntoPyDict
Browse files Browse the repository at this point in the history
  • Loading branch information
Icxolu committed Aug 25, 2024
1 parent 7ead7ff commit 3563ef4
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 53 deletions.
18 changes: 12 additions & 6 deletions src/conversions/hashbrown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
dict::PyDictMethods,
frozenset::PyFrozenSetMethods,
set::{new_from_iter, try_new_from_iter, PySetMethods},
IntoPyDict, PyDict, PyFrozenSet, PySet,
PyDict, PyFrozenSet, PySet,
},
Bound, BoundObject, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject,
};
Expand All @@ -36,7 +36,11 @@ where
H: hash::BuildHasher,
{
fn to_object(&self, py: Python<'_>) -> PyObject {
IntoPyDict::into_py_dict(self, py).into()
let dict = PyDict::new(py);
for (k, v) in self {
dict.set_item(k.to_object(py), v.to_object(py)).unwrap();
}
dict.into_any().unbind()
}
}

Expand All @@ -47,10 +51,11 @@ where
H: hash::BuildHasher,
{
fn into_py(self, py: Python<'_>) -> PyObject {
let iter = self
.into_iter()
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
IntoPyDict::into_py_dict(iter, py).into()
let dict = PyDict::new(py);
for (k, v) in self {
dict.set_item(k.into_py(py), v.into_py(py)).unwrap();
}
dict.into_any().unbind()
}
}

Expand Down Expand Up @@ -197,6 +202,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::types::IntoPyDict;

#[test]
fn test_hashbrown_hashmap_to_python() {
Expand Down
15 changes: 10 additions & 5 deletions src/conversions/indexmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ where
H: hash::BuildHasher,
{
fn to_object(&self, py: Python<'_>) -> PyObject {
IntoPyDict::into_py_dict(self, py).into()
let dict = PyDict::new(py);
for (k, v) in self {
dict.set_item(k.to_object(py), v.to_object(py)).unwrap();
}
dict.into_any().unbind()
}
}

Expand All @@ -110,10 +114,11 @@ where
H: hash::BuildHasher,
{
fn into_py(self, py: Python<'_>) -> PyObject {
let iter = self
.into_iter()
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
IntoPyDict::into_py_dict(iter, py).into()
let dict = PyDict::new(py);
for (k, v) in self {
dict.set_item(k.into_py(py), v.into_py(py)).unwrap();
}
dict.into_any().unbind()
}
}

Expand Down
32 changes: 21 additions & 11 deletions src/conversions/std/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::inspect::types::TypeInfo;
use crate::{
conversion::IntoPyObject,
instance::Bound,
types::{any::PyAnyMethods, dict::PyDictMethods, IntoPyDict, PyDict},
types::{any::PyAnyMethods, dict::PyDictMethods, PyDict},
FromPyObject, IntoPy, PyAny, PyErr, PyObject, Python, ToPyObject,
};

Expand All @@ -16,7 +16,11 @@ where
H: hash::BuildHasher,
{
fn to_object(&self, py: Python<'_>) -> PyObject {
IntoPyDict::into_py_dict(self, py).into()
let dict = PyDict::new(py);
for (k, v) in self {
dict.set_item(k.to_object(py), v.to_object(py)).unwrap();
}
dict.into_any().unbind()
}
}

Expand All @@ -26,7 +30,11 @@ where
V: ToPyObject,
{
fn to_object(&self, py: Python<'_>) -> PyObject {
IntoPyDict::into_py_dict(self, py).into()
let dict = PyDict::new(py);
for (k, v) in self {
dict.set_item(k.to_object(py), v.to_object(py)).unwrap();
}
dict.into_any().unbind()
}
}

Expand All @@ -37,10 +45,11 @@ where
H: hash::BuildHasher,
{
fn into_py(self, py: Python<'_>) -> PyObject {
let iter = self
.into_iter()
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
IntoPyDict::into_py_dict(iter, py).into()
let dict = PyDict::new(py);
for (k, v) in self {
dict.set_item(k.into_py(py), v.into_py(py)).unwrap();
}
dict.into_any().unbind()
}

#[cfg(feature = "experimental-inspect")]
Expand Down Expand Up @@ -93,10 +102,11 @@ where
V: IntoPy<PyObject>,
{
fn into_py(self, py: Python<'_>) -> PyObject {
let iter = self
.into_iter()
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
IntoPyDict::into_py_dict(iter, py).into()
let dict = PyDict::new(py);
for (k, v) in self {
dict.set_item(k.into_py(py), v.into_py(py)).unwrap();
}
dict.into_any().unbind()
}

#[cfg(feature = "experimental-inspect")]
Expand Down
59 changes: 28 additions & 31 deletions src/types/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::instance::{Borrowed, Bound};
use crate::py_result_ext::PyResultExt;
use crate::types::any::PyAnyMethods;
use crate::types::{PyAny, PyList};
use crate::{ffi, BoundObject, Python, ToPyObject};
use crate::{ffi, BoundObject, Python};

/// Represents a Python `dict`.
///
Expand Down Expand Up @@ -557,76 +557,73 @@ pub(crate) use borrowed_iter::BorrowedDictIter;

/// Conversion trait that allows a sequence of tuples to be converted into `PyDict`
/// Primary use case for this trait is `call` and `call_method` methods as keywords argument.
pub trait IntoPyDict: Sized {
pub trait IntoPyDict<'py>: Sized {
/// Converts self into a `PyDict` object pointer. Whether pointer owned or borrowed
/// depends on implementation.
fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict>;
fn into_py_dict(self, py: Python<'py>) -> Bound<'_, PyDict>;

/// Deprecated name for [`IntoPyDict::into_py_dict`].
#[deprecated(since = "0.23.0", note = "renamed to `IntoPyDict::into_py_dict`")]
#[inline]
fn into_py_dict_bound(self, py: Python<'_>) -> Bound<'_, PyDict> {
fn into_py_dict_bound(self, py: Python<'py>) -> Bound<'_, PyDict> {
self.into_py_dict(py)
}
}

impl<T, I> IntoPyDict for I
impl<'py, T, I> IntoPyDict<'py> for I
where
T: PyDictItem,
T: PyDictItem<'py>,
I: IntoIterator<Item = T>,
{
fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict> {
fn into_py_dict(self, py: Python<'py>) -> Bound<'_, PyDict> {
let dict = PyDict::new(py);
for item in self {
dict.set_item(item.key().to_object(py), item.value().to_object(py))
let (key, value) = item.unpack();
dict.set_item(key, value)
.expect("Failed to set_item on dict");
}
dict
}
}

/// Represents a tuple which can be used as a PyDict item.
pub trait PyDictItem {
type K: ToPyObject;
type V: ToPyObject;
fn key(&self) -> &Self::K;
fn value(&self) -> &Self::V;
pub trait PyDictItem<'py> {
type K: IntoPyObject<'py>;
type V: IntoPyObject<'py>;
fn unpack(self) -> (Self::K, Self::V);
}

impl<K, V> PyDictItem for (K, V)
impl<'py, K, V> PyDictItem<'py> for (K, V)
where
K: ToPyObject,
V: ToPyObject,
K: IntoPyObject<'py>,
V: IntoPyObject<'py>,
{
type K = K;
type V = V;
fn key(&self) -> &Self::K {
&self.0
}
fn value(&self) -> &Self::V {
&self.1

fn unpack(self) -> (Self::K, Self::V) {
(self.0, self.1)
}
}

impl<K, V> PyDictItem for &(K, V)
impl<'a, 'py, K, V> PyDictItem<'py> for &'a (K, V)
where
K: ToPyObject,
V: ToPyObject,
&'a K: IntoPyObject<'py>,
&'a V: IntoPyObject<'py>,
{
type K = K;
type V = V;
fn key(&self) -> &Self::K {
&self.0
}
fn value(&self) -> &Self::V {
&self.1
type K = &'a K;
type V = &'a V;

fn unpack(self) -> (Self::K, Self::V) {
(&self.0, &self.1)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::types::PyTuple;
use crate::ToPyObject;
use std::collections::{BTreeMap, HashMap};

#[test]
Expand Down

0 comments on commit 3563ef4

Please sign in to comment.