Merge pull request #3816 from Icxolu/python-run

port `Python::run` to `Bound` API
This commit is contained in:
David Hewitt 2024-02-09 21:42:51 +00:00 committed by GitHub
commit 45f2b0aba5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 198 additions and 148 deletions

View File

@ -387,10 +387,10 @@ fn my_module(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
#
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let globals = PyModule::import(py, "__main__")?.dict();
# let globals = PyModule::import(py, "__main__")?.dict().as_borrowed();
# globals.set_item("Number", Number::type_object_bound(py))?;
#
# py.run(SCRIPT, Some(globals), None)?;
# py.run_bound(SCRIPT, Some(&globals), None)?;
# Ok(())
# })
# }

View File

@ -93,9 +93,9 @@ fn func() -> String {
# use pyo3::wrap_pymodule;
# use pyo3::types::IntoPyDict;
# let parent_module = wrap_pymodule!(parent_module)(py);
# let ctx = [("parent_module", parent_module)].into_py_dict(py);
# let ctx = [("parent_module", parent_module)].into_py_dict(py).as_borrowed();
#
# py.run("assert parent_module.child_module.func() == 'func'", None, Some(&ctx)).unwrap();
# py.run_bound("assert parent_module.child_module.func() == 'func'", None, Some(&ctx)).unwrap();
# })
```

View File

@ -290,7 +290,7 @@ fn foo(_py: Python<'_>, foo_module: &PyModule) -> PyResult<()> {
fn main() -> PyResult<()> {
pyo3::append_to_inittab!(foo);
Python::with_gil(|py| Python::run(py, "import foo; foo.add_one(6)", None, None))
Python::with_gil(|py| Python::run_bound(py, "import foo; foo.add_one(6)", None, None))
}
```
@ -321,7 +321,7 @@ fn main() -> PyResult<()> {
py_modules.set_item("foo", foo_module)?;
// Now we can import + run our python code
Python::run(py, "import foo; foo.add_one(6)", None, None)
Python::run_bound(py, "import foo; foo.add_one(6)", None, None)
})
}
```

View File

@ -147,8 +147,8 @@ mod test_anyhow {
let pyerr = PyErr::from(err);
Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run("raise err", None, Some(locals)).unwrap_err();
let locals = [("err", pyerr)].into_py_dict(py).as_borrowed();
let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err();
assert_eq!(pyerr.value(py).to_string(), expected_contents);
})
}
@ -164,8 +164,8 @@ mod test_anyhow {
let pyerr = PyErr::from(err);
Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run("raise err", None, Some(locals)).unwrap_err();
let locals = [("err", pyerr)].into_py_dict(py).as_borrowed();
let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err();
assert_eq!(pyerr.value(py).to_string(), expected_contents);
})
}

View File

@ -574,12 +574,15 @@ mod tests {
// tzdata there to make this work.
#[cfg(all(Py_3_9, not(target_os = "windows")))]
fn test_zoneinfo_is_not_fixed_offset() {
use crate::types::any::PyAnyMethods;
use crate::types::dict::PyDictMethods;
Python::with_gil(|py| {
let locals = crate::types::PyDict::new(py);
py.run(
let locals = crate::types::PyDict::new_bound(py);
py.run_bound(
"import zoneinfo; zi = zoneinfo.ZoneInfo('Europe/London')",
None,
Some(locals),
Some(&locals),
)
.unwrap();
let result: PyResult<FixedOffset> = locals.get_item("zi").unwrap().unwrap().extract();

View File

@ -152,8 +152,8 @@ mod tests {
let pyerr = PyErr::from(err);
Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run("raise err", None, Some(locals)).unwrap_err();
let locals = [("err", pyerr)].into_py_dict(py).as_borrowed();
let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err();
assert_eq!(pyerr.value(py).to_string(), expected_contents);
})
}
@ -169,8 +169,8 @@ mod tests {
let pyerr = PyErr::from(err);
Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run("raise err", None, Some(locals)).unwrap_err();
let locals = [("err", pyerr)].into_py_dict(py).as_borrowed();
let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err();
assert_eq!(pyerr.value(py).to_string(), expected_contents);
})
}

View File

@ -108,6 +108,8 @@ impl IntoPy<PyObject> for Decimal {
mod test_rust_decimal {
use super::*;
use crate::err::PyErr;
use crate::types::any::PyAnyMethods;
use crate::types::dict::PyDictMethods;
use crate::types::PyDict;
use rust_decimal::Decimal;
@ -121,16 +123,16 @@ mod test_rust_decimal {
Python::with_gil(|py| {
let rs_orig = $rs;
let rs_dec = rs_orig.into_py(py);
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("rs_dec", &rs_dec).unwrap();
// Checks if Rust Decimal -> Python Decimal conversion is correct
py.run(
py.run_bound(
&format!(
"import decimal\npy_dec = decimal.Decimal({})\nassert py_dec == rs_dec",
$py
),
None,
Some(locals),
Some(&locals),
)
.unwrap();
// Checks if Python Decimal -> Rust Decimal conversion is correct
@ -163,13 +165,13 @@ mod test_rust_decimal {
let num = Decimal::from_parts(lo, mid, high, negative, scale);
Python::with_gil(|py| {
let rs_dec = num.into_py(py);
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("rs_dec", &rs_dec).unwrap();
py.run(
py.run_bound(
&format!(
"import decimal\npy_dec = decimal.Decimal(\"{}\")\nassert py_dec == rs_dec",
num),
None, Some(locals)).unwrap();
None, Some(&locals)).unwrap();
let roundtripped: Decimal = rs_dec.extract(py).unwrap();
assert_eq!(num, roundtripped);
})
@ -189,11 +191,11 @@ mod test_rust_decimal {
#[test]
fn test_nan() {
Python::with_gil(|py| {
let locals = PyDict::new(py);
py.run(
let locals = PyDict::new_bound(py);
py.run_bound(
"import decimal\npy_dec = decimal.Decimal(\"NaN\")",
None,
Some(locals),
Some(&locals),
)
.unwrap();
let py_dec = locals.get_item("py_dec").unwrap().unwrap();
@ -205,11 +207,11 @@ mod test_rust_decimal {
#[test]
fn test_infinity() {
Python::with_gil(|py| {
let locals = PyDict::new(py);
py.run(
let locals = PyDict::new_bound(py);
py.run_bound(
"import decimal\npy_dec = decimal.Decimal(\"Infinity\")",
None,
Some(locals),
Some(&locals),
)
.unwrap();
let py_dec = locals.get_item("py_dec").unwrap().unwrap();

View File

@ -376,6 +376,9 @@ mod test_128bit_integers {
#[cfg(not(target_arch = "wasm32"))]
use crate::types::PyDict;
#[cfg(not(target_arch = "wasm32"))]
use crate::types::dict::PyDictMethods;
#[cfg(not(target_arch = "wasm32"))]
use proptest::prelude::*;
@ -385,9 +388,9 @@ mod test_128bit_integers {
fn test_i128_roundtrip(x: i128) {
Python::with_gil(|py| {
let x_py = x.into_py(py);
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("x_py", x_py.clone_ref(py)).unwrap();
py.run(&format!("assert x_py == {}", x), None, Some(locals)).unwrap();
py.run_bound(&format!("assert x_py == {}", x), None, Some(&locals)).unwrap();
let roundtripped: i128 = x_py.extract(py).unwrap();
assert_eq!(x, roundtripped);
})
@ -401,9 +404,9 @@ mod test_128bit_integers {
) {
Python::with_gil(|py| {
let x_py = x.into_py(py);
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("x_py", x_py.clone_ref(py)).unwrap();
py.run(&format!("assert x_py == {}", x), None, Some(locals)).unwrap();
py.run_bound(&format!("assert x_py == {}", x), None, Some(&locals)).unwrap();
let roundtripped: NonZeroI128 = x_py.extract(py).unwrap();
assert_eq!(x, roundtripped);
})
@ -416,9 +419,9 @@ mod test_128bit_integers {
fn test_u128_roundtrip(x: u128) {
Python::with_gil(|py| {
let x_py = x.into_py(py);
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("x_py", x_py.clone_ref(py)).unwrap();
py.run(&format!("assert x_py == {}", x), None, Some(locals)).unwrap();
py.run_bound(&format!("assert x_py == {}", x), None, Some(&locals)).unwrap();
let roundtripped: u128 = x_py.extract(py).unwrap();
assert_eq!(x, roundtripped);
})
@ -432,9 +435,9 @@ mod test_128bit_integers {
) {
Python::with_gil(|py| {
let x_py = x.into_py(py);
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("x_py", x_py.clone_ref(py)).unwrap();
py.run(&format!("assert x_py == {}", x), None, Some(locals)).unwrap();
py.run_bound(&format!("assert x_py == {}", x), None, Some(&locals)).unwrap();
let roundtripped: NonZeroU128 = x_py.extract(py).unwrap();
assert_eq!(x, roundtripped);
})

View File

@ -1030,7 +1030,7 @@ mod tests {
Python::with_gil(|py| {
let err = py
.run("raise Exception('banana')", None, None)
.run_bound("raise Exception('banana')", None, None)
.expect_err("raising should have given us an error");
let debug_str = format!("{:?}", err);
@ -1055,7 +1055,7 @@ mod tests {
fn err_display() {
Python::with_gil(|py| {
let err = py
.run("raise Exception('banana')", None, None)
.run_bound("raise Exception('banana')", None, None)
.expect_err("raising should have given us an error");
assert_eq!(err.to_string(), "Exception: banana");
});
@ -1102,12 +1102,12 @@ mod tests {
fn test_pyerr_cause() {
Python::with_gil(|py| {
let err = py
.run("raise Exception('banana')", None, None)
.run_bound("raise Exception('banana')", None, None)
.expect_err("raising should have given us an error");
assert!(err.cause(py).is_none());
let err = py
.run(
.run_bound(
"raise Exception('banana') from Exception('apple')",
None,
None,

View File

@ -165,18 +165,18 @@ macro_rules! import_exception {
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| -> PyResult<()> {
/// # let fun = wrap_pyfunction!(raise_myerror, py)?;
/// # let locals = pyo3::types::PyDict::new(py);
/// # let locals = pyo3::types::PyDict::new_bound(py);
/// # locals.set_item("MyError", py.get_type::<MyError>())?;
/// # locals.set_item("raise_myerror", fun)?;
/// #
/// # py.run(
/// # py.run_bound(
/// # "try:
/// # raise_myerror()
/// # except MyError as e:
/// # assert e.__doc__ == 'Some description.'
/// # assert str(e) == 'Some error happened.'",
/// # None,
/// # Some(locals),
/// # Some(&locals),
/// # )?;
/// #
/// # Ok(())
@ -338,7 +338,7 @@ use pyo3::prelude::*;
use pyo3::exceptions::Py", $name, ";
Python::with_gil(|py| {
let result: PyResult<()> = py.run(\"raise ", $name, "\", None, None);
let result: PyResult<()> = py.run_bound(\"raise ", $name, "\", None, None);
let error_type = match result {
Ok(_) => \"Not an error\",
@ -816,7 +816,7 @@ mod tests {
.map_err(|e| e.display(py))
.expect("could not import socket");
let d = PyDict::new(py);
let d = PyDict::new_bound(py);
d.set_item("socket", socket)
.map_err(|e| e.display(py))
.expect("could not setitem");
@ -825,7 +825,7 @@ mod tests {
.map_err(|e| e.display(py))
.expect("could not setitem");
py.run("assert isinstance(exc, socket.gaierror)", None, Some(d))
py.run_bound("assert isinstance(exc, socket.gaierror)", None, Some(&d))
.map_err(|e| e.display(py))
.expect("assertion failed");
});
@ -840,7 +840,7 @@ mod tests {
.map_err(|e| e.display(py))
.expect("could not import email");
let d = PyDict::new(py);
let d = PyDict::new_bound(py);
d.set_item("email", email)
.map_err(|e| e.display(py))
.expect("could not setitem");
@ -848,10 +848,10 @@ mod tests {
.map_err(|e| e.display(py))
.expect("could not setitem");
py.run(
py.run_bound(
"assert isinstance(exc, email.errors.MessageError)",
None,
Some(d),
Some(&d),
)
.map_err(|e| e.display(py))
.expect("assertion failed");
@ -871,14 +871,13 @@ mod tests {
.extract()
.unwrap();
assert_eq!(type_description, "<class 'mymodule.CustomError'>");
let ctx = ctx.as_gil_ref();
py.run(
py.run_bound(
"assert CustomError('oops').args == ('oops',)",
None,
Some(ctx),
Some(&ctx),
)
.unwrap();
py.run("assert CustomError.__doc__ is None", None, Some(ctx))
py.run_bound("assert CustomError.__doc__ is None", None, Some(&ctx))
.unwrap();
});
}
@ -914,15 +913,18 @@ mod tests {
.extract()
.unwrap();
assert_eq!(type_description, "<class 'mymodule.CustomError'>");
let ctx = ctx.as_gil_ref();
py.run(
py.run_bound(
"assert CustomError('oops').args == ('oops',)",
None,
Some(ctx),
Some(&ctx),
)
.unwrap();
py.run_bound(
"assert CustomError.__doc__ == 'Some docs'",
None,
Some(&ctx),
)
.unwrap();
py.run("assert CustomError.__doc__ == 'Some docs'", None, Some(ctx))
.unwrap();
});
}
@ -944,17 +946,16 @@ mod tests {
.extract()
.unwrap();
assert_eq!(type_description, "<class 'mymodule.CustomError'>");
let ctx = ctx.as_gil_ref();
py.run(
py.run_bound(
"assert CustomError('oops').args == ('oops',)",
None,
Some(ctx),
Some(&ctx),
)
.unwrap();
py.run(
py.run_bound(
"assert CustomError.__doc__ == 'Some more docs'",
None,
Some(ctx),
Some(&ctx),
)
.unwrap();
});
@ -964,7 +965,7 @@ mod tests {
fn native_exception_debug() {
Python::with_gil(|py| {
let exc = py
.run("raise Exception('banana')", None, None)
.run_bound("raise Exception('banana')", None, None)
.expect_err("raising should have given us an error")
.into_value(py)
.into_ref(py);
@ -979,7 +980,7 @@ mod tests {
fn native_exception_display() {
Python::with_gil(|py| {
let exc = py
.run("raise Exception('banana')", None, None)
.run_bound("raise Exception('banana')", None, None)
.expect_err("raising should have given us an error")
.into_value(py)
.into_ref(py);
@ -996,7 +997,7 @@ mod tests {
Python::with_gil(|py| {
let exc = py
.run(
.run_bound(
"raise Exception('banana') from TypeError('peach')",
None,
None,

View File

@ -20,12 +20,12 @@ fn test_datetime_fromtimestamp() {
PyDateTime_IMPORT();
py.from_owned_ptr(PyDateTime_FromTimestamp(args.as_ptr()))
};
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("dt", dt).unwrap();
py.run(
py.run_bound(
"import datetime; assert dt == datetime.datetime.fromtimestamp(100)",
None,
Some(locals),
Some(&locals),
)
.unwrap();
})
@ -41,12 +41,12 @@ fn test_date_fromtimestamp() {
PyDateTime_IMPORT();
py.from_owned_ptr(PyDate_FromTimestamp(args.as_ptr()))
};
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("dt", dt).unwrap();
py.run(
py.run_bound(
"import datetime; assert dt == datetime.date.fromtimestamp(100)",
None,
Some(locals),
Some(&locals),
)
.unwrap();
})
@ -61,12 +61,12 @@ fn test_utc_timezone() {
PyDateTime_IMPORT();
py.from_borrowed_ptr(PyDateTime_TimeZone_UTC())
};
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("utc_timezone", utc_timezone).unwrap();
py.run(
py.run_bound(
"import datetime; assert utc_timezone is datetime.timezone.utc",
None,
Some(locals),
Some(&locals),
)
.unwrap();
})

View File

@ -75,7 +75,7 @@ fn gil_is_acquired() -> bool {
///
/// # fn main() -> PyResult<()> {
/// pyo3::prepare_freethreaded_python();
/// Python::with_gil(|py| py.run("print('Hello World')", None, None))
/// Python::with_gil(|py| py.run_bound("print('Hello World')", None, None))
/// # }
/// ```
#[cfg(not(PyPy))]
@ -118,7 +118,7 @@ pub fn prepare_freethreaded_python() {
/// ```rust
/// unsafe {
/// pyo3::with_embedded_python_interpreter(|py| {
/// if let Err(e) = py.run("print('Hello World')", None, None) {
/// if let Err(e) = py.run_bound("print('Hello World')", None, None) {
/// // We must make sure to not return a `PyErr`!
/// e.print(py);
/// }

View File

@ -104,12 +104,13 @@ macro_rules! py_run_impl {
}};
($py:expr, *$dict:expr, $code:expr) => {{
use ::std::option::Option::*;
if let ::std::result::Result::Err(e) = $py.run($code, None, Some($dict)) {
use $crate::PyNativeType;
if let ::std::result::Result::Err(e) = $py.run_bound($code, None, Some(&$dict.as_borrowed())) {
e.print($py);
// So when this c api function the last line called printed the error to stderr,
// the output is only written into a buffer which is never flushed because we
// panic before flushing. This is where this hack comes into place
$py.run("import sys; sys.stderr.flush()", None, None)
$py.run_bound("import sys; sys.stderr.flush()", None, None)
.unwrap();
::std::panic!("{}", $code)
}

View File

@ -600,6 +600,27 @@ impl<'py> Python<'py> {
self.run_code(code, ffi::Py_eval_input, globals, locals)
}
/// Deprecated version of [`Python::run_bound`]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
since = "0.21.0",
note = "`Python::run` will be replaced by `Python::run_bound` in a future PyO3 version"
)
)]
pub fn run(
self,
code: &str,
globals: Option<&PyDict>,
locals: Option<&PyDict>,
) -> PyResult<()> {
self.run_bound(
code,
globals.map(PyNativeType::as_borrowed).as_deref(),
locals.map(PyNativeType::as_borrowed).as_deref(),
)
}
/// Executes one or more Python statements in the given context.
///
/// If `globals` is `None`, it defaults to Python module `__main__`.
@ -615,37 +636,32 @@ impl<'py> Python<'py> {
/// types::{PyBytes, PyDict},
/// };
/// Python::with_gil(|py| {
/// let locals = PyDict::new(py);
/// py.run(
/// let locals = PyDict::new_bound(py);
/// py.run_bound(
/// r#"
/// import base64
/// s = 'Hello Rust!'
/// ret = base64.b64encode(s.encode('utf-8'))
/// "#,
/// None,
/// Some(locals),
/// Some(&locals),
/// )
/// .unwrap();
/// let ret = locals.get_item("ret").unwrap().unwrap();
/// let b64: &PyBytes = ret.downcast().unwrap();
/// let b64 = ret.downcast::<PyBytes>().unwrap();
/// assert_eq!(b64.as_bytes(), b"SGVsbG8gUnVzdCE=");
/// });
/// ```
///
/// You can use [`py_run!`](macro.py_run.html) for a handy alternative of `run`
/// if you don't need `globals` and unwrapping is OK.
pub fn run(
pub fn run_bound(
self,
code: &str,
globals: Option<&PyDict>,
locals: Option<&PyDict>,
globals: Option<&Bound<'py, PyDict>>,
locals: Option<&Bound<'py, PyDict>>,
) -> PyResult<()> {
let res = self.run_code(
code,
ffi::Py_file_input,
globals.map(PyNativeType::as_borrowed).as_deref(),
locals.map(PyNativeType::as_borrowed).as_deref(),
);
let res = self.run_code(code, ffi::Py_file_input, globals, locals);
res.map(|obj| {
debug_assert!(obj.is_none());
})
@ -1235,9 +1251,11 @@ mod tests {
#[test]
fn test_py_run_inserts_globals() {
use crate::types::dict::PyDictMethods;
Python::with_gil(|py| {
let namespace = PyDict::new(py);
py.run("class Foo: pass", Some(namespace), Some(namespace))
let namespace = PyDict::new_bound(py);
py.run_bound("class Foo: pass", Some(&namespace), Some(&namespace))
.unwrap();
assert!(matches!(namespace.get_item("Foo"), Ok(Some(..))));
assert!(matches!(namespace.get_item("__builtins__"), Ok(Some(..))));

View File

@ -40,7 +40,8 @@ mod inner {
}};
// Case2: dict & no err_msg
($py:expr, *$dict:expr, $code:expr, $err:ident) => {{
let res = $py.run($code, None, Some($dict));
use pyo3::PyNativeType;
let res = $py.run_bound($code, None, Some(&$dict.as_borrowed()));
let err = res.expect_err(&format!("Did not raise {}", stringify!($err)));
if !err.matches($py, $py.get_type::<pyo3::exceptions::$err>()) {
panic!("Expected {} but got {:?}", stringify!($err), err)

View File

@ -197,10 +197,10 @@ impl PyByteArray {
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| -> PyResult<()> {
/// # let fun = wrap_pyfunction!(a_valid_function, py)?;
/// # let locals = pyo3::types::PyDict::new(py);
/// # let locals = pyo3::types::PyDict::new_bound(py);
/// # locals.set_item("a_valid_function", fun)?;
/// #
/// # py.run(
/// # py.run_bound(
/// # r#"b = bytearray(b"hello world")
/// # a_valid_function(b)
/// #
@ -209,7 +209,7 @@ impl PyByteArray {
/// # except RuntimeError as e:
/// # assert str(e) == 'input is not long enough'"#,
/// # None,
/// # Some(locals),
/// # Some(&locals),
/// # )?;
/// #
/// # Ok(())
@ -359,10 +359,10 @@ pub trait PyByteArrayMethods<'py> {
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| -> PyResult<()> {
/// # let fun = wrap_pyfunction!(a_valid_function, py)?;
/// # let locals = pyo3::types::PyDict::new(py);
/// # let locals = pyo3::types::PyDict::new_bound(py);
/// # locals.set_item("a_valid_function", fun)?;
/// #
/// # py.run(
/// # py.run_bound(
/// # r#"b = bytearray(b"hello world")
/// # a_valid_function(b)
/// #
@ -371,7 +371,7 @@ pub trait PyByteArrayMethods<'py> {
/// # except RuntimeError as e:
/// # assert str(e) == 'input is not long enough'"#,
/// # None,
/// # Some(locals),
/// # Some(&locals),
/// # )?;
/// #
/// # Ok(())

View File

@ -28,7 +28,7 @@ impl PyTraceback {
/// # let result: PyResult<()> =
/// Python::with_gil(|py| {
/// let err = py
/// .run("raise Exception('banana')", None, None)
/// .run_bound("raise Exception('banana')", None, None)
/// .expect_err("raise will create a Python error");
///
/// let traceback = err.traceback_bound(py).expect("raised exception will have a traceback");
@ -71,7 +71,7 @@ pub trait PyTracebackMethods<'py> {
/// # let result: PyResult<()> =
/// Python::with_gil(|py| {
/// let err = py
/// .run("raise Exception('banana')", None, None)
/// .run_bound("raise Exception('banana')", None, None)
/// .expect_err("raise will create a Python error");
///
/// let traceback = err.traceback_bound(py).expect("raised exception will have a traceback");
@ -121,7 +121,7 @@ mod tests {
fn format_traceback() {
Python::with_gil(|py| {
let err = py
.run("raise Exception('banana')", None, None)
.run_bound("raise Exception('banana')", None, None)
.expect_err("raising should have given us an error");
assert_eq!(
@ -134,9 +134,9 @@ mod tests {
#[test]
fn test_err_from_value() {
Python::with_gil(|py| {
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
// Produce an error from python so that it has a traceback
py.run(
py.run_bound(
r"
try:
raise ValueError('raised exception')
@ -144,10 +144,10 @@ except Exception as e:
err = e
",
None,
Some(locals),
Some(&locals),
)
.unwrap();
let err = PyErr::from_value(locals.get_item("err").unwrap().unwrap());
let err = PyErr::from_value(locals.get_item("err").unwrap().unwrap().into_gil_ref());
let traceback = err.value(py).getattr("__traceback__").unwrap();
assert!(err.traceback_bound(py).unwrap().is(traceback));
})
@ -156,15 +156,15 @@ except Exception as e:
#[test]
fn test_err_into_py() {
Python::with_gil(|py| {
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
// Produce an error from python so that it has a traceback
py.run(
py.run_bound(
r"
def f():
raise ValueError('raised exception')
",
None,
Some(locals),
Some(&locals),
)
.unwrap();
let f = locals.get_item("f").unwrap().unwrap();

View File

@ -25,6 +25,7 @@ fn test_anyhow_py_function_ok_result() {
#[test]
fn test_anyhow_py_function_err_result() {
use pyo3::prelude::PyDictMethods;
use pyo3::{pyfunction, types::PyDict, wrap_pyfunction, Python};
#[pyfunction]
@ -34,15 +35,15 @@ fn test_anyhow_py_function_err_result() {
Python::with_gil(|py| {
let func = wrap_pyfunction!(produce_err_result)(py).unwrap();
let locals = PyDict::new(py);
let locals = PyDict::new_bound(py);
locals.set_item("func", func).unwrap();
py.run(
py.run_bound(
r#"
func()
"#,
None,
Some(locals),
Some(&locals),
)
.unwrap_err();
});

View File

@ -18,7 +18,7 @@ fn test_module_append_to_inittab() {
use pyo3::append_to_inittab;
append_to_inittab!(module_with_functions);
Python::with_gil(|py| {
py.run(
py.run_bound(
r#"
import module_with_functions
assert module_with_functions.foo() == 123

View File

@ -169,9 +169,12 @@ c = Class()
assert c.from_rust is False
"#
);
let globals = PyModule::import(py, "__main__").unwrap().dict();
let globals = PyModule::import(py, "__main__")
.unwrap()
.dict()
.as_borrowed();
globals.set_item("SuperClass", super_cls).unwrap();
py.run(source, Some(globals), None)
py.run_bound(source, Some(&globals), None)
.map_err(|e| e.display(py))
.unwrap();
});

View File

@ -127,12 +127,12 @@ fn cancelled_coroutine() {
await task
asyncio.run(main())
"#;
let globals = gil.import("__main__").unwrap().dict();
let globals = gil.import("__main__").unwrap().dict().as_borrowed();
globals.set_item("sleep", sleep).unwrap();
let err = gil
.run(
.run_bound(
&pyo3::unindent::unindent(&handle_windows(test)),
Some(globals),
Some(&globals),
None,
)
.unwrap_err();
@ -166,13 +166,13 @@ fn coroutine_cancel_handle() {
return await task
assert asyncio.run(main()) == 0
"#;
let globals = gil.import("__main__").unwrap().dict();
let globals = gil.import("__main__").unwrap().dict().as_borrowed();
globals
.set_item("cancellable_sleep", cancellable_sleep)
.unwrap();
gil.run(
gil.run_bound(
&pyo3::unindent::unindent(&handle_windows(test)),
Some(globals),
Some(&globals),
None,
)
.unwrap();
@ -198,11 +198,11 @@ fn coroutine_is_cancelled() {
await task
asyncio.run(main())
"#;
let globals = gil.import("__main__").unwrap().dict();
let globals = gil.import("__main__").unwrap().dict().as_borrowed();
globals.set_item("sleep_loop", sleep_loop).unwrap();
gil.run(
gil.run_bound(
&pyo3::unindent::unindent(&handle_windows(test)),
Some(globals),
Some(&globals),
None,
)
.unwrap();

View File

@ -12,14 +12,16 @@ fn _get_subclasses<'py>(
// Import the class from Python and create some subclasses
let datetime = py.import("datetime")?;
let locals = [(py_type, datetime.getattr(py_type)?)].into_py_dict(py);
let locals = [(py_type, datetime.getattr(py_type)?)]
.into_py_dict(py)
.as_borrowed();
let make_subclass_py = format!("class Subklass({}):\n pass", py_type);
let make_sub_subclass_py = "class SubSubklass(Subklass):\n pass";
py.run(&make_subclass_py, None, Some(locals))?;
py.run(make_sub_subclass_py, None, Some(locals))?;
py.run_bound(&make_subclass_py, None, Some(&locals))?;
py.run_bound(make_sub_subclass_py, None, Some(&locals))?;
let locals = locals.as_borrowed();
// Construct an instance of the base class

View File

@ -117,7 +117,7 @@ fn gc_integration() {
});
Python::with_gil(|py| {
py.run("import gc; gc.collect()", None, None).unwrap();
py.run_bound("import gc; gc.collect()", None, None).unwrap();
assert!(drop_called.load(Ordering::Relaxed));
});
}
@ -156,7 +156,7 @@ fn gc_null_traversal() {
obj.borrow_mut(py).cycle = Some(obj.clone_ref(py));
// the object doesn't have to be cleaned up, it just needs to be traversed.
py.run("import gc; gc.collect()", None, None).unwrap();
py.run_bound("import gc; gc.collect()", None, None).unwrap();
});
}
@ -469,7 +469,7 @@ fn drop_during_traversal_with_gil() {
// (but not too many) collections to get `inst` actually dropped.
for _ in 0..10 {
Python::with_gil(|py| {
py.run("import gc; gc.collect()", None, None).unwrap();
py.run_bound("import gc; gc.collect()", None, None).unwrap();
});
}
assert!(drop_called.load(Ordering::Relaxed));
@ -502,7 +502,7 @@ fn drop_during_traversal_without_gil() {
// (but not too many) collections to get `inst` actually dropped.
for _ in 0..10 {
Python::with_gil(|py| {
py.run("import gc; gc.collect()", None, None).unwrap();
py.run_bound("import gc; gc.collect()", None, None).unwrap();
});
}
assert!(drop_called.load(Ordering::Relaxed));

View File

@ -20,12 +20,14 @@ struct SubclassAble {}
#[test]
fn subclass() {
Python::with_gil(|py| {
let d = [("SubclassAble", py.get_type::<SubclassAble>())].into_py_dict(py);
let d = [("SubclassAble", py.get_type::<SubclassAble>())]
.into_py_dict(py)
.as_borrowed();
py.run(
py.run_bound(
"class A(SubclassAble): pass\nassert issubclass(A, SubclassAble)",
None,
Some(d),
Some(&d),
)
.map_err(|e| e.display(py))
.unwrap();
@ -97,9 +99,13 @@ fn call_base_and_sub_methods() {
fn mutation_fails() {
Python::with_gil(|py| {
let obj = PyCell::new(py, SubClass::new()).unwrap();
let global = Some([("obj", obj)].into_py_dict(py));
let global = [("obj", obj)].into_py_dict(py).as_borrowed();
let e = py
.run("obj.base_set(lambda: obj.sub_set_and_ret(1))", global, None)
.run_bound(
"obj.base_set(lambda: obj.sub_set_and_ret(1))",
Some(&global),
None,
)
.unwrap_err();
assert_eq!(&e.to_string(), "RuntimeError: Already borrowed");
});
@ -271,11 +277,11 @@ mod inheriting_native_type {
fn custom_exception() {
Python::with_gil(|py| {
let cls = py.get_type::<CustomException>();
let dict = [("cls", cls)].into_py_dict(py);
let res = py.run(
let dict = [("cls", cls)].into_py_dict(py).as_borrowed();
let res = py.run_bound(
"e = cls('hello'); assert str(e) == 'hello'; assert e.context == 'Hello :)'; raise e",
None,
Some(dict)
Some(&dict)
);
let err = res.unwrap_err();
assert!(err.matches(py, cls), "{}", err);

View File

@ -687,9 +687,12 @@ if sys.platform == "win32" and sys.version_info >= (3, 8, 0):
asyncio.run(main())
"#;
let globals = PyModule::import(py, "__main__").unwrap().dict();
let globals = PyModule::import(py, "__main__")
.unwrap()
.dict()
.as_borrowed();
globals.set_item("Once", once).unwrap();
py.run(source, Some(globals), None)
py.run_bound(source, Some(&globals), None)
.map_err(|e| e.display(py))
.unwrap();
});
@ -741,12 +744,15 @@ if sys.platform == "win32" and sys.version_info >= (3, 8, 0):
asyncio.run(main())
"#;
let globals = PyModule::import(py, "__main__").unwrap().dict();
let globals = PyModule::import(py, "__main__")
.unwrap()
.dict()
.as_borrowed();
globals.set_item("Once", once).unwrap();
globals
.set_item("AsyncIterator", py.get_type::<AsyncIterator>())
.unwrap();
py.run(source, Some(globals), None)
py.run_bound(source, Some(&globals), None)
.map_err(|e| e.display(py))
.unwrap();
});
@ -813,9 +819,12 @@ del c.counter
assert c.counter.count == 1
"#
);
let globals = PyModule::import(py, "__main__").unwrap().dict();
let globals = PyModule::import(py, "__main__")
.unwrap()
.dict()
.as_borrowed();
globals.set_item("Counter", counter).unwrap();
py.run(source, Some(globals), None)
py.run_bound(source, Some(&globals), None)
.map_err(|e| e.display(py))
.unwrap();
});