Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate PyTuple / PyList constructors #4580

Merged
merged 3 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading