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

port Python::eval to Bound API #3806

Merged
merged 1 commit into from
Feb 9, 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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ fn main() -> PyResult<()> {
let sys = py.import("sys")?;
let version: String = sys.getattr("version")?.extract()?;

let locals = [("os", py.import("os")?)].into_py_dict(py);
let locals = [("os", py.import("os")?)].into_py_dict(py).as_borrowed();
let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'";
let user: String = py.eval(code, None, Some(&locals))?.extract()?;
let user: String = py.eval_bound(code, None, Some(&locals))?.extract()?;

println!("Hello {}, I'm Python {}", user, version);
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion guide/src/conversions/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ struct RustyStruct {
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let py_dict = py.eval("{'foo': 'foo', 'bar': 'bar', 'foobar': 'foobar'}", None, None)?;
# let py_dict = py.eval_bound("{'foo': 'foo', 'bar': 'bar', 'foobar': 'foobar'}", None, None)?;
# let rustystruct: RustyStruct = py_dict.extract()?;
# assert_eq!(rustystruct.foo, "foo");
# assert_eq!(rustystruct.bar, "bar");
Expand Down
22 changes: 11 additions & 11 deletions guide/src/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ very simple and easy-to-understand programs like this:
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
Python::with_gil(|py| -> PyResult<()> {
let hello: &PyString = py.eval("\"Hello World!\"", None, None)?.extract()?;
let hello = py.eval_bound("\"Hello World!\"", None, None)?.downcast_into::<PyString>()?;
println!("Python says: {}", hello);
Ok(())
})?;
Expand All @@ -48,7 +48,7 @@ of the time we don't have to think about this, but consider the following:
# fn main() -> PyResult<()> {
Python::with_gil(|py| -> PyResult<()> {
for _ in 0..10 {
let hello: &PyString = py.eval("\"Hello World!\"", None, None)?.extract()?;
let hello = py.eval_bound("\"Hello World!\"", None, None)?.downcast_into::<PyString>()?;
println!("Python says: {}", hello);
}
// There are 10 copies of `hello` on Python's heap here.
Expand Down Expand Up @@ -76,7 +76,7 @@ is to acquire and release the GIL with each iteration of the loop.
# fn main() -> PyResult<()> {
for _ in 0..10 {
Python::with_gil(|py| -> PyResult<()> {
let hello: &PyString = py.eval("\"Hello World!\"", None, None)?.extract()?;
let hello = py.eval_bound("\"Hello World!\"", None, None)?.downcast_into::<PyString>()?;
println!("Python says: {}", hello);
Ok(())
})?; // only one copy of `hello` at a time
Expand All @@ -97,7 +97,7 @@ Python::with_gil(|py| -> PyResult<()> {
for _ in 0..10 {
let pool = unsafe { py.new_pool() };
let py = pool.python();
let hello: &PyString = py.eval("\"Hello World!\"", None, None)?.extract()?;
let hello = py.eval_bound("\"Hello World!\"", None, None)?.downcast_into::<PyString>()?;
println!("Python says: {}", hello);
}
Ok(())
Expand Down Expand Up @@ -144,8 +144,8 @@ reference count reaches zero? It depends whether or not we are holding the GIL.
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
Python::with_gil(|py| -> PyResult<()> {
let hello: Py<PyString> = py.eval("\"Hello World!\"", None, None)?.extract()?;
println!("Python says: {}", hello.as_ref(py));
let hello: Py<PyString> = py.eval_bound("\"Hello World!\"", None, None)?.extract()?;
println!("Python says: {}", hello.bind(py));
Ok(())
})?;
# Ok(())
Expand All @@ -166,7 +166,7 @@ we are *not* holding the GIL?
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
let hello: Py<PyString> = Python::with_gil(|py| {
py.eval("\"Hello World!\"", None, None)?.extract()
py.eval_bound("\"Hello World!\"", None, None)?.extract()
})?;
// Do some stuff...
// Now sometime later in the program we want to access `hello`.
Expand Down Expand Up @@ -197,11 +197,11 @@ We can avoid the delay in releasing memory if we are careful to drop the
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
let hello: Py<PyString> =
Python::with_gil(|py| py.eval("\"Hello World!\"", None, None)?.extract())?;
Python::with_gil(|py| py.eval_bound("\"Hello World!\"", None, None)?.extract())?;
// Do some stuff...
// Now sometime later in the program:
Python::with_gil(|py| {
println!("Python says: {}", hello.as_ref(py));
println!("Python says: {}", hello.bind(py));
drop(hello); // Memory released here.
});
# Ok(())
Expand All @@ -219,11 +219,11 @@ until the GIL is dropped.
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
let hello: Py<PyString> =
Python::with_gil(|py| py.eval("\"Hello World!\"", None, None)?.extract())?;
Python::with_gil(|py| py.eval_bound("\"Hello World!\"", None, None)?.extract())?;
// Do some stuff...
// Now sometime later in the program:
Python::with_gil(|py| {
println!("Python says: {}", hello.into_ref(py));
println!("Python says: {}", hello.into_bound(py));
// Memory not released yet.
// Do more stuff...
// Memory released here at end of `with_gil()` closure.
Expand Down
6 changes: 3 additions & 3 deletions guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,7 @@ all you need to do is remove `ObjectProtocol` from your code.
Or if you use `ObjectProtocol` by `use pyo3::prelude::*`, you have to do nothing.

Before:
```rust,compile_fail
```rust,compile_fail,ignore
use pyo3::ObjectProtocol;

# pyo3::Python::with_gil(|py| {
Expand All @@ -1212,7 +1212,7 @@ assert_eq!(hi.len().unwrap(), 5);
```

After:
```rust
```rust,ignore
# pyo3::Python::with_gil(|py| {
let obj = py.eval("lambda: 'Hi :)'", None, None).unwrap();
let hi: &pyo3::types::PyString = obj.call0().unwrap().downcast().unwrap();
Expand Down Expand Up @@ -1351,7 +1351,7 @@ let obj_ref_mut: &mut MyClass = obj.extract().unwrap();
```

After:
```rust
```rust,ignore
# use pyo3::prelude::*;
# use pyo3::types::IntoPyDict;
# #[pyclass] #[derive(Clone)] struct MyClass {}
Expand Down
4 changes: 2 additions & 2 deletions guide/src/python_from_rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ use pyo3::prelude::*;
# fn main() -> Result<(), ()> {
Python::with_gil(|py| {
let result = py
.eval("[i * 10 for i in range(5)]", None, None)
.eval_bound("[i * 10 for i in range(5)]", None, None)
.map_err(|e| {
e.print_and_set_sys_last_vars(py);
})?;
Expand Down Expand Up @@ -466,7 +466,7 @@ class House(object):

house.call_method0("__enter__").unwrap();

let result = py.eval("undefined_variable + 1", None, None);
let result = py.eval_bound("undefined_variable + 1", None, None);

// If the eval threw an exception we'll pass it through to the context manager.
// Otherwise, __exit__ is called with empty arguments (Python "None").
Expand Down
8 changes: 4 additions & 4 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,8 +694,8 @@ mod tests {
#[test]
fn test_debug() {
Python::with_gil(|py| {
let bytes = py.eval("b'abcde'", None, None).unwrap();
let buffer: PyBuffer<u8> = PyBuffer::get(bytes).unwrap();
let bytes = py.eval_bound("b'abcde'", None, None).unwrap();
let buffer: PyBuffer<u8> = PyBuffer::get(bytes.as_gil_ref()).unwrap();
let expected = format!(
concat!(
"PyBuffer {{ buf: {:?}, obj: {:?}, ",
Expand Down Expand Up @@ -857,8 +857,8 @@ mod tests {
#[test]
fn test_bytes_buffer() {
Python::with_gil(|py| {
let bytes = py.eval("b'abcde'", None, None).unwrap();
let buffer = PyBuffer::get(bytes).unwrap();
let bytes = py.eval_bound("b'abcde'", None, None).unwrap();
let buffer = PyBuffer::get(bytes.as_gil_ref()).unwrap();
assert_eq!(buffer.dimensions(), 1);
assert_eq!(buffer.item_count(), 5);
assert_eq!(buffer.format().to_str().unwrap(), "B");
Expand Down
5 changes: 3 additions & 2 deletions src/conversions/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,7 @@ mod tests {
mod proptests {
use super::*;
use crate::tests::common::CatchWarnings;
use crate::types::any::PyAnyMethods;
use crate::types::IntoPyDict;
use proptest::prelude::*;

Expand All @@ -1105,9 +1106,9 @@ mod tests {
fn test_pyo3_offset_fixed_frompyobject_created_in_python(timestamp in 0..(i32::MAX as i64), timedelta in -86399i32..=86399i32) {
Python::with_gil(|py| {

let globals = [("datetime", py.import("datetime").unwrap())].into_py_dict(py);
let globals = [("datetime", py.import("datetime").unwrap())].into_py_dict(py).as_borrowed();
let code = format!("datetime.datetime.fromtimestamp({}).replace(tzinfo=datetime.timezone(datetime.timedelta(seconds={})))", timestamp, timedelta);
let t = py.eval(&code, Some(globals), None).unwrap();
let t = py.eval_bound(&code, Some(&globals), None).unwrap();

// Get ISO 8601 string from python
let py_iso_str = t.call_method0("isoformat").unwrap();
Expand Down
6 changes: 4 additions & 2 deletions src/conversions/num_bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ fn int_n_bits(long: &Bound<'_, PyLong>) -> PyResult<usize> {

#[cfg(test)]
mod tests {
use self::{any::PyAnyMethods, dict::PyDictMethods};

use super::*;
use crate::types::{PyDict, PyModule};
use indoc::indoc;
Expand Down Expand Up @@ -340,9 +342,9 @@ mod tests {
fn convert_index_class() {
Python::with_gil(|py| {
let index = python_index_class(py);
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("index", index).unwrap();
let ob = py.eval("index.C(10)", None, Some(locals)).unwrap();
let ob = py.eval_bound("index.C(10)", None, Some(&locals)).unwrap();
let _: BigInt = ob.extract().unwrap();
});
}
Expand Down
9 changes: 5 additions & 4 deletions src/conversions/std/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ mod tests {
sync::atomic::{AtomicUsize, Ordering},
};

use crate::types::any::PyAnyMethods;
use crate::{types::PyList, IntoPy, PyResult, Python, ToPyObject};

#[test]
Expand Down Expand Up @@ -157,7 +158,7 @@ mod tests {
fn test_extract_bytearray_to_array() {
Python::with_gil(|py| {
let v: [u8; 33] = py
.eval(
.eval_bound(
"bytearray(b'abcabcabcabcabcabcabcabcabcabcabc')",
None,
None,
Expand All @@ -173,7 +174,7 @@ mod tests {
fn test_extract_small_bytearray_to_array() {
Python::with_gil(|py| {
let v: [u8; 3] = py
.eval("bytearray(b'abc')", None, None)
.eval_bound("bytearray(b'abc')", None, None)
.unwrap()
.extract()
.unwrap();
Expand All @@ -197,7 +198,7 @@ mod tests {
fn test_extract_invalid_sequence_length() {
Python::with_gil(|py| {
let v: PyResult<[u8; 3]> = py
.eval("bytearray(b'abcdefg')", None, None)
.eval_bound("bytearray(b'abcdefg')", None, None)
.unwrap()
.extract();
assert_eq!(
Expand All @@ -223,7 +224,7 @@ mod tests {
#[test]
fn test_extract_non_iterable_to_array() {
Python::with_gil(|py| {
let v = py.eval("42", None, None).unwrap();
let v = py.eval_bound("42", None, None).unwrap();
v.extract::<i32>().unwrap();
v.extract::<[i32; 1]>().unwrap_err();
});
Expand Down
14 changes: 8 additions & 6 deletions src/conversions/std/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,8 @@ nonzero_int_impl!(NonZeroUsize, usize);
#[cfg(test)]
mod test_128bit_integers {
use super::*;
use crate::types::any::PyAnyMethods;

#[cfg(not(target_arch = "wasm32"))]
use crate::types::PyDict;

Expand Down Expand Up @@ -474,7 +476,7 @@ mod test_128bit_integers {
#[test]
fn test_i128_overflow() {
Python::with_gil(|py| {
let obj = py.eval("(1 << 130) * -1", None, None).unwrap();
let obj = py.eval_bound("(1 << 130) * -1", None, None).unwrap();
let err = obj.extract::<i128>().unwrap_err();
assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py));
})
Expand All @@ -483,7 +485,7 @@ mod test_128bit_integers {
#[test]
fn test_u128_overflow() {
Python::with_gil(|py| {
let obj = py.eval("1 << 130", None, None).unwrap();
let obj = py.eval_bound("1 << 130", None, None).unwrap();
let err = obj.extract::<u128>().unwrap_err();
assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py));
})
Expand Down Expand Up @@ -527,7 +529,7 @@ mod test_128bit_integers {
#[test]
fn test_nonzero_i128_overflow() {
Python::with_gil(|py| {
let obj = py.eval("(1 << 130) * -1", None, None).unwrap();
let obj = py.eval_bound("(1 << 130) * -1", None, None).unwrap();
let err = obj.extract::<NonZeroI128>().unwrap_err();
assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py));
})
Expand All @@ -536,7 +538,7 @@ mod test_128bit_integers {
#[test]
fn test_nonzero_u128_overflow() {
Python::with_gil(|py| {
let obj = py.eval("1 << 130", None, None).unwrap();
let obj = py.eval_bound("1 << 130", None, None).unwrap();
let err = obj.extract::<NonZeroU128>().unwrap_err();
assert!(err.is_instance_of::<crate::exceptions::PyOverflowError>(py));
})
Expand All @@ -545,7 +547,7 @@ mod test_128bit_integers {
#[test]
fn test_nonzero_i128_zero_value() {
Python::with_gil(|py| {
let obj = py.eval("0", None, None).unwrap();
let obj = py.eval_bound("0", None, None).unwrap();
let err = obj.extract::<NonZeroI128>().unwrap_err();
assert!(err.is_instance_of::<crate::exceptions::PyValueError>(py));
})
Expand All @@ -554,7 +556,7 @@ mod test_128bit_integers {
#[test]
fn test_nonzero_u128_zero_value() {
Python::with_gil(|py| {
let obj = py.eval("0", None, None).unwrap();
let obj = py.eval_bound("0", None, None).unwrap();
let err = obj.extract::<NonZeroU128>().unwrap_err();
assert!(err.is_instance_of::<crate::exceptions::PyValueError>(py));
})
Expand Down
15 changes: 10 additions & 5 deletions src/conversions/std/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,15 @@ impl IntoPy<Py<PyAny>> for Cow<'_, [u8]> {
mod tests {
use std::borrow::Cow;

use crate::{types::PyBytes, Python, ToPyObject};
use crate::{
types::{any::PyAnyMethods, PyBytes},
Python, ToPyObject,
};

#[test]
fn test_extract_bytes() {
Python::with_gil(|py| {
let py_bytes = py.eval("b'Hello Python'", None, None).unwrap();
let py_bytes = py.eval_bound("b'Hello Python'", None, None).unwrap();
let bytes: &[u8] = py_bytes.extract().unwrap();
assert_eq!(bytes, b"Hello Python");
});
Expand All @@ -75,15 +78,17 @@ mod tests {
#[test]
fn test_cow_impl() {
Python::with_gil(|py| {
let bytes = py.eval(r#"b"foobar""#, None, None).unwrap();
let bytes = py.eval_bound(r#"b"foobar""#, None, None).unwrap();
let cow = bytes.extract::<Cow<'_, [u8]>>().unwrap();
assert_eq!(cow, Cow::<[u8]>::Borrowed(b"foobar"));

let byte_array = py.eval(r#"bytearray(b"foobar")"#, None, None).unwrap();
let byte_array = py
.eval_bound(r#"bytearray(b"foobar")"#, None, None)
.unwrap();
let cow = byte_array.extract::<Cow<'_, [u8]>>().unwrap();
assert_eq!(cow, Cow::<[u8]>::Owned(b"foobar".to_vec()));

let something_else_entirely = py.eval("42", None, None).unwrap();
let something_else_entirely = py.eval_bound("42", None, None).unwrap();
something_else_entirely
.extract::<Cow<'_, [u8]>>()
.unwrap_err();
Expand Down
Loading
Loading