Add into_mapping and into_sequence methods to Bound types (#3982)
* Add Bound<'py, PyDict>.into_mapping method * Add Bound<'py, PyTuple>.into_sequence method * Add Bound<'py, PyList>.into_sequence method * Add newsfragment * Add tests for into_mapping and into_sequence
This commit is contained in:
parent
9808f7111c
commit
009cd32a44
|
@ -0,0 +1 @@
|
||||||
|
Added `Bound<'py, PyDict>::into_mapping`, `Bound<'py, PyList>::into_sequence` and `Bound<'py, PyTuple>::into_sequence`.
|
|
@ -365,6 +365,9 @@ pub trait PyDictMethods<'py>: crate::sealed::Sealed {
|
||||||
/// Returns `self` cast as a `PyMapping`.
|
/// Returns `self` cast as a `PyMapping`.
|
||||||
fn as_mapping(&self) -> &Bound<'py, PyMapping>;
|
fn as_mapping(&self) -> &Bound<'py, PyMapping>;
|
||||||
|
|
||||||
|
/// Returns `self` cast as a `PyMapping`.
|
||||||
|
fn into_mapping(self) -> Bound<'py, PyMapping>;
|
||||||
|
|
||||||
/// Update this dictionary with the key/value pairs from another.
|
/// Update this dictionary with the key/value pairs from another.
|
||||||
///
|
///
|
||||||
/// This is equivalent to the Python expression `self.update(other)`. If `other` is a `PyDict`, you may want
|
/// This is equivalent to the Python expression `self.update(other)`. If `other` is a `PyDict`, you may want
|
||||||
|
@ -511,6 +514,10 @@ impl<'py> PyDictMethods<'py> for Bound<'py, PyDict> {
|
||||||
unsafe { self.downcast_unchecked() }
|
unsafe { self.downcast_unchecked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_mapping(self) -> Bound<'py, PyMapping> {
|
||||||
|
unsafe { self.into_any().downcast_into_unchecked() }
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, other: &Bound<'_, PyMapping>) -> PyResult<()> {
|
fn update(&self, other: &Bound<'_, PyMapping>) -> PyResult<()> {
|
||||||
err::error_on_minusone(self.py(), unsafe {
|
err::error_on_minusone(self.py(), unsafe {
|
||||||
ffi::PyDict_Update(self.as_ptr(), other.as_ptr())
|
ffi::PyDict_Update(self.as_ptr(), other.as_ptr())
|
||||||
|
@ -1367,6 +1374,20 @@ mod tests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dict_into_mapping() {
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
let mut map = HashMap::<i32, i32>::new();
|
||||||
|
map.insert(1, 1);
|
||||||
|
|
||||||
|
let py_map = map.into_py_dict_bound(py);
|
||||||
|
|
||||||
|
let py_mapping = py_map.into_mapping();
|
||||||
|
assert_eq!(py_mapping.len().unwrap(), 1);
|
||||||
|
assert_eq!(py_mapping.get_item(1).unwrap().extract::<i32>().unwrap(), 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(PyPy))]
|
#[cfg(not(PyPy))]
|
||||||
fn abc_dict(py: Python<'_>) -> Bound<'_, PyDict> {
|
fn abc_dict(py: Python<'_>) -> Bound<'_, PyDict> {
|
||||||
let mut map = HashMap::<&'static str, i32>::new();
|
let mut map = HashMap::<&'static str, i32>::new();
|
||||||
|
|
|
@ -295,6 +295,9 @@ pub trait PyListMethods<'py>: crate::sealed::Sealed {
|
||||||
/// Returns `self` cast as a `PySequence`.
|
/// Returns `self` cast as a `PySequence`.
|
||||||
fn as_sequence(&self) -> &Bound<'py, PySequence>;
|
fn as_sequence(&self) -> &Bound<'py, PySequence>;
|
||||||
|
|
||||||
|
/// Returns `self` cast as a `PySequence`.
|
||||||
|
fn into_sequence(self) -> Bound<'py, PySequence>;
|
||||||
|
|
||||||
/// Gets the list item at the specified index.
|
/// Gets the list item at the specified index.
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -408,6 +411,11 @@ impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
|
||||||
unsafe { self.downcast_unchecked() }
|
unsafe { self.downcast_unchecked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `self` cast as a `PySequence`.
|
||||||
|
fn into_sequence(self) -> Bound<'py, PySequence> {
|
||||||
|
unsafe { self.into_any().downcast_into_unchecked() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the list item at the specified index.
|
/// Gets the list item at the specified index.
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -715,6 +723,9 @@ impl<'py> IntoIterator for &Bound<'py, PyList> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))]
|
#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::types::any::PyAnyMethods;
|
||||||
|
use crate::types::list::PyListMethods;
|
||||||
|
use crate::types::sequence::PySequenceMethods;
|
||||||
use crate::types::{PyList, PyTuple};
|
use crate::types::{PyList, PyTuple};
|
||||||
use crate::Python;
|
use crate::Python;
|
||||||
use crate::{IntoPy, PyObject, ToPyObject};
|
use crate::{IntoPy, PyObject, ToPyObject};
|
||||||
|
@ -934,6 +945,35 @@ mod tests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_as_sequence() {
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
let list = PyList::new_bound(py, [1, 2, 3, 4]);
|
||||||
|
|
||||||
|
assert_eq!(list.as_sequence().len().unwrap(), 4);
|
||||||
|
assert_eq!(
|
||||||
|
list.as_sequence()
|
||||||
|
.get_item(1)
|
||||||
|
.unwrap()
|
||||||
|
.extract::<i32>()
|
||||||
|
.unwrap(),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_into_sequence() {
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
let list = PyList::new_bound(py, [1, 2, 3, 4]);
|
||||||
|
|
||||||
|
let sequence = list.into_sequence();
|
||||||
|
|
||||||
|
assert_eq!(sequence.len().unwrap(), 4);
|
||||||
|
assert_eq!(sequence.get_item(1).unwrap().extract::<i32>().unwrap(), 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract() {
|
fn test_extract() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
|
|
|
@ -258,6 +258,9 @@ pub trait PyTupleMethods<'py>: crate::sealed::Sealed {
|
||||||
/// Returns `self` cast as a `PySequence`.
|
/// Returns `self` cast as a `PySequence`.
|
||||||
fn as_sequence(&self) -> &Bound<'py, PySequence>;
|
fn as_sequence(&self) -> &Bound<'py, PySequence>;
|
||||||
|
|
||||||
|
/// Returns `self` cast as a `PySequence`.
|
||||||
|
fn into_sequence(self) -> Bound<'py, PySequence>;
|
||||||
|
|
||||||
/// Takes the slice `self[low:high]` and returns it as a new tuple.
|
/// Takes the slice `self[low:high]` and returns it as a new tuple.
|
||||||
///
|
///
|
||||||
/// Indices must be nonnegative, and out-of-range indices are clipped to
|
/// Indices must be nonnegative, and out-of-range indices are clipped to
|
||||||
|
@ -353,6 +356,10 @@ impl<'py> PyTupleMethods<'py> for Bound<'py, PyTuple> {
|
||||||
unsafe { self.downcast_unchecked() }
|
unsafe { self.downcast_unchecked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_sequence(self) -> Bound<'py, PySequence> {
|
||||||
|
unsafe { self.into_any().downcast_into_unchecked() }
|
||||||
|
}
|
||||||
|
|
||||||
fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyTuple> {
|
fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyTuple> {
|
||||||
unsafe {
|
unsafe {
|
||||||
ffi::PyTuple_GetSlice(self.as_ptr(), get_ssize_index(low), get_ssize_index(high))
|
ffi::PyTuple_GetSlice(self.as_ptr(), get_ssize_index(low), get_ssize_index(high))
|
||||||
|
@ -1415,7 +1422,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tuple_as_sequence() {
|
fn test_tuple_as_sequence() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let tuple = PyTuple::new(py, vec![1, 2, 3]);
|
let tuple = PyTuple::new_bound(py, vec![1, 2, 3]);
|
||||||
let sequence = tuple.as_sequence();
|
let sequence = tuple.as_sequence();
|
||||||
assert!(tuple.get_item(0).unwrap().eq(1).unwrap());
|
assert!(tuple.get_item(0).unwrap().eq(1).unwrap());
|
||||||
assert!(sequence.get_item(0).unwrap().eq(1).unwrap());
|
assert!(sequence.get_item(0).unwrap().eq(1).unwrap());
|
||||||
|
@ -1425,6 +1432,16 @@ mod tests {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_into_sequence() {
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
let tuple = PyTuple::new_bound(py, vec![1, 2, 3]);
|
||||||
|
let sequence = tuple.into_sequence();
|
||||||
|
assert!(sequence.get_item(0).unwrap().eq(1).unwrap());
|
||||||
|
assert_eq!(sequence.len().unwrap(), 3);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bound_tuple_get_item() {
|
fn test_bound_tuple_get_item() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
|
|
Loading…
Reference in New Issue