Merge pull request #3806 from Icxolu/python-eval
port `Python::eval` to `Bound` API
This commit is contained in:
commit
2fedea24b3
|
@ -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(())
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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(())
|
||||
})?;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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(())
|
||||
|
@ -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(())
|
||||
|
@ -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`.
|
||||
|
@ -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(())
|
||||
|
@ -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.
|
||||
|
|
|
@ -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| {
|
||||
|
@ -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();
|
||||
|
@ -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 {}
|
||||
|
|
|
@ -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);
|
||||
})?;
|
||||
|
@ -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").
|
||||
|
|
|
@ -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: {:?}, ",
|
||||
|
@ -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");
|
||||
|
|
|
@ -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::*;
|
||||
|
||||
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -130,6 +130,7 @@ mod tests {
|
|||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use crate::types::any::PyAnyMethods;
|
||||
use crate::{types::PyList, IntoPy, PyResult, Python, ToPyObject};
|
||||
|
||||
#[test]
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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!(
|
||||
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
})
|
||||
|
@ -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));
|
||||
})
|
||||
|
@ -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));
|
||||
})
|
||||
|
@ -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));
|
||||
})
|
||||
|
@ -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));
|
||||
})
|
||||
|
@ -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));
|
||||
})
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
|
@ -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();
|
||||
|
|
|
@ -800,8 +800,9 @@ pub mod socket {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::types::any::PyAnyMethods;
|
||||
use crate::types::{IntoPyDict, PyDict};
|
||||
use crate::{PyErr, Python};
|
||||
use crate::{PyErr, PyNativeType, Python};
|
||||
|
||||
import_exception!(socket, gaierror);
|
||||
import_exception!(email.errors, MessageError);
|
||||
|
@ -863,13 +864,14 @@ mod tests {
|
|||
|
||||
Python::with_gil(|py| {
|
||||
let error_type = py.get_type::<CustomError>();
|
||||
let ctx = [("CustomError", error_type)].into_py_dict(py);
|
||||
let ctx = [("CustomError", error_type)].into_py_dict(py).as_borrowed();
|
||||
let type_description: String = py
|
||||
.eval("str(CustomError)", None, Some(ctx))
|
||||
.eval_bound("str(CustomError)", None, Some(&ctx))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
assert_eq!(type_description, "<class 'mymodule.CustomError'>");
|
||||
let ctx = ctx.as_gil_ref();
|
||||
py.run(
|
||||
"assert CustomError('oops').args == ('oops',)",
|
||||
None,
|
||||
|
@ -886,9 +888,9 @@ mod tests {
|
|||
create_exception!(mymodule.exceptions, CustomError, PyException);
|
||||
Python::with_gil(|py| {
|
||||
let error_type = py.get_type::<CustomError>();
|
||||
let ctx = [("CustomError", error_type)].into_py_dict(py);
|
||||
let ctx = [("CustomError", error_type)].into_py_dict(py).as_borrowed();
|
||||
let type_description: String = py
|
||||
.eval("str(CustomError)", None, Some(ctx))
|
||||
.eval_bound("str(CustomError)", None, Some(&ctx))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
|
@ -905,13 +907,14 @@ mod tests {
|
|||
|
||||
Python::with_gil(|py| {
|
||||
let error_type = py.get_type::<CustomError>();
|
||||
let ctx = [("CustomError", error_type)].into_py_dict(py);
|
||||
let ctx = [("CustomError", error_type)].into_py_dict(py).as_borrowed();
|
||||
let type_description: String = py
|
||||
.eval("str(CustomError)", None, Some(ctx))
|
||||
.eval_bound("str(CustomError)", None, Some(&ctx))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
assert_eq!(type_description, "<class 'mymodule.CustomError'>");
|
||||
let ctx = ctx.as_gil_ref();
|
||||
py.run(
|
||||
"assert CustomError('oops').args == ('oops',)",
|
||||
None,
|
||||
|
@ -934,13 +937,14 @@ mod tests {
|
|||
|
||||
Python::with_gil(|py| {
|
||||
let error_type = py.get_type::<CustomError>();
|
||||
let ctx = [("CustomError", error_type)].into_py_dict(py);
|
||||
let ctx = [("CustomError", error_type)].into_py_dict(py).as_borrowed();
|
||||
let type_description: String = py
|
||||
.eval("str(CustomError)", None, Some(ctx))
|
||||
.eval_bound("str(CustomError)", None, Some(&ctx))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
assert_eq!(type_description, "<class 'mymodule.CustomError'>");
|
||||
let ctx = ctx.as_gil_ref();
|
||||
py.run(
|
||||
"assert CustomError('oops').args == ('oops',)",
|
||||
None,
|
||||
|
@ -1077,7 +1081,7 @@ mod tests {
|
|||
PyErr::from_value(PyUnicodeDecodeError::new_utf8(py, invalid_utf8, err).unwrap())
|
||||
});
|
||||
test_exception!(PyUnicodeEncodeError, |py| py
|
||||
.eval("chr(40960).encode('ascii')", None, None)
|
||||
.eval_bound("chr(40960).encode('ascii')", None, None)
|
||||
.unwrap_err());
|
||||
test_exception!(PyUnicodeTranslateError, |_| {
|
||||
PyUnicodeTranslateError::new_err(("\u{3042}", 0, 1, "ouch"))
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ffi::*;
|
||||
use crate::types::any::PyAnyMethods;
|
||||
use crate::Python;
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
use crate::{
|
||||
types::{any::PyAnyMethods, PyDict, PyString},
|
||||
types::{PyDict, PyString},
|
||||
IntoPy, Py, PyAny,
|
||||
};
|
||||
#[cfg(not(any(Py_3_12, Py_LIMITED_API)))]
|
||||
|
@ -293,7 +294,7 @@ fn test_get_tzinfo() {
|
|||
#[test]
|
||||
fn test_inc_dec_ref() {
|
||||
Python::with_gil(|py| {
|
||||
let obj = py.eval("object()", None, None).unwrap();
|
||||
let obj = py.eval_bound("object()", None, None).unwrap();
|
||||
|
||||
let ref_count = obj.get_refcnt();
|
||||
let ptr = obj.as_ptr();
|
||||
|
|
|
@ -507,6 +507,7 @@ fn decrement_gil_count() {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{gil_is_acquired, GILPool, GIL_COUNT, OWNED_OBJECTS, POOL};
|
||||
use crate::types::any::PyAnyMethods;
|
||||
use crate::{ffi, gil, PyObject, Python, ToPyObject};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use parking_lot::{const_mutex, Condvar, Mutex};
|
||||
|
@ -518,7 +519,7 @@ mod tests {
|
|||
let pool = unsafe { py.new_pool() };
|
||||
let py = pool.python();
|
||||
|
||||
let obj = py.eval("object()", None, None).unwrap();
|
||||
let obj = py.eval_bound("object()", None, None).unwrap();
|
||||
obj.to_object(py)
|
||||
}
|
||||
|
||||
|
@ -735,7 +736,7 @@ mod tests {
|
|||
fn dropping_gil_does_not_invalidate_references() {
|
||||
// Acquiring GIL for the second time should be safe - see #864
|
||||
Python::with_gil(|py| {
|
||||
let obj = Python::with_gil(|_| py.eval("object()", None, None).unwrap());
|
||||
let obj = Python::with_gil(|_| py.eval_bound("object()", None, None).unwrap());
|
||||
|
||||
// After gil2 drops, obj should still have a reference count of one
|
||||
assert_eq!(obj.get_refcnt(), 1);
|
||||
|
|
|
@ -221,9 +221,9 @@
|
|||
//! 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(())
|
||||
|
|
|
@ -117,14 +117,19 @@
|
|||
//! [`Rc`]: std::rc::Rc
|
||||
//! [`Py`]: crate::Py
|
||||
use crate::err::{self, PyDowncastError, PyErr, PyResult};
|
||||
use crate::ffi_ptr_ext::FfiPtrExt;
|
||||
use crate::gil::{GILGuard, GILPool, SuspendGIL};
|
||||
use crate::impl_::not_send::NotSend;
|
||||
use crate::py_result_ext::PyResultExt;
|
||||
use crate::type_object::HasPyGilRef;
|
||||
use crate::types::any::PyAnyMethods;
|
||||
use crate::types::{
|
||||
PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType,
|
||||
};
|
||||
use crate::version::PythonVersionInfo;
|
||||
use crate::{ffi, FromPyPointer, IntoPy, Py, PyObject, PyTypeCheck, PyTypeInfo};
|
||||
use crate::{
|
||||
ffi, Bound, FromPyPointer, IntoPy, Py, PyNativeType, PyObject, PyTypeCheck, PyTypeInfo,
|
||||
};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_int;
|
||||
|
@ -358,8 +363,8 @@ pub use nightly::Ungil;
|
|||
/// # fn main () -> PyResult<()> {
|
||||
/// Python::with_gil(|py| -> PyResult<()> {
|
||||
/// for _ in 0..10 {
|
||||
/// let hello: &PyString = py.eval("\"Hello World!\"", None, None)?.extract()?;
|
||||
/// println!("Python says: {}", hello.to_str()?);
|
||||
/// let hello = py.eval_bound("\"Hello World!\"", None, None)?.downcast_into::<PyString>()?;
|
||||
/// println!("Python says: {}", hello.to_cow()?);
|
||||
/// // Normally variables in a loop scope are dropped here, but `hello` is a reference to
|
||||
/// // something owned by the Python interpreter. Dropping this reference does nothing.
|
||||
/// }
|
||||
|
@ -417,7 +422,7 @@ impl Python<'_> {
|
|||
///
|
||||
/// # fn main() -> PyResult<()> {
|
||||
/// Python::with_gil(|py| -> PyResult<()> {
|
||||
/// let x: i32 = py.eval("5", None, None)?.extract()?;
|
||||
/// let x: i32 = py.eval_bound("5", None, None)?.extract()?;
|
||||
/// assert_eq!(x, 5);
|
||||
/// Ok(())
|
||||
/// })
|
||||
|
@ -546,6 +551,28 @@ impl<'py> Python<'py> {
|
|||
f()
|
||||
}
|
||||
|
||||
/// Deprecated version of [`Python::eval_bound`]
|
||||
#[cfg_attr(
|
||||
not(feature = "gil-refs"),
|
||||
deprecated(
|
||||
since = "0.21.0",
|
||||
note = "`Python::eval` will be replaced by `Python::eval_bound` in a future PyO3 version"
|
||||
)
|
||||
)]
|
||||
pub fn eval(
|
||||
self,
|
||||
code: &str,
|
||||
globals: Option<&'py PyDict>,
|
||||
locals: Option<&'py PyDict>,
|
||||
) -> PyResult<&'py PyAny> {
|
||||
self.eval_bound(
|
||||
code,
|
||||
globals.map(PyNativeType::as_borrowed).as_deref(),
|
||||
locals.map(PyNativeType::as_borrowed).as_deref(),
|
||||
)
|
||||
.map(Bound::into_gil_ref)
|
||||
}
|
||||
|
||||
/// Evaluates a Python expression in the given context and returns the result.
|
||||
///
|
||||
/// If `globals` is `None`, it defaults to Python module `__main__`.
|
||||
|
@ -559,17 +586,17 @@ impl<'py> Python<'py> {
|
|||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// # Python::with_gil(|py| {
|
||||
/// let result = py.eval("[i * 10 for i in range(5)]", None, None).unwrap();
|
||||
/// let result = py.eval_bound("[i * 10 for i in range(5)]", None, None).unwrap();
|
||||
/// let res: Vec<i64> = result.extract().unwrap();
|
||||
/// assert_eq!(res, vec![0, 10, 20, 30, 40])
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn eval(
|
||||
pub fn eval_bound(
|
||||
self,
|
||||
code: &str,
|
||||
globals: Option<&PyDict>,
|
||||
locals: Option<&PyDict>,
|
||||
) -> PyResult<&'py PyAny> {
|
||||
globals: Option<&Bound<'py, PyDict>>,
|
||||
locals: Option<&Bound<'py, PyDict>>,
|
||||
) -> PyResult<Bound<'py, PyAny>> {
|
||||
self.run_code(code, ffi::Py_eval_input, globals, locals)
|
||||
}
|
||||
|
||||
|
@ -613,7 +640,12 @@ impl<'py> Python<'py> {
|
|||
globals: Option<&PyDict>,
|
||||
locals: Option<&PyDict>,
|
||||
) -> PyResult<()> {
|
||||
let res = self.run_code(code, ffi::Py_file_input, globals, locals);
|
||||
let res = self.run_code(
|
||||
code,
|
||||
ffi::Py_file_input,
|
||||
globals.map(PyNativeType::as_borrowed).as_deref(),
|
||||
locals.map(PyNativeType::as_borrowed).as_deref(),
|
||||
);
|
||||
res.map(|obj| {
|
||||
debug_assert!(obj.is_none());
|
||||
})
|
||||
|
@ -630,9 +662,9 @@ impl<'py> Python<'py> {
|
|||
self,
|
||||
code: &str,
|
||||
start: c_int,
|
||||
globals: Option<&PyDict>,
|
||||
locals: Option<&PyDict>,
|
||||
) -> PyResult<&'py PyAny> {
|
||||
globals: Option<&Bound<'py, PyDict>>,
|
||||
locals: Option<&Bound<'py, PyDict>>,
|
||||
) -> PyResult<Bound<'py, PyAny>> {
|
||||
let code = CString::new(code)?;
|
||||
unsafe {
|
||||
let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _);
|
||||
|
@ -675,7 +707,7 @@ impl<'py> Python<'py> {
|
|||
let res_ptr = ffi::PyEval_EvalCode(code_obj, globals, locals);
|
||||
ffi::Py_DECREF(code_obj);
|
||||
|
||||
self.from_owned_ptr_or_err(res_ptr)
|
||||
res_ptr.assume_owned_or_err(self).downcast_into_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1077,18 +1109,18 @@ mod tests {
|
|||
Python::with_gil(|py| {
|
||||
// Make sure builtin names are accessible
|
||||
let v: i32 = py
|
||||
.eval("min(1, 2)", None, None)
|
||||
.eval_bound("min(1, 2)", None, None)
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
assert_eq!(v, 1);
|
||||
|
||||
let d = [("foo", 13)].into_py_dict(py);
|
||||
let d = [("foo", 13)].into_py_dict(py).as_borrowed();
|
||||
|
||||
// Inject our own global namespace
|
||||
let v: i32 = py
|
||||
.eval("foo + 29", Some(d), None)
|
||||
.eval_bound("foo + 29", Some(&d), None)
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
|
@ -1096,7 +1128,7 @@ mod tests {
|
|||
|
||||
// Inject our own local namespace
|
||||
let v: i32 = py
|
||||
.eval("foo + 29", None, Some(d))
|
||||
.eval_bound("foo + 29", None, Some(&d))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
|
@ -1104,7 +1136,7 @@ mod tests {
|
|||
|
||||
// Make sure builtin names are still accessible when using a local namespace
|
||||
let v: i32 = py
|
||||
.eval("min(foo, 2)", None, Some(d))
|
||||
.eval_bound("min(foo, 2)", None, Some(&d))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
|
@ -1193,7 +1225,7 @@ mod tests {
|
|||
assert_eq!(py.Ellipsis().to_string(), "Ellipsis");
|
||||
|
||||
let v = py
|
||||
.eval("...", None, None)
|
||||
.eval_bound("...", None, None)
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@ use crate::{
|
|||
///
|
||||
/// # fn main() -> PyResult<()> {
|
||||
/// Python::with_gil(|py| -> PyResult<()> {
|
||||
/// let list = py.eval("iter([1, 2, 3, 4])", None, None)?;
|
||||
/// let list = py.eval_bound("iter([1, 2, 3, 4])", None, None)?;
|
||||
/// let numbers: PyResult<Vec<usize>> = list
|
||||
/// .iter()?
|
||||
/// .map(|i| i.and_then(PyAny::extract::<usize>))
|
||||
/// .map(|i| i.and_then(|i|i.extract::<usize>()))
|
||||
/// .collect();
|
||||
/// let sum: usize = numbers?.iter().sum();
|
||||
/// assert_eq!(sum, 10);
|
||||
|
|
|
@ -59,9 +59,9 @@ pub use self::typeobject::PyType;
|
|||
///
|
||||
/// # pub fn main() -> PyResult<()> {
|
||||
/// Python::with_gil(|py| {
|
||||
/// let dict: &PyDict = py.eval("{'a':'b', 'c':'d'}", None, None)?.downcast()?;
|
||||
/// let dict = py.eval_bound("{'a':'b', 'c':'d'}", None, None)?.downcast_into::<PyDict>()?;
|
||||
///
|
||||
/// for (key, value) in dict {
|
||||
/// for (key, value) in dict.iter() {
|
||||
/// println!("key: {}, value: {}", key, value);
|
||||
/// }
|
||||
///
|
||||
|
|
|
@ -4,11 +4,11 @@ use pyo3::prelude::*;
|
|||
use pyo3::types::{timezone_utc, IntoPyDict, PyDate, PyDateTime, PyTime};
|
||||
use pyo3_ffi::PyDateTime_IMPORT;
|
||||
|
||||
fn _get_subclasses<'p>(
|
||||
py: Python<'p>,
|
||||
fn _get_subclasses<'py>(
|
||||
py: Python<'py>,
|
||||
py_type: &str,
|
||||
args: &str,
|
||||
) -> PyResult<(&'p PyAny, &'p PyAny, &'p PyAny)> {
|
||||
) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyAny>, Bound<'py, PyAny>)> {
|
||||
// Import the class from Python and create some subclasses
|
||||
let datetime = py.import("datetime")?;
|
||||
|
||||
|
@ -21,14 +21,15 @@ fn _get_subclasses<'p>(
|
|||
py.run(&make_subclass_py, None, Some(locals))?;
|
||||
py.run(make_sub_subclass_py, None, Some(locals))?;
|
||||
|
||||
let locals = locals.as_borrowed();
|
||||
// Construct an instance of the base class
|
||||
let obj = py.eval(&format!("{}({})", py_type, args), None, Some(locals))?;
|
||||
let obj = py.eval_bound(&format!("{}({})", py_type, args), None, Some(&locals))?;
|
||||
|
||||
// Construct an instance of the subclass
|
||||
let sub_obj = py.eval(&format!("Subklass({})", args), None, Some(locals))?;
|
||||
let sub_obj = py.eval_bound(&format!("Subklass({})", args), None, Some(&locals))?;
|
||||
|
||||
// Construct an instance of the sub-subclass
|
||||
let sub_sub_obj = py.eval(&format!("SubSubklass({})", args), None, Some(locals))?;
|
||||
let sub_sub_obj = py.eval_bound(&format!("SubSubklass({})", args), None, Some(&locals))?;
|
||||
|
||||
Ok((obj, sub_obj, sub_sub_obj))
|
||||
}
|
||||
|
@ -122,10 +123,10 @@ fn test_datetime_utc() {
|
|||
|
||||
let dt = PyDateTime::new(py, 2018, 1, 1, 0, 0, 0, 0, Some(utc)).unwrap();
|
||||
|
||||
let locals = [("dt", dt)].into_py_dict(py);
|
||||
let locals = [("dt", dt)].into_py_dict(py).as_borrowed();
|
||||
|
||||
let offset: f32 = py
|
||||
.eval("dt.utcoffset().total_seconds()", None, Some(locals))
|
||||
.eval_bound("dt.utcoffset().total_seconds()", None, Some(&locals))
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
|
|
|
@ -486,14 +486,14 @@ pub struct Zap {
|
|||
fn test_from_py_with() {
|
||||
Python::with_gil(|py| {
|
||||
let py_zap = py
|
||||
.eval(
|
||||
.eval_bound(
|
||||
r#"{"name": "whatever", "my_object": [1, 2, 3]}"#,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("failed to create dict");
|
||||
|
||||
let zap = Zap::extract(py_zap).unwrap();
|
||||
let zap = Zap::extract_bound(&py_zap).unwrap();
|
||||
|
||||
assert_eq!(zap.name, "whatever");
|
||||
assert_eq!(zap.some_object_length, 3usize);
|
||||
|
@ -507,10 +507,10 @@ pub struct ZapTuple(String, #[pyo3(from_py_with = "PyAny::len")] usize);
|
|||
fn test_from_py_with_tuple_struct() {
|
||||
Python::with_gil(|py| {
|
||||
let py_zap = py
|
||||
.eval(r#"("whatever", [1, 2, 3])"#, None, None)
|
||||
.eval_bound(r#"("whatever", [1, 2, 3])"#, None, None)
|
||||
.expect("failed to create tuple");
|
||||
|
||||
let zap = ZapTuple::extract(py_zap).unwrap();
|
||||
let zap = ZapTuple::extract_bound(&py_zap).unwrap();
|
||||
|
||||
assert_eq!(zap.0, "whatever");
|
||||
assert_eq!(zap.1, 3usize);
|
||||
|
@ -521,10 +521,10 @@ fn test_from_py_with_tuple_struct() {
|
|||
fn test_from_py_with_tuple_struct_error() {
|
||||
Python::with_gil(|py| {
|
||||
let py_zap = py
|
||||
.eval(r#"("whatever", [1, 2, 3], "third")"#, None, None)
|
||||
.eval_bound(r#"("whatever", [1, 2, 3], "third")"#, None, None)
|
||||
.expect("failed to create tuple");
|
||||
|
||||
let f = ZapTuple::extract(py_zap);
|
||||
let f = ZapTuple::extract_bound(&py_zap);
|
||||
|
||||
assert!(f.is_err());
|
||||
assert_eq!(
|
||||
|
@ -544,10 +544,10 @@ pub enum ZapEnum {
|
|||
fn test_from_py_with_enum() {
|
||||
Python::with_gil(|py| {
|
||||
let py_zap = py
|
||||
.eval(r#"("whatever", [1, 2, 3])"#, None, None)
|
||||
.eval_bound(r#"("whatever", [1, 2, 3])"#, None, None)
|
||||
.expect("failed to create tuple");
|
||||
|
||||
let zap = ZapEnum::extract(py_zap).unwrap();
|
||||
let zap = ZapEnum::extract_bound(&py_zap).unwrap();
|
||||
let expected_zap = ZapEnum::Zip(2);
|
||||
|
||||
assert_eq!(zap, expected_zap);
|
||||
|
|
|
@ -240,7 +240,7 @@ mod inheriting_native_type {
|
|||
let dict_sub = pyo3::Py::new(py, DictWithName::new()).unwrap();
|
||||
assert_eq!(dict_sub.get_refcnt(py), 1);
|
||||
|
||||
let item = py.eval("object()", None, None).unwrap();
|
||||
let item = &py.eval_bound("object()", None, None).unwrap();
|
||||
assert_eq!(item.get_refcnt(), 1);
|
||||
|
||||
dict_sub.as_ref(py).set_item("foo", item).unwrap();
|
||||
|
|
Loading…
Reference in New Issue