Skip to content

Commit

Permalink
Migrate PyTuple / PyList constructors (#4580)
Browse files Browse the repository at this point in the history
* migrate `PyList::new`

* migrate `PyTuple::new`

* add newsfragment
  • Loading branch information
Icxolu authored Sep 29, 2024
1 parent e053dbc commit 2fa97f9
Show file tree
Hide file tree
Showing 30 changed files with 243 additions and 199 deletions.
6 changes: 3 additions & 3 deletions guide/src/conversions/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fails, so usually you will use something like
# use pyo3::types::PyList;
# fn main() -> PyResult<()> {
# Python::with_gil(|py| {
# let list = PyList::new(py, b"foo");
# let list = PyList::new(py, b"foo")?;
let v: Vec<i32> = list.extract()?;
# assert_eq!(&v, &[102, 111, 111]);
# Ok(())
Expand Down Expand Up @@ -183,7 +183,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(py, vec!["test", "test2"])?;
#
# let rustytuple: RustyTuple = tuple.extract()?;
# assert_eq!(rustytuple.0, "test");
Expand All @@ -206,7 +206,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(py, vec!["test"])?;
#
# let rustytuple: RustyTuple = tuple.extract()?;
# assert_eq!((rustytuple.0).0, "test");
Expand Down
7 changes: 5 additions & 2 deletions guide/src/exception.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,15 @@ In PyO3 every object has the [`PyAny::is_instance`] and [`PyAny::is_instance_of`
use pyo3::prelude::*;
use pyo3::types::{PyBool, PyList};

# fn main() -> PyResult<()> {
Python::with_gil(|py| {
assert!(PyBool::new(py, true).is_instance_of::<PyBool>());
let list = PyList::new(py, &[1, 2, 3, 4]);
let list = PyList::new(py, &[1, 2, 3, 4])?;
assert!(!list.is_instance_of::<PyBool>());
assert!(list.is_instance_of::<PyList>());
});
# Ok(())
})
# }
```

To check the type of an exception, you can similarly do:
Expand Down
2 changes: 1 addition & 1 deletion guide/src/python-from-rust/function-calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn main() -> PyResult<()> {
fun.call1(py, args)?;

// call object with Python tuple of positional arguments
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
let args = PyTuple::new(py, &[arg1, arg2, arg3])?;
fun.call1(py, args)?;
Ok(())
})
Expand Down
10 changes: 5 additions & 5 deletions guide/src/trait-bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl Model for UserModel {
Python::with_gil(|py| {
self.model
.bind(py)
.call_method("set_variables", (PyList::new(py, var),), None)
.call_method("set_variables", (PyList::new(py, var).unwrap(),), None)
.unwrap();
})
}
Expand Down Expand Up @@ -182,7 +182,7 @@ This wrapper will also perform the type conversions between Python and Rust.
# println!("Rust calling Python to set the variables");
# Python::with_gil(|py| {
# self.model.bind(py)
# .call_method("set_variables", (PyList::new(py, var),), None)
# .call_method("set_variables", (PyList::new(py, var).unwrap(),), None)
# .unwrap();
# })
# }
Expand Down Expand Up @@ -360,7 +360,7 @@ impl Model for UserModel {
# println!("Rust calling Python to set the variables");
# Python::with_gil(|py| {
# self.model.bind(py)
# .call_method("set_variables", (PyList::new(py, var),), None)
# .call_method("set_variables", (PyList::new(py, var).unwrap(),), None)
# .unwrap();
# })
# }
Expand Down Expand Up @@ -419,7 +419,7 @@ impl Model for UserModel {
# println!("Rust calling Python to set the variables");
# Python::with_gil(|py| {
# let py_model = self.model.bind(py)
# .call_method("set_variables", (PyList::new(py, var),), None)
# .call_method("set_variables", (PyList::new(py, var).unwrap(),), None)
# .unwrap();
# })
# }
Expand Down Expand Up @@ -517,7 +517,7 @@ impl Model for UserModel {
Python::with_gil(|py| {
self.model
.bind(py)
.call_method("set_variables", (PyList::new(py, var),), None)
.call_method("set_variables", (PyList::new(py, var).unwrap(),), None)
.unwrap();
})
}
Expand Down
6 changes: 3 additions & 3 deletions guide/src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ use pyo3::types::PyTuple;

# fn example<'py>(py: Python<'py>) -> PyResult<()> {
// Create a new tuple with the elements (0, 1, 2)
let t = PyTuple::new(py, [0, 1, 2]);
let t = PyTuple::new(py, [0, 1, 2])?;
for i in 0..=2 {
let entry: Borrowed<'_, 'py, PyAny> = t.get_borrowed_item(i)?;
// `PyAnyMethods::extract` is available on `Borrowed`
Expand Down Expand Up @@ -232,7 +232,7 @@ fn get_first_item<'py>(list: &Bound<'py, PyList>) -> PyResult<Bound<'py, PyAny>>
list.get_item(0)
}
# Python::with_gil(|py| {
# let l = PyList::new(py, ["hello world"]);
# let l = PyList::new(py, ["hello world"]).unwrap();
# assert!(get_first_item(&l).unwrap().eq("hello world").unwrap());
# })
```
Expand Down Expand Up @@ -295,7 +295,7 @@ For example, the following snippet extracts a Rust tuple of integers from a Pyth
# use pyo3::types::PyTuple;
# fn example<'py>(py: Python<'py>) -> PyResult<()> {
// create a new Python `tuple`, and use `.into_any()` to erase the type
let obj: Bound<'py, PyAny> = PyTuple::new(py, [1, 2, 3]).into_any();
let obj: Bound<'py, PyAny> = PyTuple::new(py, [1, 2, 3])?.into_any();

// extracting the Python `tuple` to a rust `(i32, i32, i32)` tuple
let (x, y, z) = obj.extract::<(i32, i32, i32)>()?;
Expand Down
1 change: 1 addition & 0 deletions newsfragments/4580.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`PyList::new` and `PyTuple::new` are now fallible due to `IntoPyObject` migration.
8 changes: 4 additions & 4 deletions pyo3-benches/benches/bench_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use pyo3::types::{PyList, PySequence};
fn iter_list(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
const LEN: usize = 100_000;
let list = PyList::new(py, 0..LEN);
let list = PyList::new(py, 0..LEN).unwrap();
let mut sum = 0;
b.iter(|| {
for x in &list {
Expand All @@ -29,7 +29,7 @@ fn list_new(b: &mut Bencher<'_>) {
fn list_get_item(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
const LEN: usize = 50_000;
let list = PyList::new(py, 0..LEN);
let list = PyList::new(py, 0..LEN).unwrap();
let mut sum = 0;
b.iter(|| {
for i in 0..LEN {
Expand All @@ -43,7 +43,7 @@ fn list_get_item(b: &mut Bencher<'_>) {
fn list_get_item_unchecked(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
const LEN: usize = 50_000;
let list = PyList::new(py, 0..LEN);
let list = PyList::new(py, 0..LEN).unwrap();
let mut sum = 0;
b.iter(|| {
for i in 0..LEN {
Expand All @@ -58,7 +58,7 @@ fn list_get_item_unchecked(b: &mut Bencher<'_>) {
fn sequence_from_list(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
const LEN: usize = 50_000;
let list = &PyList::new(py, 0..LEN);
let list = &PyList::new(py, 0..LEN).unwrap();
b.iter(|| black_box(list).downcast::<PySequence>().unwrap());
});
}
Expand Down
12 changes: 6 additions & 6 deletions pytests/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn make_date(py: Python<'_>, year: i32, month: u8, day: u8) -> PyResult<Bound<'_
}

#[pyfunction]
fn get_date_tuple<'py>(d: &Bound<'py, PyDate>) -> Bound<'py, PyTuple> {
fn get_date_tuple<'py>(d: &Bound<'py, PyDate>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
d.py(),
[d.get_year(), d.get_month() as i32, d.get_day() as i32],
Expand Down Expand Up @@ -52,7 +52,7 @@ fn time_with_fold<'py>(
}

#[pyfunction]
fn get_time_tuple<'py>(dt: &Bound<'py, PyTime>) -> Bound<'py, PyTuple> {
fn get_time_tuple<'py>(dt: &Bound<'py, PyTime>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
dt.py(),
[
Expand All @@ -65,7 +65,7 @@ fn get_time_tuple<'py>(dt: &Bound<'py, PyTime>) -> Bound<'py, PyTuple> {
}

#[pyfunction]
fn get_time_tuple_fold<'py>(dt: &Bound<'py, PyTime>) -> Bound<'py, PyTuple> {
fn get_time_tuple_fold<'py>(dt: &Bound<'py, PyTime>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
dt.py(),
[
Expand All @@ -89,7 +89,7 @@ fn make_delta(
}

#[pyfunction]
fn get_delta_tuple<'py>(delta: &Bound<'py, PyDelta>) -> Bound<'py, PyTuple> {
fn get_delta_tuple<'py>(delta: &Bound<'py, PyDelta>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
delta.py(),
[
Expand Down Expand Up @@ -128,7 +128,7 @@ fn make_datetime<'py>(
}

#[pyfunction]
fn get_datetime_tuple<'py>(dt: &Bound<'py, PyDateTime>) -> Bound<'py, PyTuple> {
fn get_datetime_tuple<'py>(dt: &Bound<'py, PyDateTime>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
dt.py(),
[
Expand All @@ -144,7 +144,7 @@ fn get_datetime_tuple<'py>(dt: &Bound<'py, PyDateTime>) -> Bound<'py, PyTuple> {
}

#[pyfunction]
fn get_datetime_tuple_fold<'py>(dt: &Bound<'py, PyDateTime>) -> Bound<'py, PyTuple> {
fn get_datetime_tuple_fold<'py>(dt: &Bound<'py, PyDateTime>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
dt.py(),
[
Expand Down
4 changes: 2 additions & 2 deletions src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ pub trait IntoPyObject<'py>: Sized {
let mut iter = iter.into_iter().map(|e| {
e.into_pyobject(py)
.map(BoundObject::into_any)
.map(BoundObject::unbind)
.map(BoundObject::into_bound)
.map_err(Into::into)
});
let list = crate::types::list::try_new_from_iter(py, &mut iter);
Expand All @@ -327,7 +327,7 @@ pub trait IntoPyObject<'py>: Sized {
let mut iter = iter.into_iter().map(|e| {
e.into_pyobject(py)
.map(BoundObject::into_any)
.map(BoundObject::unbind)
.map(BoundObject::into_bound)
.map_err(Into::into)
});
let list = crate::types::list::try_new_from_iter(py, &mut iter);
Expand Down
6 changes: 3 additions & 3 deletions src/conversions/smallvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,15 @@ mod tests {
Python::with_gil(|py| {
let sv: SmallVec<[u64; 8]> = [1, 2, 3, 4, 5].iter().cloned().collect();
let hso: PyObject = sv.clone().into_py(py);
let l = PyList::new(py, [1, 2, 3, 4, 5]);
let l = PyList::new(py, [1, 2, 3, 4, 5]).unwrap();
assert!(l.eq(hso).unwrap());
});
}

#[test]
fn test_smallvec_from_py_object() {
Python::with_gil(|py| {
let l = PyList::new(py, [1, 2, 3, 4, 5]);
let l = PyList::new(py, [1, 2, 3, 4, 5]).unwrap();
let sv: SmallVec<[u64; 8]> = l.extract().unwrap();
assert_eq!(sv.as_slice(), [1, 2, 3, 4, 5]);
});
Expand All @@ -171,7 +171,7 @@ mod tests {
Python::with_gil(|py| {
let sv: SmallVec<[u64; 8]> = [1, 2, 3, 4, 5].iter().cloned().collect();
let hso: PyObject = sv.to_object(py);
let l = PyList::new(py, [1, 2, 3, 4, 5]);
let l = PyList::new(py, [1, 2, 3, 4, 5]).unwrap();
assert!(l.eq(hso).unwrap());
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/impl_/extract_argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ impl<'py> VarargsHandler<'py> for TupleVarargs {
varargs: &[Option<PyArg<'py>>],
_function_description: &FunctionDescription,
) -> PyResult<Self::Varargs> {
Ok(PyTuple::new(py, varargs))
PyTuple::new(py, varargs)
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/impl_/pymodule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,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(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 \
Expand Down
2 changes: 1 addition & 1 deletion src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ impl<'a, 'py, T> Borrowed<'a, 'py, T> {
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let tuple = PyTuple::new(py, [1, 2, 3]);
/// let tuple = PyTuple::new(py, [1, 2, 3])?;
///
/// // borrows from `tuple`, so can only be
/// // used while `tuple` stays alive
Expand Down
7 changes: 5 additions & 2 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
/// ```
/// use pyo3::{prelude::*, py_run, types::PyList};
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| {
/// let list = PyList::new(py, &[1, 2, 3]);
/// let list = PyList::new(py, &[1, 2, 3])?;
/// py_run!(py, list, "assert list == [1, 2, 3]");
/// });
/// # Ok(())
/// })
/// # }
/// ```
///
/// You can use this macro to test pyfunctions or pyclasses quickly.
Expand Down
4 changes: 2 additions & 2 deletions src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -939,15 +939,15 @@ mod tests {

// If allow_threads is implemented correctly, this thread still owns the GIL here
// so the following Python calls should not cause crashes.
let list = PyList::new(py, [1, 2, 3, 4]);
let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
assert_eq!(list.extract::<Vec<i32>>().unwrap(), vec![1, 2, 3, 4]);
});
}

#[cfg(not(pyo3_disable_reference_pool))]
#[test]
fn test_allow_threads_pass_stuff_in() {
let list = Python::with_gil(|py| PyList::new(py, vec!["foo", "bar"]).unbind());
let list = Python::with_gil(|py| PyList::new(py, vec!["foo", "bar"]).unwrap().unbind());
let mut v = vec![1, 2, 3];
let a = std::sync::Arc::new(String::from("foo"));

Expand Down
5 changes: 4 additions & 1 deletion src/tests/hygiene/pymethods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ impl Dummy {

fn __delattr__(&mut self, name: ::std::string::String) {}

fn __dir__<'py>(&self, py: crate::Python<'py>) -> crate::Bound<'py, crate::types::PyList> {
fn __dir__<'py>(
&self,
py: crate::Python<'py>,
) -> crate::PyResult<crate::Bound<'py, crate::types::PyList>> {
crate::types::PyList::new(py, ::std::vec![0_u8])
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2021,7 +2021,7 @@ class SimpleClass:
let empty_list = PyList::empty(py).into_any();
assert!(empty_list.is_empty().unwrap());

let list = PyList::new(py, vec![1, 2, 3]).into_any();
let list = PyList::new(py, vec![1, 2, 3]).unwrap().into_any();
assert!(!list.is_empty().unwrap());

let not_container = 5.to_object(py).into_bound(py);
Expand Down
2 changes: 1 addition & 1 deletion src/types/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl PyDate {
///
/// This is equivalent to `datetime.date.fromtimestamp`
pub fn from_timestamp(py: Python<'_>, timestamp: i64) -> PyResult<Bound<'_, PyDate>> {
let time_tuple = PyTuple::new(py, [timestamp]);
let time_tuple = PyTuple::new(py, [timestamp])?;

// safety ensure that the API is loaded
let _api = ensure_datetime_api(py)?;
Expand Down
4 changes: 2 additions & 2 deletions src/types/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ mod tests {
#[cfg(not(any(PyPy, GraalPy)))]
fn test_from_sequence() {
Python::with_gil(|py| {
let items = PyList::new(py, vec![("a", 1), ("b", 2)]);
let items = PyList::new(py, vec![("a", 1), ("b", 2)]).unwrap();
let dict = PyDict::from_sequence(&items).unwrap();
assert_eq!(
1,
Expand Down Expand Up @@ -660,7 +660,7 @@ mod tests {
#[cfg(not(any(PyPy, GraalPy)))]
fn test_from_sequence_err() {
Python::with_gil(|py| {
let items = PyList::new(py, vec!["a", "b"]);
let items = PyList::new(py, vec!["a", "b"]).unwrap();
assert!(PyDict::from_sequence(&items).is_err());
});
}
Expand Down
Loading

0 comments on commit 2fa97f9

Please sign in to comment.