From 4d423b0c67e34f3e8820aefc76cb69805f8d1522 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Mon, 5 Feb 2024 19:44:00 +0100 Subject: [PATCH] port `Python::run` to `Bound` API --- guide/src/class/numeric.md | 4 +-- guide/src/module.md | 4 +-- guide/src/python_from_rust.md | 4 +-- src/conversions/anyhow.rs | 8 ++--- src/conversions/chrono.rs | 9 ++++-- src/conversions/eyre.rs | 8 ++--- src/conversions/rust_decimal.rs | 26 ++++++++-------- src/conversions/std/num.rs | 19 +++++++----- src/err/mod.rs | 8 ++--- src/exceptions.rs | 53 +++++++++++++++++---------------- src/ffi/tests.rs | 18 +++++------ src/gil.rs | 4 +-- src/macros.rs | 5 ++-- src/marker.rs | 48 +++++++++++++++++++---------- src/tests/common.rs | 3 +- src/types/bytearray.rs | 12 ++++---- src/types/traceback.rs | 20 ++++++------- tests/test_anyhow.rs | 7 +++-- tests/test_append_to_inittab.rs | 2 +- tests/test_class_new.rs | 7 +++-- tests/test_coroutine.rs | 18 +++++------ tests/test_datetime.rs | 8 +++-- tests/test_gc.rs | 8 ++--- tests/test_inheritance.rs | 22 +++++++++----- tests/test_proto_methods.rs | 21 +++++++++---- 25 files changed, 198 insertions(+), 148 deletions(-) diff --git a/guide/src/class/numeric.md b/guide/src/class/numeric.md index 6f2e6e18..c6b6a65b 100644 --- a/guide/src/class/numeric.md +++ b/guide/src/class/numeric.md @@ -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(()) # }) # } diff --git a/guide/src/module.md b/guide/src/module.md index 9e52ab93..5d224de4 100644 --- a/guide/src/module.md +++ b/guide/src/module.md @@ -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(); # }) ``` diff --git a/guide/src/python_from_rust.md b/guide/src/python_from_rust.md index 2f3be53a..753ce620 100644 --- a/guide/src/python_from_rust.md +++ b/guide/src/python_from_rust.md @@ -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) }) } ``` diff --git a/src/conversions/anyhow.rs b/src/conversions/anyhow.rs index 3b5aa053..809b2aa2 100644 --- a/src/conversions/anyhow.rs +++ b/src/conversions/anyhow.rs @@ -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); }) } diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index 83f9830b..069a137f 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -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 = locals.get_item("zi").unwrap().unwrap().extract(); diff --git a/src/conversions/eyre.rs b/src/conversions/eyre.rs index b0559ad1..7f029cf6 100644 --- a/src/conversions/eyre.rs +++ b/src/conversions/eyre.rs @@ -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); }) } diff --git a/src/conversions/rust_decimal.rs b/src/conversions/rust_decimal.rs index 2e38e780..e829e883 100644 --- a/src/conversions/rust_decimal.rs +++ b/src/conversions/rust_decimal.rs @@ -108,6 +108,8 @@ impl IntoPy 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(); diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index 2d20915d..75c2e16b 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -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); }) diff --git a/src/err/mod.rs b/src/err/mod.rs index 85685456..e53a9657 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -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, diff --git a/src/exceptions.rs b/src/exceptions.rs index daea55e5..10121b8a 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -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::())?; /// # 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, ""); - 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, ""); - 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, ""); - 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, diff --git a/src/ffi/tests.rs b/src/ffi/tests.rs index fc10bf05..0735e456 100644 --- a/src/ffi/tests.rs +++ b/src/ffi/tests.rs @@ -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(); }) diff --git a/src/gil.rs b/src/gil.rs index 61d69ed9..379dab4b 100644 --- a/src/gil.rs +++ b/src/gil.rs @@ -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); /// } diff --git a/src/macros.rs b/src/macros.rs index 41de9079..79e8ea58 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -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) } diff --git a/src/marker.rs b/src/marker.rs index 1802d858..121cfe68 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -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::().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(..)))); diff --git a/src/tests/common.rs b/src/tests/common.rs index efab3ccb..e424c1ca 100644 --- a/src/tests/common.rs +++ b/src/tests/common.rs @@ -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::()) { panic!("Expected {} but got {:?}", stringify!($err), err) diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 6303a87d..7f0fdf9e 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -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(()) diff --git a/src/types/traceback.rs b/src/types/traceback.rs index 84ecda74..3608772f 100644 --- a/src/types/traceback.rs +++ b/src/types/traceback.rs @@ -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(); diff --git a/tests/test_anyhow.rs b/tests/test_anyhow.rs index f0df4dcc..1807cfe9 100644 --- a/tests/test_anyhow.rs +++ b/tests/test_anyhow.rs @@ -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(); }); diff --git a/tests/test_append_to_inittab.rs b/tests/test_append_to_inittab.rs index e0a57da1..00cccdbb 100644 --- a/tests/test_append_to_inittab.rs +++ b/tests/test_append_to_inittab.rs @@ -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 diff --git a/tests/test_class_new.rs b/tests/test_class_new.rs index 8cb42686..8084be05 100644 --- a/tests/test_class_new.rs +++ b/tests/test_class_new.rs @@ -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(); }); diff --git a/tests/test_coroutine.rs b/tests/test_coroutine.rs index 206c35da..d9672cd6 100644 --- a/tests/test_coroutine.rs +++ b/tests/test_coroutine.rs @@ -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(); diff --git a/tests/test_datetime.rs b/tests/test_datetime.rs index bfde37d3..d1efd1ef 100644 --- a/tests/test_datetime.rs +++ b/tests/test_datetime.rs @@ -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 diff --git a/tests/test_gc.rs b/tests/test_gc.rs index 43cdb1b4..7ed39436 100644 --- a/tests/test_gc.rs +++ b/tests/test_gc.rs @@ -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)); diff --git a/tests/test_inheritance.rs b/tests/test_inheritance.rs index 16f87df9..4b024ed7 100644 --- a/tests/test_inheritance.rs +++ b/tests/test_inheritance.rs @@ -20,12 +20,14 @@ struct SubclassAble {} #[test] fn subclass() { Python::with_gil(|py| { - let d = [("SubclassAble", py.get_type::())].into_py_dict(py); + let d = [("SubclassAble", py.get_type::())] + .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::(); - 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); diff --git a/tests/test_proto_methods.rs b/tests/test_proto_methods.rs index 50dd99ce..b1fe7548 100644 --- a/tests/test_proto_methods.rs +++ b/tests/test_proto_methods.rs @@ -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::()) .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(); });