Merge pull request #3681 from davidhewitt/tuple2-try2
implement `PyTupleMethods`
This commit is contained in:
commit
0ca97b5e53
|
@ -181,7 +181,7 @@ struct RustyTuple(String, String);
|
|||
# use pyo3::types::PyTuple;
|
||||
# fn main() -> PyResult<()> {
|
||||
# Python::with_gil(|py| -> PyResult<()> {
|
||||
# let tuple = PyTuple::new(py, vec!["test", "test2"]);
|
||||
# let tuple = PyTuple::new_bound(py, vec!["test", "test2"]);
|
||||
#
|
||||
# let rustytuple: RustyTuple = tuple.extract()?;
|
||||
# assert_eq!(rustytuple.0, "test");
|
||||
|
@ -204,7 +204,7 @@ struct RustyTuple((String,));
|
|||
# use pyo3::types::PyTuple;
|
||||
# fn main() -> PyResult<()> {
|
||||
# Python::with_gil(|py| -> PyResult<()> {
|
||||
# let tuple = PyTuple::new(py, vec!["test"]);
|
||||
# let tuple = PyTuple::new_bound(py, vec!["test"]);
|
||||
#
|
||||
# let rustytuple: RustyTuple = tuple.extract()?;
|
||||
# assert_eq!((rustytuple.0).0, "test");
|
||||
|
@ -482,7 +482,7 @@ If the input is neither a string nor an integer, the error message will be:
|
|||
- retrieve the field from a mapping, possibly with the custom key specified as an argument.
|
||||
- can be any literal that implements `ToBorrowedObject`
|
||||
- `pyo3(from_py_with = "...")`
|
||||
- apply a custom function to convert the field from Python the desired Rust type.
|
||||
- apply a custom function to convert the field from Python the desired Rust type.
|
||||
- the argument must be the name of the function as a string.
|
||||
- the function signature must be `fn(&PyAny) -> PyResult<T>` where `T` is the Rust type of the argument.
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ fn main() -> PyResult<()> {
|
|||
fun.call0(py)?;
|
||||
|
||||
// call object with PyTuple
|
||||
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
|
||||
let args = PyTuple::new_bound(py, &[arg1, arg2, arg3]);
|
||||
fun.call1(py, args)?;
|
||||
|
||||
// pass arguments as rust tuple
|
||||
|
|
|
@ -12,8 +12,8 @@ fn make_date(py: Python<'_>, year: i32, month: u8, day: u8) -> PyResult<&PyDate>
|
|||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_date_tuple<'p>(py: Python<'p>, d: &PyDate) -> &'p PyTuple {
|
||||
PyTuple::new(py, [d.get_year(), d.get_month() as i32, d.get_day() as i32])
|
||||
fn get_date_tuple<'p>(py: Python<'p>, d: &PyDate) -> Bound<'p, PyTuple> {
|
||||
PyTuple::new_bound(py, [d.get_year(), d.get_month() as i32, d.get_day() as i32])
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
@ -48,8 +48,8 @@ fn time_with_fold<'p>(
|
|||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple {
|
||||
PyTuple::new(
|
||||
fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> Bound<'p, PyTuple> {
|
||||
PyTuple::new_bound(
|
||||
py,
|
||||
[
|
||||
dt.get_hour() as u32,
|
||||
|
@ -61,8 +61,8 @@ fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple {
|
|||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_time_tuple_fold<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple {
|
||||
PyTuple::new(
|
||||
fn get_time_tuple_fold<'p>(py: Python<'p>, dt: &PyTime) -> Bound<'p, PyTuple> {
|
||||
PyTuple::new_bound(
|
||||
py,
|
||||
[
|
||||
dt.get_hour() as u32,
|
||||
|
@ -80,8 +80,8 @@ fn make_delta(py: Python<'_>, days: i32, seconds: i32, microseconds: i32) -> PyR
|
|||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_delta_tuple<'p>(py: Python<'p>, delta: &PyDelta) -> &'p PyTuple {
|
||||
PyTuple::new(
|
||||
fn get_delta_tuple<'p>(py: Python<'p>, delta: &PyDelta) -> Bound<'p, PyTuple> {
|
||||
PyTuple::new_bound(
|
||||
py,
|
||||
[
|
||||
delta.get_days(),
|
||||
|
@ -118,8 +118,8 @@ fn make_datetime<'p>(
|
|||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple {
|
||||
PyTuple::new(
|
||||
fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> Bound<'p, PyTuple> {
|
||||
PyTuple::new_bound(
|
||||
py,
|
||||
[
|
||||
dt.get_year(),
|
||||
|
@ -134,8 +134,8 @@ fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple {
|
|||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_datetime_tuple_fold<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple {
|
||||
PyTuple::new(
|
||||
fn get_datetime_tuple_fold<'p>(py: Python<'p>, dt: &PyDateTime) -> Bound<'p, PyTuple> {
|
||||
PyTuple::new_bound(
|
||||
py,
|
||||
[
|
||||
dt.get_year(),
|
||||
|
|
|
@ -465,7 +465,7 @@ mod implementations {
|
|||
/// Converts `()` to an empty Python tuple.
|
||||
impl IntoPy<Py<PyTuple>> for () {
|
||||
fn into_py(self, py: Python<'_>) -> Py<PyTuple> {
|
||||
PyTuple::empty(py).into()
|
||||
PyTuple::empty_bound(py).unbind()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -615,7 +615,7 @@ impl<'py> VarargsHandler<'py> for TupleVarargs {
|
|||
varargs: &[Option<&PyAny>],
|
||||
_function_description: &FunctionDescription,
|
||||
) -> PyResult<Self::Varargs> {
|
||||
Ok(PyTuple::new(py, varargs))
|
||||
Ok(PyTuple::new_bound(py, varargs).into_gil_ref())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -697,7 +697,7 @@ fn push_parameter_list(msg: &mut String, parameter_names: &[&str]) {
|
|||
mod tests {
|
||||
use crate::{
|
||||
types::{IntoPyDict, PyTuple},
|
||||
PyAny, Python, ToPyObject,
|
||||
PyAny, Python,
|
||||
};
|
||||
|
||||
use super::{push_parameter_list, FunctionDescription, NoVarargs, NoVarkeywords};
|
||||
|
@ -714,8 +714,8 @@ mod tests {
|
|||
};
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let args = PyTuple::new(py, Vec::<&PyAny>::new());
|
||||
let kwargs = [("foo".to_object(py).into_ref(py), 0u8)].into_py_dict(py);
|
||||
let args = PyTuple::new_bound(py, Vec::<&PyAny>::new());
|
||||
let kwargs = [("foo", 0u8)].into_py_dict(py);
|
||||
let err = unsafe {
|
||||
function_description
|
||||
.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
|
||||
|
@ -745,8 +745,8 @@ mod tests {
|
|||
};
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let args = PyTuple::new(py, Vec::<&PyAny>::new());
|
||||
let kwargs = [(1u8.to_object(py).into_ref(py), 1u8)].into_py_dict(py);
|
||||
let args = PyTuple::new_bound(py, Vec::<&PyAny>::new());
|
||||
let kwargs = [(1u8, 1u8)].into_py_dict(py);
|
||||
let err = unsafe {
|
||||
function_description
|
||||
.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
|
||||
|
@ -776,7 +776,7 @@ mod tests {
|
|||
};
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let args = PyTuple::new(py, Vec::<&PyAny>::new());
|
||||
let args = PyTuple::new_bound(py, Vec::<&PyAny>::new());
|
||||
let mut output = [None, None];
|
||||
let err = unsafe {
|
||||
function_description.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
|
||||
|
|
|
@ -72,7 +72,7 @@ impl ModuleDef {
|
|||
.import("sys")?
|
||||
.getattr("implementation")?
|
||||
.getattr("version")?;
|
||||
if version.lt(crate::types::PyTuple::new(py, PYPY_GOOD_VERSION))? {
|
||||
if version.lt(crate::types::PyTuple::new_bound(py, PYPY_GOOD_VERSION))? {
|
||||
let warn = py.import("warnings")?.getattr("warn")?;
|
||||
warn.call1((
|
||||
"PyPy 3.7 versions older than 7.3.8 are known to have binary \
|
||||
|
|
|
@ -325,10 +325,10 @@ impl<'py, T> Borrowed<'py, 'py, T>
|
|||
where
|
||||
T: HasPyGilRef,
|
||||
{
|
||||
// pub(crate) fn into_gil_ref(self) -> &'py T::AsRefTarget {
|
||||
// // Safety: self is a borrow over `'py`.
|
||||
// unsafe { self.py().from_borrowed_ptr(self.0.as_ptr()) }
|
||||
// }
|
||||
pub(crate) fn into_gil_ref(self) -> &'py T::AsRefTarget {
|
||||
// Safety: self is a borrow over `'py`.
|
||||
unsafe { self.py().from_borrowed_ptr(self.0.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::fmt::Debug for Borrowed<'_, '_, T> {
|
||||
|
|
|
@ -38,3 +38,4 @@ pub use crate::types::module::PyModuleMethods;
|
|||
pub use crate::types::sequence::PySequenceMethods;
|
||||
pub use crate::types::set::PySetMethods;
|
||||
pub use crate::types::string::PyStringMethods;
|
||||
pub use crate::types::tuple::PyTupleMethods;
|
||||
|
|
|
@ -212,7 +212,7 @@ impl PyDate {
|
|||
///
|
||||
/// This is equivalent to `datetime.date.fromtimestamp`
|
||||
pub fn from_timestamp(py: Python<'_>, timestamp: i64) -> PyResult<&PyDate> {
|
||||
let time_tuple = PyTuple::new(py, [timestamp]);
|
||||
let time_tuple = PyTuple::new_bound(py, [timestamp]);
|
||||
|
||||
// safety ensure that the API is loaded
|
||||
let _api = ensure_datetime_api(py);
|
||||
|
|
|
@ -1231,7 +1231,7 @@ mod tests {
|
|||
Python::with_gil(|py| {
|
||||
let list = PyList::new(py, vec![1, 2, 3]);
|
||||
let tuple = list.to_tuple();
|
||||
let tuple_expected = PyTuple::new(py, vec![1, 2, 3]);
|
||||
let tuple_expected = PyTuple::new_bound(py, vec![1, 2, 3]);
|
||||
assert!(tuple.eq(tuple_expected).unwrap());
|
||||
})
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ pub mod iter {
|
|||
pub use super::frozenset::{BoundFrozenSetIterator, PyFrozenSetIterator};
|
||||
pub use super::list::{BoundListIterator, PyListIterator};
|
||||
pub use super::set::{BoundSetIterator, PySetIterator};
|
||||
pub use super::tuple::PyTupleIterator;
|
||||
pub use super::tuple::{BorrowedTupleIterator, BoundTupleIterator, PyTupleIterator};
|
||||
}
|
||||
|
||||
// Implementations core to all native types
|
||||
|
@ -305,5 +305,5 @@ pub(crate) mod set;
|
|||
mod slice;
|
||||
pub(crate) mod string;
|
||||
mod traceback;
|
||||
mod tuple;
|
||||
pub(crate) mod tuple;
|
||||
mod typeobject;
|
||||
|
|
|
@ -1009,7 +1009,7 @@ mod tests {
|
|||
assert!(seq
|
||||
.to_tuple()
|
||||
.unwrap()
|
||||
.eq(PyTuple::new(py, ["foo", "bar"]))
|
||||
.eq(PyTuple::new_bound(py, ["foo", "bar"]))
|
||||
.unwrap());
|
||||
});
|
||||
}
|
||||
|
@ -1020,7 +1020,11 @@ mod tests {
|
|||
let v = vec!["foo", "bar"];
|
||||
let ob = v.to_object(py);
|
||||
let seq = ob.downcast::<PySequence>(py).unwrap();
|
||||
assert!(seq.to_tuple().unwrap().eq(PyTuple::new(py, &v)).unwrap());
|
||||
assert!(seq
|
||||
.to_tuple()
|
||||
.unwrap()
|
||||
.eq(PyTuple::new_bound(py, &v))
|
||||
.unwrap());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -2,21 +2,23 @@ use std::convert::TryInto;
|
|||
use std::iter::FusedIterator;
|
||||
|
||||
use crate::ffi::{self, Py_ssize_t};
|
||||
use crate::ffi_ptr_ext::FfiPtrExt;
|
||||
#[cfg(feature = "experimental-inspect")]
|
||||
use crate::inspect::types::TypeInfo;
|
||||
use crate::instance::Borrowed;
|
||||
use crate::internal_tricks::get_ssize_index;
|
||||
use crate::types::PyList;
|
||||
use crate::types::PySequence;
|
||||
use crate::types::{any::PyAnyMethods, sequence::PySequenceMethods, PyList, PySequence};
|
||||
use crate::{
|
||||
exceptions, FromPyObject, IntoPy, Py, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject,
|
||||
exceptions, Bound, FromPyObject, IntoPy, Py, PyAny, PyErr, PyNativeType, PyObject, PyResult,
|
||||
Python, ToPyObject,
|
||||
};
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
fn new_from_iter(
|
||||
py: Python<'_>,
|
||||
fn new_from_iter<'py>(
|
||||
py: Python<'py>,
|
||||
elements: &mut dyn ExactSizeIterator<Item = PyObject>,
|
||||
) -> Py<PyTuple> {
|
||||
) -> Bound<'py, PyTuple> {
|
||||
unsafe {
|
||||
// PyTuple_New checks for overflow but has a bad error message, so we check ourselves
|
||||
let len: Py_ssize_t = elements
|
||||
|
@ -28,7 +30,7 @@ fn new_from_iter(
|
|||
|
||||
// - Panics if the ptr is null
|
||||
// - Cleans up the tuple if `convert` or the asserts panic
|
||||
let tup: Py<PyTuple> = Py::from_owned_ptr(py, ptr);
|
||||
let tup = ptr.assume_owned(py).downcast_into_unchecked();
|
||||
|
||||
let mut counter: Py_ssize_t = 0;
|
||||
|
||||
|
@ -56,6 +58,26 @@ pub struct PyTuple(PyAny);
|
|||
pyobject_native_type_core!(PyTuple, pyobject_native_static_type_object!(ffi::PyTuple_Type), #checkfunction=ffi::PyTuple_Check);
|
||||
|
||||
impl PyTuple {
|
||||
/// Deprecated form of `PyTuple::new_bound`.
|
||||
#[track_caller]
|
||||
#[cfg_attr(
|
||||
not(feature = "gil-refs"),
|
||||
deprecated(
|
||||
since = "0.21.0",
|
||||
note = "`PyTuple::new` will be replaced by `PyTuple::new_bound` in a future PyO3 version"
|
||||
)
|
||||
)]
|
||||
pub fn new<T, U>(
|
||||
py: Python<'_>,
|
||||
elements: impl IntoIterator<Item = T, IntoIter = U>,
|
||||
) -> &PyTuple
|
||||
where
|
||||
T: ToPyObject,
|
||||
U: ExactSizeIterator<Item = T>,
|
||||
{
|
||||
Self::new_bound(py, elements).into_gil_ref()
|
||||
}
|
||||
|
||||
/// Constructs a new tuple with the given elements.
|
||||
///
|
||||
/// If you want to create a [`PyTuple`] with elements of different or unknown types, or from an
|
||||
|
@ -71,7 +93,7 @@ impl PyTuple {
|
|||
/// # fn main() {
|
||||
/// Python::with_gil(|py| {
|
||||
/// let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5];
|
||||
/// let tuple: &PyTuple = PyTuple::new(py, elements);
|
||||
/// let tuple = PyTuple::new_bound(py, elements);
|
||||
/// assert_eq!(format!("{:?}", tuple), "(0, 1, 2, 3, 4, 5)");
|
||||
/// });
|
||||
/// # }
|
||||
|
@ -83,39 +105,47 @@ impl PyTuple {
|
|||
/// All standard library structures implement this trait correctly, if they do, so calling this
|
||||
/// function using [`Vec`]`<T>` or `&[T]` will always succeed.
|
||||
#[track_caller]
|
||||
pub fn new<T, U>(
|
||||
pub fn new_bound<T, U>(
|
||||
py: Python<'_>,
|
||||
elements: impl IntoIterator<Item = T, IntoIter = U>,
|
||||
) -> &PyTuple
|
||||
) -> Bound<'_, PyTuple>
|
||||
where
|
||||
T: ToPyObject,
|
||||
U: ExactSizeIterator<Item = T>,
|
||||
{
|
||||
let mut elements = elements.into_iter().map(|e| e.to_object(py));
|
||||
let tup = new_from_iter(py, &mut elements);
|
||||
tup.into_ref(py)
|
||||
new_from_iter(py, &mut elements)
|
||||
}
|
||||
|
||||
/// Deprecated form of `PyTuple::empty_bound`.
|
||||
#[cfg_attr(
|
||||
not(feature = "gil-refs"),
|
||||
deprecated(
|
||||
since = "0.21.0",
|
||||
note = "`PyTuple::empty` will be replaced by `PyTuple::empty_bound` in a future PyO3 version"
|
||||
)
|
||||
)]
|
||||
pub fn empty(py: Python<'_>) -> &PyTuple {
|
||||
Self::empty_bound(py).into_gil_ref()
|
||||
}
|
||||
|
||||
/// Constructs an empty tuple (on the Python side, a singleton object).
|
||||
pub fn empty(py: Python<'_>) -> &PyTuple {
|
||||
unsafe { py.from_owned_ptr(ffi::PyTuple_New(0)) }
|
||||
pub fn empty_bound(py: Python<'_>) -> Bound<'_, PyTuple> {
|
||||
unsafe {
|
||||
ffi::PyTuple_New(0)
|
||||
.assume_owned(py)
|
||||
.downcast_into_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the length of the tuple.
|
||||
pub fn len(&self) -> usize {
|
||||
unsafe {
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
let size = ffi::PyTuple_GET_SIZE(self.as_ptr());
|
||||
#[cfg(any(Py_LIMITED_API, PyPy))]
|
||||
let size = ffi::PyTuple_Size(self.as_ptr());
|
||||
// non-negative Py_ssize_t should always fit into Rust uint
|
||||
size as usize
|
||||
}
|
||||
self.as_borrowed().len()
|
||||
}
|
||||
|
||||
/// Checks if the tuple is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
self.as_borrowed().is_empty()
|
||||
}
|
||||
|
||||
/// Returns `self` cast as a `PySequence`.
|
||||
|
@ -128,13 +158,7 @@ impl PyTuple {
|
|||
/// Indices must be nonnegative, and out-of-range indices are clipped to
|
||||
/// `self.len()`.
|
||||
pub fn get_slice(&self, low: usize, high: usize) -> &PyTuple {
|
||||
unsafe {
|
||||
self.py().from_owned_ptr(ffi::PyTuple_GetSlice(
|
||||
self.as_ptr(),
|
||||
get_ssize_index(low),
|
||||
get_ssize_index(high),
|
||||
))
|
||||
}
|
||||
self.as_borrowed().get_slice(low, high).into_gil_ref()
|
||||
}
|
||||
|
||||
/// Gets the tuple item at the specified index.
|
||||
|
@ -153,10 +177,9 @@ impl PyTuple {
|
|||
/// # }
|
||||
/// ```
|
||||
pub fn get_item(&self, index: usize) -> PyResult<&PyAny> {
|
||||
unsafe {
|
||||
let item = ffi::PyTuple_GetItem(self.as_ptr(), index as Py_ssize_t);
|
||||
self.py().from_borrowed_ptr_or_err(item)
|
||||
}
|
||||
self.as_borrowed()
|
||||
.get_borrowed_item(index)
|
||||
.map(Borrowed::into_gil_ref)
|
||||
}
|
||||
|
||||
/// Gets the tuple item at the specified index. Undefined behavior on bad index. Use with caution.
|
||||
|
@ -166,8 +189,9 @@ impl PyTuple {
|
|||
/// Caller must verify that the index is within the bounds of the tuple.
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
pub unsafe fn get_item_unchecked(&self, index: usize) -> &PyAny {
|
||||
let item = ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t);
|
||||
self.py().from_borrowed_ptr(item)
|
||||
self.as_borrowed()
|
||||
.get_borrowed_item_unchecked(index)
|
||||
.into_gil_ref()
|
||||
}
|
||||
|
||||
/// Returns `self` as a slice of objects.
|
||||
|
@ -190,7 +214,7 @@ impl PyTuple {
|
|||
where
|
||||
V: ToPyObject,
|
||||
{
|
||||
self.as_sequence().contains(value)
|
||||
self.as_borrowed().contains(value)
|
||||
}
|
||||
|
||||
/// Returns the first index `i` for which `self[i] == value`.
|
||||
|
@ -201,54 +225,285 @@ impl PyTuple {
|
|||
where
|
||||
V: ToPyObject,
|
||||
{
|
||||
self.as_sequence().index(value)
|
||||
self.as_borrowed().index(value)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the tuple items.
|
||||
pub fn iter(&self) -> PyTupleIterator<'_> {
|
||||
PyTupleIterator {
|
||||
tuple: self,
|
||||
index: 0,
|
||||
length: self.len(),
|
||||
}
|
||||
PyTupleIterator(BorrowedTupleIterator::new(self.as_borrowed()))
|
||||
}
|
||||
|
||||
/// Return a new list containing the contents of this tuple; equivalent to the Python expression `list(tuple)`.
|
||||
///
|
||||
/// This method is equivalent to `self.as_sequence().to_list()` and faster than `PyList::new(py, self)`.
|
||||
pub fn to_list(&self) -> &PyList {
|
||||
self.as_borrowed().to_list().into_gil_ref()
|
||||
}
|
||||
}
|
||||
|
||||
index_impls!(PyTuple, "tuple", PyTuple::len, PyTuple::get_slice);
|
||||
|
||||
/// Implementation of functionality for [`PyTuple`].
|
||||
///
|
||||
/// These methods are defined for the `Bound<'py, PyTuple>` smart pointer, so to use method call
|
||||
/// syntax these methods are separated into a trait, because stable Rust does not yet support
|
||||
/// `arbitrary_self_types`.
|
||||
#[doc(alias = "PyTuple")]
|
||||
pub trait PyTupleMethods<'py> {
|
||||
/// Gets the length of the tuple.
|
||||
fn len(&self) -> usize;
|
||||
|
||||
/// Checks if the tuple is empty.
|
||||
fn is_empty(&self) -> bool;
|
||||
|
||||
/// Returns `self` cast as a `PySequence`.
|
||||
fn as_sequence(&self) -> &Bound<'py, PySequence>;
|
||||
|
||||
/// 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
|
||||
/// `self.len()`.
|
||||
fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyTuple>;
|
||||
|
||||
/// Gets the tuple item at the specified index.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use pyo3::{prelude::*, types::PyTuple};
|
||||
///
|
||||
/// # fn main() -> PyResult<()> {
|
||||
/// Python::with_gil(|py| -> PyResult<()> {
|
||||
/// let ob = (1, 2, 3).to_object(py);
|
||||
/// let tuple: &PyTuple = ob.downcast(py).unwrap();
|
||||
/// let obj = tuple.get_item(0);
|
||||
/// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 1);
|
||||
/// Ok(())
|
||||
/// })
|
||||
/// # }
|
||||
/// ```
|
||||
fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>>;
|
||||
|
||||
/// Like [`get_item`][PyTupleMethods::get_item], but returns a borrowed object, which is a slight performance optimization
|
||||
/// by avoiding a reference count change.
|
||||
fn get_borrowed_item<'a>(&'a self, index: usize) -> PyResult<Borrowed<'a, 'py, PyAny>>;
|
||||
|
||||
/// Gets the tuple item at the specified index. Undefined behavior on bad index. Use with caution.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Caller must verify that the index is within the bounds of the tuple.
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny>;
|
||||
|
||||
/// Like [`get_item_unchecked`][PyTupleMethods::get_item_unchecked], but returns a borrowed object,
|
||||
/// which is a slight performance optimization by avoiding a reference count change.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Caller must verify that the index is within the bounds of the tuple.
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
unsafe fn get_borrowed_item_unchecked<'a>(&'a self, index: usize) -> Borrowed<'a, 'py, PyAny>;
|
||||
|
||||
/// Returns `self` as a slice of objects.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
fn as_slice(&self) -> &[Bound<'py, PyAny>];
|
||||
|
||||
/// Determines if self contains `value`.
|
||||
///
|
||||
/// This is equivalent to the Python expression `value in self`.
|
||||
fn contains<V>(&self, value: V) -> PyResult<bool>
|
||||
where
|
||||
V: ToPyObject;
|
||||
|
||||
/// Returns the first index `i` for which `self[i] == value`.
|
||||
///
|
||||
/// This is equivalent to the Python expression `self.index(value)`.
|
||||
fn index<V>(&self, value: V) -> PyResult<usize>
|
||||
where
|
||||
V: ToPyObject;
|
||||
|
||||
/// Returns an iterator over the tuple items.
|
||||
fn iter(&self) -> BoundTupleIterator<'py>;
|
||||
|
||||
/// Like [`iter`][PyTupleMethods::iter], but produces an iterator which returns borrowed objects,
|
||||
/// which is a slight performance optimization by avoiding a reference count change.
|
||||
fn iter_borrowed<'a>(&'a self) -> BorrowedTupleIterator<'a, 'py>;
|
||||
|
||||
/// Return a new list containing the contents of this tuple; equivalent to the Python expression `list(tuple)`.
|
||||
///
|
||||
/// This method is equivalent to `self.as_sequence().to_list()` and faster than `PyList::new(py, self)`.
|
||||
fn to_list(&self) -> Bound<'py, PyList>;
|
||||
}
|
||||
|
||||
impl<'py> PyTupleMethods<'py> for Bound<'py, PyTuple> {
|
||||
fn len(&self) -> usize {
|
||||
unsafe {
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
let size = ffi::PyTuple_GET_SIZE(self.as_ptr());
|
||||
#[cfg(any(Py_LIMITED_API, PyPy))]
|
||||
let size = ffi::PyTuple_Size(self.as_ptr());
|
||||
// non-negative Py_ssize_t should always fit into Rust uint
|
||||
size as usize
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
fn as_sequence(&self) -> &Bound<'py, PySequence> {
|
||||
unsafe { self.downcast_unchecked() }
|
||||
}
|
||||
|
||||
fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyTuple> {
|
||||
unsafe {
|
||||
ffi::PyTuple_GetSlice(self.as_ptr(), get_ssize_index(low), get_ssize_index(high))
|
||||
.assume_owned(self.py())
|
||||
.downcast_into_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>> {
|
||||
self.get_borrowed_item(index).map(Borrowed::to_owned)
|
||||
}
|
||||
|
||||
fn get_borrowed_item<'a>(&'a self, index: usize) -> PyResult<Borrowed<'a, 'py, PyAny>> {
|
||||
self.as_borrowed().get_borrowed_item(index)
|
||||
}
|
||||
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny> {
|
||||
self.get_borrowed_item_unchecked(index).to_owned()
|
||||
}
|
||||
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
unsafe fn get_borrowed_item_unchecked<'a>(&'a self, index: usize) -> Borrowed<'a, 'py, PyAny> {
|
||||
self.as_borrowed().get_borrowed_item_unchecked(index)
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
fn as_slice(&self) -> &[Bound<'py, PyAny>] {
|
||||
// This is safe because Bound<'py, PyAny> has the same memory layout as *mut ffi::PyObject,
|
||||
// and because tuples are immutable.
|
||||
unsafe {
|
||||
let ptr = self.as_ptr() as *mut ffi::PyTupleObject;
|
||||
let slice = std::slice::from_raw_parts((*ptr).ob_item.as_ptr(), self.len());
|
||||
&*(slice as *const [*mut ffi::PyObject] as *const [Bound<'py, PyAny>])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn contains<V>(&self, value: V) -> PyResult<bool>
|
||||
where
|
||||
V: ToPyObject,
|
||||
{
|
||||
self.as_sequence().contains(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index<V>(&self, value: V) -> PyResult<usize>
|
||||
where
|
||||
V: ToPyObject,
|
||||
{
|
||||
self.as_sequence().index(value)
|
||||
}
|
||||
|
||||
fn iter(&self) -> BoundTupleIterator<'py> {
|
||||
BoundTupleIterator::new(self.clone())
|
||||
}
|
||||
|
||||
fn iter_borrowed<'a>(&'a self) -> BorrowedTupleIterator<'a, 'py> {
|
||||
BorrowedTupleIterator::new(self.as_borrowed())
|
||||
}
|
||||
|
||||
fn to_list(&self) -> Bound<'py, PyList> {
|
||||
self.as_sequence()
|
||||
.to_list()
|
||||
.expect("failed to convert tuple to list")
|
||||
}
|
||||
}
|
||||
|
||||
index_impls!(PyTuple, "tuple", PyTuple::len, PyTuple::get_slice);
|
||||
impl<'a, 'py> Borrowed<'a, 'py, PyTuple> {
|
||||
fn get_borrowed_item(self, index: usize) -> PyResult<Borrowed<'a, 'py, PyAny>> {
|
||||
unsafe {
|
||||
ffi::PyTuple_GetItem(self.as_ptr(), index as Py_ssize_t)
|
||||
.assume_borrowed_or_err(self.py())
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `PyTuple::iter()`.
|
||||
pub struct PyTupleIterator<'a> {
|
||||
tuple: &'a PyTuple,
|
||||
index: usize,
|
||||
length: usize,
|
||||
}
|
||||
|
||||
impl<'a> PyTupleIterator<'a> {
|
||||
unsafe fn get_item(&self, index: usize) -> &'a PyAny {
|
||||
#[cfg(any(Py_LIMITED_API, PyPy))]
|
||||
let item = self.tuple.get_item(index).expect("tuple.get failed");
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
let item = self.tuple.get_item_unchecked(index);
|
||||
item
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
unsafe fn get_borrowed_item_unchecked(self, index: usize) -> Borrowed<'a, 'py, PyAny> {
|
||||
ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t).assume_borrowed(self.py())
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `PyTuple::iter()`.
|
||||
pub struct PyTupleIterator<'a>(BorrowedTupleIterator<'a, 'a>);
|
||||
|
||||
impl<'a> Iterator for PyTupleIterator<'a> {
|
||||
type Item = &'a PyAny;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next().map(Borrowed::into_gil_ref)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for PyTupleIterator<'a> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.0.next_back().map(Borrowed::into_gil_ref)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for PyTupleIterator<'a> {
|
||||
fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedIterator for PyTupleIterator<'_> {}
|
||||
|
||||
impl<'a> IntoIterator for &'a PyTuple {
|
||||
type Item = &'a PyAny;
|
||||
type IntoIter = PyTupleIterator<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
PyTupleIterator(BorrowedTupleIterator::new(self.as_borrowed()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `PyTuple::into_iter()`.
|
||||
pub struct BoundTupleIterator<'py> {
|
||||
tuple: Bound<'py, PyTuple>,
|
||||
index: usize,
|
||||
length: usize,
|
||||
}
|
||||
|
||||
impl<'py> BoundTupleIterator<'py> {
|
||||
fn new(tuple: Bound<'py, PyTuple>) -> Self {
|
||||
let length = tuple.len();
|
||||
BoundTupleIterator {
|
||||
tuple,
|
||||
index: 0,
|
||||
length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'py> Iterator for BoundTupleIterator<'py> {
|
||||
type Item = Bound<'py, PyAny>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index < self.length {
|
||||
let item = unsafe { self.get_item(self.index) };
|
||||
let item = unsafe {
|
||||
BorrowedTupleIterator::get_item(self.tuple.as_borrowed(), self.index).to_owned()
|
||||
};
|
||||
self.index += 1;
|
||||
Some(item)
|
||||
} else {
|
||||
|
@ -263,11 +518,14 @@ impl<'a> Iterator for PyTupleIterator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for PyTupleIterator<'a> {
|
||||
impl<'py> DoubleEndedIterator for BoundTupleIterator<'py> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
if self.index < self.length {
|
||||
let item = unsafe { self.get_item(self.length - 1) };
|
||||
let item = unsafe {
|
||||
BorrowedTupleIterator::get_item(self.tuple.as_borrowed(), self.length - 1)
|
||||
.to_owned()
|
||||
};
|
||||
self.length -= 1;
|
||||
Some(item)
|
||||
} else {
|
||||
|
@ -276,20 +534,97 @@ impl<'a> DoubleEndedIterator for PyTupleIterator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for PyTupleIterator<'a> {
|
||||
impl<'py> ExactSizeIterator for BoundTupleIterator<'py> {
|
||||
fn len(&self) -> usize {
|
||||
self.length.saturating_sub(self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedIterator for PyTupleIterator<'_> {}
|
||||
impl FusedIterator for BoundTupleIterator<'_> {}
|
||||
|
||||
impl<'a> IntoIterator for &'a PyTuple {
|
||||
type Item = &'a PyAny;
|
||||
type IntoIter = PyTupleIterator<'a>;
|
||||
impl<'py> IntoIterator for Bound<'py, PyTuple> {
|
||||
type Item = Bound<'py, PyAny>;
|
||||
type IntoIter = BoundTupleIterator<'py>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
BoundTupleIterator::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `PyTuple::iter_borrowed()`.
|
||||
pub struct BorrowedTupleIterator<'a, 'py> {
|
||||
tuple: Borrowed<'a, 'py, PyTuple>,
|
||||
index: usize,
|
||||
length: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'py> BorrowedTupleIterator<'a, 'py> {
|
||||
fn new(tuple: Borrowed<'a, 'py, PyTuple>) -> Self {
|
||||
let length = tuple.len();
|
||||
BorrowedTupleIterator {
|
||||
tuple,
|
||||
index: 0,
|
||||
length,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_item(
|
||||
tuple: Borrowed<'a, 'py, PyTuple>,
|
||||
index: usize,
|
||||
) -> Borrowed<'a, 'py, PyAny> {
|
||||
#[cfg(any(Py_LIMITED_API, PyPy))]
|
||||
let item = tuple.get_borrowed_item(index).expect("tuple.get failed");
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
let item = tuple.get_borrowed_item_unchecked(index);
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'py> Iterator for BorrowedTupleIterator<'a, 'py> {
|
||||
type Item = Borrowed<'a, 'py, PyAny>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index < self.length {
|
||||
let item = unsafe { Self::get_item(self.tuple, self.index) };
|
||||
self.index += 1;
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.len();
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'py> DoubleEndedIterator for BorrowedTupleIterator<'a, 'py> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
if self.index < self.length {
|
||||
let item = unsafe { Self::get_item(self.tuple, self.length - 1) };
|
||||
self.length -= 1;
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'py> ExactSizeIterator for BorrowedTupleIterator<'a, 'py> {
|
||||
fn len(&self) -> usize {
|
||||
self.length.saturating_sub(self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedIterator for BorrowedTupleIterator<'_, '_> {}
|
||||
|
||||
impl IntoPy<Py<PyTuple>> for Bound<'_, PyTuple> {
|
||||
fn into_py(self, _: Python<'_>) -> Py<PyTuple> {
|
||||
self.unbind()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,7 +669,7 @@ fn type_output() -> TypeInfo {
|
|||
impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) {
|
||||
fn extract(obj: &'s PyAny) -> PyResult<Self>
|
||||
{
|
||||
let t: &PyTuple = obj.downcast()?;
|
||||
let t = obj.downcast::<PyTuple>()?;
|
||||
if t.len() == $length {
|
||||
#[cfg(any(Py_LIMITED_API, PyPy))]
|
||||
return Ok(($(t.get_item($n)?.extract::<$T>()?,)+));
|
||||
|
@ -472,8 +807,9 @@ tuple_conversion!(
|
|||
);
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(deprecated)] // TODO: remove allow when GIL Pool is removed
|
||||
mod tests {
|
||||
use crate::types::{PyAny, PyList, PyTuple};
|
||||
use crate::types::{any::PyAnyMethods, tuple::PyTupleMethods, PyAny, PyList, PyTuple};
|
||||
use crate::{Python, ToPyObject};
|
||||
use std::collections::HashSet;
|
||||
|
||||
|
@ -498,11 +834,21 @@ mod tests {
|
|||
let ob = (1, 2, 3).to_object(py);
|
||||
let tuple: &PyTuple = ob.downcast(py).unwrap();
|
||||
assert_eq!(3, tuple.len());
|
||||
assert!(!tuple.is_empty());
|
||||
let ob: &PyAny = tuple.into();
|
||||
assert_eq!((1, 2, 3), ob.extract().unwrap());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
Python::with_gil(|py| {
|
||||
let tuple = PyTuple::empty(py);
|
||||
assert!(tuple.is_empty());
|
||||
assert_eq!(0, tuple.len());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice() {
|
||||
Python::with_gil(|py| {
|
||||
|
@ -562,6 +908,52 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bound_iter() {
|
||||
Python::with_gil(|py| {
|
||||
let tuple = PyTuple::new_bound(py, [1, 2, 3]);
|
||||
assert_eq!(3, tuple.len());
|
||||
let mut iter = tuple.iter();
|
||||
|
||||
assert_eq!(iter.size_hint(), (3, Some(3)));
|
||||
|
||||
assert_eq!(1_i32, iter.next().unwrap().extract::<'_, i32>().unwrap());
|
||||
assert_eq!(iter.size_hint(), (2, Some(2)));
|
||||
|
||||
assert_eq!(2_i32, iter.next().unwrap().extract::<'_, i32>().unwrap());
|
||||
assert_eq!(iter.size_hint(), (1, Some(1)));
|
||||
|
||||
assert_eq!(3_i32, iter.next().unwrap().extract::<'_, i32>().unwrap());
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
|
||||
assert!(iter.next().is_none());
|
||||
assert!(iter.next().is_none());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bound_iter_rev() {
|
||||
Python::with_gil(|py| {
|
||||
let tuple = PyTuple::new_bound(py, [1, 2, 3]);
|
||||
assert_eq!(3, tuple.len());
|
||||
let mut iter = tuple.iter().rev();
|
||||
|
||||
assert_eq!(iter.size_hint(), (3, Some(3)));
|
||||
|
||||
assert_eq!(3_i32, iter.next().unwrap().extract::<'_, i32>().unwrap());
|
||||
assert_eq!(iter.size_hint(), (2, Some(2)));
|
||||
|
||||
assert_eq!(2_i32, iter.next().unwrap().extract::<'_, i32>().unwrap());
|
||||
assert_eq!(iter.size_hint(), (1, Some(1)));
|
||||
|
||||
assert_eq!(1_i32, iter.next().unwrap().extract::<'_, i32>().unwrap());
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
|
||||
assert!(iter.next().is_none());
|
||||
assert!(iter.next().is_none());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter() {
|
||||
Python::with_gil(|py| {
|
||||
|
@ -984,4 +1376,50 @@ mod tests {
|
|||
assert!(list.eq(list_expected).unwrap());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tuple_as_sequence() {
|
||||
Python::with_gil(|py| {
|
||||
let tuple = PyTuple::new(py, vec![1, 2, 3]);
|
||||
let sequence = tuple.as_sequence();
|
||||
assert!(tuple.get_item(0).unwrap().eq(1).unwrap());
|
||||
assert!(sequence.get_item(0).unwrap().eq(1).unwrap());
|
||||
|
||||
assert_eq!(tuple.len(), 3);
|
||||
assert_eq!(sequence.len().unwrap(), 3);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bound_tuple_get_item() {
|
||||
Python::with_gil(|py| {
|
||||
let tuple = PyTuple::new_bound(py, vec![1, 2, 3, 4]);
|
||||
|
||||
assert_eq!(tuple.len(), 4);
|
||||
assert_eq!(tuple.get_item(0).unwrap().extract::<i32>().unwrap(), 1);
|
||||
assert_eq!(
|
||||
tuple
|
||||
.get_borrowed_item(1)
|
||||
.unwrap()
|
||||
.extract::<i32>()
|
||||
.unwrap(),
|
||||
2
|
||||
);
|
||||
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
|
||||
{
|
||||
assert_eq!(
|
||||
unsafe { tuple.get_item_unchecked(2) }
|
||||
.extract::<i32>()
|
||||
.unwrap(),
|
||||
3
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { tuple.get_borrowed_item_unchecked(3) }
|
||||
.extract::<i32>()
|
||||
.unwrap(),
|
||||
4
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,11 +162,11 @@ pub struct Tuple(String, usize);
|
|||
#[test]
|
||||
fn test_tuple_struct() {
|
||||
Python::with_gil(|py| {
|
||||
let tup = PyTuple::new(py, &[1.into_py(py), "test".into_py(py)]);
|
||||
let tup = Tuple::extract(tup.as_ref());
|
||||
let tup = PyTuple::new_bound(py, &[1.into_py(py), "test".into_py(py)]);
|
||||
let tup = Tuple::extract(tup.as_gil_ref());
|
||||
assert!(tup.is_err());
|
||||
let tup = PyTuple::new(py, &["test".into_py(py), 1.into_py(py)]);
|
||||
let tup = Tuple::extract(tup.as_ref()).expect("Failed to extract Tuple from PyTuple");
|
||||
let tup = PyTuple::new_bound(py, &["test".into_py(py), 1.into_py(py)]);
|
||||
let tup = Tuple::extract(tup.as_gil_ref()).expect("Failed to extract Tuple from PyTuple");
|
||||
assert_eq!(tup.0, "test");
|
||||
assert_eq!(tup.1, 1);
|
||||
});
|
||||
|
@ -324,8 +324,8 @@ pub struct PyBool {
|
|||
#[test]
|
||||
fn test_enum() {
|
||||
Python::with_gil(|py| {
|
||||
let tup = PyTuple::new(py, &[1.into_py(py), "test".into_py(py)]);
|
||||
let f = Foo::extract(tup.as_ref()).expect("Failed to extract Foo from tuple");
|
||||
let tup = PyTuple::new_bound(py, &[1.into_py(py), "test".into_py(py)]);
|
||||
let f = Foo::extract(tup.as_gil_ref()).expect("Failed to extract Foo from tuple");
|
||||
match f {
|
||||
Foo::TupleVar(test, test2) => {
|
||||
assert_eq!(test, 1);
|
||||
|
@ -401,8 +401,8 @@ TypeError: failed to extract enum Foo ('TupleVar | StructVar | TransparentTuple
|
|||
- variant StructWithGetItemArg (StructWithGetItemArg): KeyError: 'foo'"
|
||||
);
|
||||
|
||||
let tup = PyTuple::empty(py);
|
||||
let err = Foo::extract(tup.as_ref()).unwrap_err();
|
||||
let tup = PyTuple::empty_bound(py);
|
||||
let err = Foo::extract(tup.as_gil_ref()).unwrap_err();
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
"\
|
||||
|
|
|
@ -91,7 +91,7 @@ fn intopytuple_pyclass() {
|
|||
#[test]
|
||||
fn pytuple_primitive_iter() {
|
||||
Python::with_gil(|py| {
|
||||
let tup = PyTuple::new(py, [1u32, 2, 3].iter());
|
||||
let tup = PyTuple::new_bound(py, [1u32, 2, 3].iter());
|
||||
py_assert!(py, tup, "tup == (1, 2, 3)");
|
||||
});
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ fn pytuple_primitive_iter() {
|
|||
#[test]
|
||||
fn pytuple_pyclass_iter() {
|
||||
Python::with_gil(|py| {
|
||||
let tup = PyTuple::new(
|
||||
let tup = PyTuple::new_bound(
|
||||
py,
|
||||
[
|
||||
PyCell::new(py, SimplePyClass {}).unwrap(),
|
||||
|
@ -126,10 +126,10 @@ impl PickleSupport {
|
|||
pub fn __reduce__<'py>(
|
||||
slf: &'py PyCell<Self>,
|
||||
py: Python<'py>,
|
||||
) -> PyResult<(PyObject, &'py PyTuple, PyObject)> {
|
||||
) -> PyResult<(PyObject, Bound<'py, PyTuple>, PyObject)> {
|
||||
let cls = slf.to_object(py).getattr(py, "__class__")?;
|
||||
let dict = slf.to_object(py).getattr(py, "__dict__")?;
|
||||
Ok((cls, PyTuple::empty(py), dict))
|
||||
Ok((cls, PyTuple::empty_bound(py), dict))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue