From 0c12d9137fe73fbe17633d8699bb94964a420e8e Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Wed, 14 Feb 2024 01:24:37 +0100 Subject: [PATCH] port `Python::import` to `Bound` API (#3832) * port `Python::import` to `Bound` API * tidy up imports in tests/test_datetime_import.rs --------- Co-authored-by: David Hewitt --- README.md | 4 +-- guide/src/python_from_rust.md | 4 +-- src/buffer.rs | 7 ++--- src/conversions/chrono.rs | 30 ++++++++++----------- src/conversions/chrono_tz.rs | 13 +++++---- src/conversions/rust_decimal.rs | 2 +- src/conversions/std/time.rs | 43 ++++++++++++++++++------------ src/coroutine/waker.rs | 3 ++- src/err/mod.rs | 3 ++- src/exceptions.rs | 7 ++--- src/gil.rs | 2 +- src/impl_/pymodule.rs | 8 +++--- src/instance.rs | 4 +-- src/lib.rs | 4 +-- src/marker.rs | 21 ++++++++++++++- src/sync.rs | 11 +++++--- src/tests/common.rs | 10 +++---- src/types/any.rs | 32 +++++++++++----------- src/types/traceback.rs | 9 ++++--- tests/test_class_attributes.rs | 16 +++++------ tests/test_coroutine.rs | 6 ++--- tests/test_datetime.rs | 2 +- tests/test_datetime_import.rs | 4 +-- tests/test_various.rs | 2 +- tests/ui/invalid_intern_arg.rs | 2 +- tests/ui/invalid_intern_arg.stderr | 12 ++++----- 26 files changed, 153 insertions(+), 108 deletions(-) diff --git a/README.md b/README.md index 64aa3e9e..21e09157 100644 --- a/README.md +++ b/README.md @@ -149,10 +149,10 @@ use pyo3::types::IntoPyDict; fn main() -> PyResult<()> { Python::with_gil(|py| { - let sys = py.import("sys")?; + let sys = py.import_bound("sys")?; let version: String = sys.getattr("version")?.extract()?; - let locals = [("os", py.import("os")?)].into_py_dict_bound(py); + let locals = [("os", py.import_bound("os")?)].into_py_dict_bound(py); let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'"; let user: String = py.eval_bound(code, None, Some(&locals))?.extract()?; diff --git a/guide/src/python_from_rust.md b/guide/src/python_from_rust.md index b53b0309..1ac1a7c2 100644 --- a/guide/src/python_from_rust.md +++ b/guide/src/python_from_rust.md @@ -414,7 +414,7 @@ fn main() -> PyResult<()> { let path = Path::new("/usr/share/python_app"); let py_app = fs::read_to_string(path.join("app.py"))?; let from_python = Python::with_gil(|py| -> PyResult> { - let syspath: &PyList = py.import("sys")?.getattr("path")?.downcast()?; + let syspath = py.import_bound("sys")?.getattr("path")?.downcast_into::()?; syspath.insert(0, &path)?; let app: Py = PyModule::from_code(py, &py_app, "", "")? .getattr("run")? @@ -498,7 +498,7 @@ use pyo3::prelude::*; # fn main() -> PyResult<()> { Python::with_gil(|py| -> PyResult<()> { - let signal = py.import("signal")?; + let signal = py.import_bound("signal")?; // Set SIGINT to have the default action signal .getattr("signal")? diff --git a/src/buffer.rs b/src/buffer.rs index 7360ef67..2e9afbca 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -689,6 +689,7 @@ impl_element!(f64, Float); mod tests { use super::PyBuffer; use crate::ffi; + use crate::types::any::PyAnyMethods; use crate::Python; #[test] @@ -890,11 +891,11 @@ mod tests { fn test_array_buffer() { Python::with_gil(|py| { let array = py - .import("array") + .import_bound("array") .unwrap() .call_method("array", ("f", (1.0, 1.5, 2.0, 2.5)), None) .unwrap(); - let buffer = PyBuffer::get(array).unwrap(); + let buffer = PyBuffer::get(array.as_gil_ref()).unwrap(); assert_eq!(buffer.dimensions(), 1); assert_eq!(buffer.item_count(), 4); assert_eq!(buffer.format().to_str().unwrap(), "f"); @@ -924,7 +925,7 @@ mod tests { assert_eq!(buffer.to_vec(py).unwrap(), [10.0, 11.0, 12.0, 13.0]); // F-contiguous fns - let buffer = PyBuffer::get(array).unwrap(); + let buffer = PyBuffer::get(array.as_gil_ref()).unwrap(); let slice = buffer.as_fortran_slice(py).unwrap(); assert_eq!(slice.len(), 4); assert_eq!(slice[1].get(), 11.0); diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index 80a83b23..421a7aec 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -540,15 +540,15 @@ impl DatetimeTypes { static TYPES: GILOnceCell = GILOnceCell::new(); TYPES .get_or_try_init(py, || { - let datetime = py.import("datetime")?; + let datetime = py.import_bound("datetime")?; let timezone = datetime.getattr("timezone")?; Ok::<_, PyErr>(Self { date: datetime.getattr("date")?.into(), datetime: datetime.getattr("datetime")?.into(), time: datetime.getattr("time")?.into(), timedelta: datetime.getattr("timedelta")?.into(), - timezone: timezone.into(), timezone_utc: timezone.getattr("utc")?.into(), + timezone: timezone.into(), tzinfo: datetime.getattr("tzinfo")?.into(), }) }) @@ -683,7 +683,7 @@ mod tests { let delta = delta.to_object(py); let py_delta = new_py_datetime_ob(py, "timedelta", (py_days, py_seconds, py_ms)); assert!( - delta.as_ref(py).eq(py_delta).unwrap(), + delta.bind(py).eq(&py_delta).unwrap(), "{}: {} != {}", name, delta, @@ -779,7 +779,7 @@ mod tests { .to_object(py); let py_date = new_py_datetime_ob(py, "date", (year, month, day)); assert_eq!( - date.as_ref(py).compare(py_date).unwrap(), + date.bind(py).compare(&py_date).unwrap(), Ordering::Equal, "{}: {} != {}", name, @@ -838,7 +838,7 @@ mod tests { ), ); assert_eq!( - datetime.as_ref(py).compare(py_datetime).unwrap(), + datetime.bind(py).compare(&py_datetime).unwrap(), Ordering::Equal, "{}: {} != {}", name, @@ -880,7 +880,7 @@ mod tests { (year, month, day, hour, minute, second, py_ms, py_tz), ); assert_eq!( - datetime.as_ref(py).compare(py_datetime).unwrap(), + datetime.bind(py).compare(&py_datetime).unwrap(), Ordering::Equal, "{}: {} != {}", name, @@ -1005,7 +1005,7 @@ mod tests { Python::with_gil(|py| { let utc = Utc.to_object(py); let py_utc = python_utc(py); - assert!(utc.as_ref(py).is(py_utc)); + assert!(utc.bind(py).is(&py_utc)); }) } @@ -1036,7 +1036,7 @@ mod tests { .to_object(py); let py_time = new_py_datetime_ob(py, "time", (hour, minute, second, py_ms)); assert!( - time.as_ref(py).eq(py_time).unwrap(), + time.bind(py).eq(&py_time).unwrap(), "{}: {} != {}", name, time, @@ -1071,12 +1071,12 @@ mod tests { }) } - fn new_py_datetime_ob<'a>( - py: Python<'a>, + fn new_py_datetime_ob<'py>( + py: Python<'py>, name: &str, args: impl IntoPy>, - ) -> &'a PyAny { - py.import("datetime") + ) -> Bound<'py, PyAny> { + py.import_bound("datetime") .unwrap() .getattr(name) .unwrap() @@ -1084,8 +1084,8 @@ mod tests { .unwrap() } - fn python_utc(py: Python<'_>) -> &PyAny { - py.import("datetime") + fn python_utc(py: Python<'_>) -> Bound<'_, PyAny> { + py.import_bound("datetime") .unwrap() .getattr("timezone") .unwrap() @@ -1108,7 +1108,7 @@ 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_bound(py); + let globals = [("datetime", py.import_bound("datetime").unwrap())].into_py_dict_bound(py); let code = format!("datetime.datetime.fromtimestamp({}).replace(tzinfo=datetime.timezone(datetime.timedelta(seconds={})))", timestamp, timedelta); let t = py.eval_bound(&code, Some(&globals), None).unwrap(); diff --git a/src/conversions/chrono_tz.rs b/src/conversions/chrono_tz.rs index 791be15c..b4d0e7ed 100644 --- a/src/conversions/chrono_tz.rs +++ b/src/conversions/chrono_tz.rs @@ -89,8 +89,8 @@ mod tests { #[test] fn test_topyobject() { Python::with_gil(|py| { - let assert_eq = |l: PyObject, r: &PyAny| { - assert!(l.as_ref(py).eq(r).unwrap()); + let assert_eq = |l: PyObject, r: Bound<'_, PyAny>| { + assert!(l.bind(py).eq(r).unwrap()); }; assert_eq( @@ -105,11 +105,14 @@ mod tests { }); } - fn new_zoneinfo<'a>(py: Python<'a>, name: &str) -> &'a PyAny { + fn new_zoneinfo<'py>(py: Python<'py>, name: &str) -> Bound<'py, PyAny> { zoneinfo_class(py).call1((name,)).unwrap() } - fn zoneinfo_class(py: Python<'_>) -> &PyAny { - py.import("zoneinfo").unwrap().getattr("ZoneInfo").unwrap() + fn zoneinfo_class(py: Python<'_>) -> Bound<'_, PyAny> { + py.import_bound("zoneinfo") + .unwrap() + .getattr("ZoneInfo") + .unwrap() } } diff --git a/src/conversions/rust_decimal.rs b/src/conversions/rust_decimal.rs index e829e883..1d0f6414 100644 --- a/src/conversions/rust_decimal.rs +++ b/src/conversions/rust_decimal.rs @@ -77,7 +77,7 @@ static DECIMAL_CLS: GILOnceCell> = GILOnceCell::new(); fn get_decimal_cls(py: Python<'_>) -> PyResult<&PyType> { DECIMAL_CLS .get_or_try_init(py, || { - py.import(intern!(py, "decimal"))? + py.import_bound(intern!(py, "decimal"))? .getattr(intern!(py, "Decimal"))? .extract() }) diff --git a/src/conversions/std/time.rs b/src/conversions/std/time.rs index 4e6009e3..89d61e69 100755 --- a/src/conversions/std/time.rs +++ b/src/conversions/std/time.rs @@ -146,7 +146,7 @@ fn unix_epoch_py(py: Python<'_>) -> &PyObject { } #[cfg(Py_LIMITED_API)] { - let datetime = py.import("datetime")?; + let datetime = py.import_bound("datetime")?; let utc = datetime.getattr("timezone")?.getattr("utc")?; Ok::<_, PyErr>( datetime @@ -216,8 +216,8 @@ mod tests { #[test] fn test_duration_topyobject() { Python::with_gil(|py| { - let assert_eq = |l: PyObject, r: &PyAny| { - assert!(l.as_ref(py).eq(r).unwrap()); + let assert_eq = |l: PyObject, r: Bound<'_, PyAny>| { + assert!(l.bind(py).eq(r).unwrap()); }; assert_eq( @@ -300,8 +300,8 @@ mod tests { #[test] fn test_time_topyobject() { Python::with_gil(|py| { - let assert_eq = |l: PyObject, r: &PyAny| { - assert!(l.as_ref(py).eq(r).unwrap()); + let assert_eq = |l: PyObject, r: Bound<'_, PyAny>| { + assert!(l.bind(py).eq(r).unwrap()); }; assert_eq( @@ -331,7 +331,7 @@ mod tests { minute: u8, second: u8, microsecond: u32, - ) -> &PyAny { + ) -> Bound<'_, PyAny> { datetime_class(py) .call1(( year, @@ -346,13 +346,11 @@ mod tests { .unwrap() } - fn max_datetime(py: Python<'_>) -> &PyAny { + fn max_datetime(py: Python<'_>) -> Bound<'_, PyAny> { let naive_max = datetime_class(py).getattr("max").unwrap(); let kargs = PyDict::new_bound(py); kargs.set_item("tzinfo", tz_utc(py)).unwrap(); - naive_max - .call_method("replace", (), Some(kargs.as_gil_ref())) - .unwrap() + naive_max.call_method("replace", (), Some(&kargs)).unwrap() } #[test] @@ -365,8 +363,8 @@ mod tests { }) } - fn tz_utc(py: Python<'_>) -> &PyAny { - py.import("datetime") + fn tz_utc(py: Python<'_>) -> Bound<'_, PyAny> { + py.import_bound("datetime") .unwrap() .getattr("timezone") .unwrap() @@ -374,17 +372,28 @@ mod tests { .unwrap() } - fn new_timedelta(py: Python<'_>, days: i32, seconds: i32, microseconds: i32) -> &PyAny { + fn new_timedelta( + py: Python<'_>, + days: i32, + seconds: i32, + microseconds: i32, + ) -> Bound<'_, PyAny> { timedelta_class(py) .call1((days, seconds, microseconds)) .unwrap() } - fn datetime_class(py: Python<'_>) -> &PyAny { - py.import("datetime").unwrap().getattr("datetime").unwrap() + fn datetime_class(py: Python<'_>) -> Bound<'_, PyAny> { + py.import_bound("datetime") + .unwrap() + .getattr("datetime") + .unwrap() } - fn timedelta_class(py: Python<'_>) -> &PyAny { - py.import("datetime").unwrap().getattr("timedelta").unwrap() + fn timedelta_class(py: Python<'_>) -> Bound<'_, PyAny> { + py.import_bound("datetime") + .unwrap() + .getattr("timedelta") + .unwrap() } } diff --git a/src/coroutine/waker.rs b/src/coroutine/waker.rs index 8a1166ce..c4665489 100644 --- a/src/coroutine/waker.rs +++ b/src/coroutine/waker.rs @@ -1,4 +1,5 @@ use crate::sync::GILOnceCell; +use crate::types::any::PyAnyMethods; use crate::types::PyCFunction; use crate::{intern, wrap_pyfunction, Py, PyAny, PyObject, PyResult, Python}; use pyo3_macros::pyfunction; @@ -56,7 +57,7 @@ impl LoopAndFuture { fn new(py: Python<'_>) -> PyResult { static GET_RUNNING_LOOP: GILOnceCell = GILOnceCell::new(); let import = || -> PyResult<_> { - let module = py.import("asyncio")?; + let module = py.import_bound("asyncio")?; Ok(module.getattr("get_running_loop")?.into()) }; let event_loop = GET_RUNNING_LOOP.get_or_try_init(py, import)?.call0(py)?; diff --git a/src/err/mod.rs b/src/err/mod.rs index 31385f4c..5c2631b9 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -974,6 +974,7 @@ impl_signed_integer!(isize); mod tests { use super::PyErrState; use crate::exceptions::{self, PyTypeError, PyValueError}; + use crate::types::any::PyAnyMethods; use crate::{PyErr, PyTypeInfo, Python}; #[test] @@ -1174,7 +1175,7 @@ mod tests { let cls = py.get_type::(); // Reset warning filter to default state - let warnings = py.import("warnings").unwrap(); + let warnings = py.import_bound("warnings").unwrap(); warnings.call_method0("resetwarnings").unwrap(); // First, test the warning is emitted diff --git a/src/exceptions.rs b/src/exceptions.rs index 7e7dc8ee..245c3bbd 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -101,13 +101,14 @@ macro_rules! import_exception { fn type_object_raw(py: $crate::Python<'_>) -> *mut $crate::ffi::PyTypeObject { use $crate::sync::GILOnceCell; use $crate::prelude::PyTracebackMethods; + use $crate::prelude::PyAnyMethods; static TYPE_OBJECT: GILOnceCell<$crate::Py<$crate::types::PyType>> = GILOnceCell::new(); TYPE_OBJECT .get_or_init(py, || { let imp = py - .import(stringify!($module)) + .import_bound(stringify!($module)) .unwrap_or_else(|err| { let traceback = err .traceback_bound(py) @@ -812,7 +813,7 @@ mod tests { Python::with_gil(|py| { let err: PyErr = gaierror::new_err(()); let socket = py - .import("socket") + .import_bound("socket") .map_err(|e| e.display(py)) .expect("could not import socket"); @@ -836,7 +837,7 @@ mod tests { Python::with_gil(|py| { let err: PyErr = MessageError::new_err(()); let email = py - .import("email") + .import_bound("email") .map_err(|e| e.display(py)) .expect("could not import email"); diff --git a/src/gil.rs b/src/gil.rs index 379dab4b..08b1b3f7 100644 --- a/src/gil.rs +++ b/src/gil.rs @@ -143,7 +143,7 @@ where // Import the threading module - this ensures that it will associate this thread as the "main" // thread, which is important to avoid an `AssertionError` at finalization. - pool.python().import("threading").unwrap(); + pool.python().import_bound("threading").unwrap(); // Execute the closure. let result = f(pool.python()); diff --git a/src/impl_/pymodule.rs b/src/impl_/pymodule.rs index 0fe5c384..ff722855 100644 --- a/src/impl_/pymodule.rs +++ b/src/impl_/pymodule.rs @@ -67,13 +67,14 @@ impl ModuleDef { pub fn make_module(&'static self, py: Python<'_>) -> PyResult> { #[cfg(all(PyPy, not(Py_3_8)))] { + use crate::types::any::PyAnyMethods; const PYPY_GOOD_VERSION: [u8; 3] = [7, 3, 8]; let version = py - .import("sys")? + .import_bound("sys")? .getattr("implementation")? .getattr("version")?; if version.lt(crate::types::PyTuple::new_bound(py, PYPY_GOOD_VERSION))? { - let warn = py.import("warnings")?.getattr("warn")?; + let warn = py.import_bound("warnings")?.getattr("warn")?; warn.call1(( "PyPy 3.7 versions older than 7.3.8 are known to have binary \ compatibility issues which may cause segfaults. Please upgrade.", @@ -202,7 +203,8 @@ mod tests { assert_eq!((*module_def.ffi_def.get()).m_doc, DOC.as_ptr() as _); Python::with_gil(|py| { - module_def.initializer.0(py, py.import("builtins").unwrap()).unwrap(); + module_def.initializer.0(py, py.import_bound("builtins").unwrap().into_gil_ref()) + .unwrap(); assert!(INIT_CALLED.load(Ordering::SeqCst)); }) } diff --git a/src/instance.rs b/src/instance.rs index 7f92744c..54a93452 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1196,7 +1196,7 @@ impl Py { /// # Example: `intern!`ing the attribute name /// /// ``` - /// # use pyo3::{intern, pyfunction, types::PyModule, IntoPy, Py, Python, PyObject, PyResult}; + /// # use pyo3::{prelude::*, intern}; /// # /// #[pyfunction] /// fn version(sys: Py, py: Python<'_>) -> PyResult { @@ -1204,7 +1204,7 @@ impl Py { /// } /// # /// # Python::with_gil(|py| { - /// # let sys = py.import("sys").unwrap().into_py(py); + /// # let sys = py.import_bound("sys").unwrap().unbind(); /// # version(sys, py).unwrap(); /// # }); /// ``` diff --git a/src/lib.rs b/src/lib.rs index 5ba0d279..91a61688 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -218,10 +218,10 @@ //! //! fn main() -> PyResult<()> { //! Python::with_gil(|py| { -//! let sys = py.import("sys")?; +//! let sys = py.import_bound("sys")?; //! let version: String = sys.getattr("version")?.extract()?; //! -//! let locals = [("os", py.import("os")?)].into_py_dict_bound(py); +//! let locals = [("os", py.import_bound("os")?)].into_py_dict_bound(py); //! let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'"; //! let user: String = py.eval_bound(code, None, Some(&locals))?.extract()?; //! diff --git a/src/marker.rs b/src/marker.rs index 642ca783..fc84ca54 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -736,7 +736,14 @@ impl<'py> Python<'py> { T::type_object_bound(self).into_gil_ref() } - /// Imports the Python module with the specified name. + /// Deprecated form of [`Python::import_bound`] + #[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`Python::import` will be replaced by `Python::import_bound` in a future PyO3 version" + ) + )] pub fn import(self, name: N) -> PyResult<&'py PyModule> where N: IntoPy>, @@ -744,6 +751,18 @@ impl<'py> Python<'py> { PyModule::import(self, name) } + /// Imports the Python module with the specified name. + pub fn import_bound(self, name: N) -> PyResult> + where + N: IntoPy>, + { + // FIXME: This should be replaced by `PyModule::import_bound` once thats + // implemented. + PyModule::import(self, name) + .map(PyNativeType::as_borrowed) + .map(crate::Borrowed::to_owned) + } + /// Gets the Python builtin value `None`. #[allow(non_snake_case)] // the Python keyword starts with uppercase #[inline] diff --git a/src/sync.rs b/src/sync.rs index 04786c85..8fff0e82 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,5 +1,8 @@ //! Synchronization mechanisms based on the Python GIL. -use crate::{types::PyString, types::PyType, Bound, Py, PyResult, PyVisit, Python}; +use crate::{ + types::{any::PyAnyMethods, PyString, PyType}, + Bound, Py, PyResult, PyVisit, Python, +}; use std::cell::UnsafeCell; /// Value with concurrent access protected by the GIL. @@ -197,8 +200,10 @@ impl GILOnceCell> { module_name: &str, attr_name: &str, ) -> PyResult<&Bound<'py, PyType>> { - self.get_or_try_init(py, || py.import(module_name)?.getattr(attr_name)?.extract()) - .map(|ty| ty.bind(py)) + self.get_or_try_init(py, || { + py.import_bound(module_name)?.getattr(attr_name)?.extract() + }) + .map(|ty| ty.bind(py)) } } diff --git a/src/tests/common.rs b/src/tests/common.rs index bb710d90..ed3972f1 100644 --- a/src/tests/common.rs +++ b/src/tests/common.rs @@ -83,7 +83,7 @@ mod inner { #[cfg(all(feature = "macros", Py_3_8))] impl UnraisableCapture { pub fn install(py: Python<'_>) -> Py { - let sys = py.import("sys").unwrap(); + let sys = py.import_bound("sys").unwrap(); let old_hook = sys.getattr("unraisablehook").unwrap().into(); let capture = Py::new( @@ -104,22 +104,22 @@ mod inner { pub fn uninstall(&mut self, py: Python<'_>) { let old_hook = self.old_hook.take().unwrap(); - let sys = py.import("sys").unwrap(); + let sys = py.import_bound("sys").unwrap(); sys.setattr("unraisablehook", old_hook).unwrap(); } } pub struct CatchWarnings<'py> { - catch_warnings: &'py PyAny, + catch_warnings: Bound<'py, PyAny>, } impl<'py> CatchWarnings<'py> { pub fn enter(py: Python<'py>, f: impl FnOnce(&PyList) -> PyResult) -> PyResult { - let warnings = py.import("warnings")?; + let warnings = py.import_bound("warnings")?; let kwargs = [("record", true)].into_py_dict_bound(py); let catch_warnings = warnings .getattr("catch_warnings")? - .call((), Some(kwargs.as_gil_ref()))?; + .call((), Some(&kwargs))?; let list = catch_warnings.call_method0("__enter__")?.extract()?; let _guard = Self { catch_warnings }; f(list) diff --git a/src/types/any.rs b/src/types/any.rs index 90c7f216..33b3d964 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -86,16 +86,16 @@ impl PyAny { /// # Example: `intern!`ing the attribute name /// /// ``` - /// # use pyo3::{intern, pyfunction, types::PyModule, Python, PyResult}; + /// # use pyo3::{prelude::*, intern}; /// # /// #[pyfunction] - /// fn has_version(sys: &PyModule) -> PyResult { + /// fn has_version(sys: &Bound<'_, PyModule>) -> PyResult { /// sys.hasattr(intern!(sys.py(), "version")) /// } /// # /// # Python::with_gil(|py| { - /// # let sys = py.import("sys").unwrap(); - /// # has_version(sys).unwrap(); + /// # let sys = py.import_bound("sys").unwrap(); + /// # has_version(&sys).unwrap(); /// # }); /// ``` pub fn hasattr(&self, attr_name: N) -> PyResult @@ -115,16 +115,16 @@ impl PyAny { /// # Example: `intern!`ing the attribute name /// /// ``` - /// # use pyo3::{intern, pyfunction, types::PyModule, PyAny, Python, PyResult}; + /// # use pyo3::{prelude::*, intern}; /// # /// #[pyfunction] - /// fn version(sys: &PyModule) -> PyResult<&PyAny> { + /// fn version<'py>(sys: &Bound<'py, PyModule>) -> PyResult> { /// sys.getattr(intern!(sys.py(), "version")) /// } /// # /// # Python::with_gil(|py| { - /// # let sys = py.import("sys").unwrap(); - /// # version(sys).unwrap(); + /// # let sys = py.import_bound("sys").unwrap(); + /// # version(&sys).unwrap(); /// # }); /// ``` pub fn getattr(&self, attr_name: N) -> PyResult<&PyAny> @@ -956,16 +956,16 @@ pub trait PyAnyMethods<'py> { /// # Example: `intern!`ing the attribute name /// /// ``` - /// # use pyo3::{intern, pyfunction, types::PyModule, Python, PyResult}; + /// # use pyo3::{prelude::*, intern}; /// # /// #[pyfunction] - /// fn has_version(sys: &PyModule) -> PyResult { + /// fn has_version(sys: &Bound<'_, PyModule>) -> PyResult { /// sys.hasattr(intern!(sys.py(), "version")) /// } /// # /// # Python::with_gil(|py| { - /// # let sys = py.import("sys").unwrap(); - /// # has_version(sys).unwrap(); + /// # let sys = py.import_bound("sys").unwrap(); + /// # has_version(&sys).unwrap(); /// # }); /// ``` fn hasattr(&self, attr_name: N) -> PyResult @@ -982,16 +982,16 @@ pub trait PyAnyMethods<'py> { /// # Example: `intern!`ing the attribute name /// /// ``` - /// # use pyo3::{intern, pyfunction, types::PyModule, PyAny, Python, PyResult}; + /// # use pyo3::{prelude::*, intern}; /// # /// #[pyfunction] - /// fn version(sys: &PyModule) -> PyResult<&PyAny> { + /// fn version<'py>(sys: &Bound<'py, PyModule>) -> PyResult> { /// sys.getattr(intern!(sys.py(), "version")) /// } /// # /// # Python::with_gil(|py| { - /// # let sys = py.import("sys").unwrap(); - /// # version(sys).unwrap(); + /// # let sys = py.import_bound("sys").unwrap(); + /// # version(&sys).unwrap(); /// # }); /// ``` fn getattr(&self, attr_name: N) -> PyResult> diff --git a/src/types/traceback.rs b/src/types/traceback.rs index 3608772f..b97e2ed0 100644 --- a/src/types/traceback.rs +++ b/src/types/traceback.rs @@ -3,6 +3,9 @@ use crate::types::PyString; use crate::{ffi, Bound}; use crate::{PyAny, PyNativeType}; +use super::any::PyAnyMethods; +use super::string::PyStringMethods; + /// Represents a Python traceback. #[repr(transparent)] pub struct PyTraceback(PyAny); @@ -95,7 +98,7 @@ impl<'py> PyTracebackMethods<'py> for Bound<'py, PyTraceback> { fn format(&self) -> PyResult { let py = self.py(); let string_io = py - .import(intern!(py, "io"))? + .import_bound(intern!(py, "io"))? .getattr(intern!(py, "StringIO"))? .call0()?; let result = unsafe { ffi::PyTraceBack_Print(self.as_ptr(), string_io.as_ptr()) }; @@ -104,8 +107,8 @@ impl<'py> PyTracebackMethods<'py> for Bound<'py, PyTraceback> { .getattr(intern!(py, "getvalue"))? .call0()? .downcast::()? - .to_str()? - .to_owned(); + .to_cow()? + .into_owned(); Ok(formatted) } } diff --git a/tests/test_class_attributes.rs b/tests/test_class_attributes.rs index b589dd08..906a11c8 100644 --- a/tests/test_class_attributes.rs +++ b/tests/test_class_attributes.rs @@ -101,16 +101,16 @@ fn test_fallible_class_attribute() { use pyo3::{exceptions::PyValueError, types::PyString}; struct CaptureStdErr<'py> { - oldstderr: &'py PyAny, - string_io: &'py PyAny, + oldstderr: Bound<'py, PyAny>, + string_io: Bound<'py, PyAny>, } impl<'py> CaptureStdErr<'py> { fn new(py: Python<'py>) -> PyResult { - let sys = py.import("sys")?; + let sys = py.import_bound("sys")?; let oldstderr = sys.getattr("stderr")?; - let string_io = py.import("io")?.getattr("StringIO")?.call0()?; - sys.setattr("stderr", string_io)?; + let string_io = py.import_bound("io")?.getattr("StringIO")?.call0()?; + sys.setattr("stderr", &string_io)?; Ok(Self { oldstderr, string_io, @@ -124,9 +124,9 @@ fn test_fallible_class_attribute() { .getattr("getvalue")? .call0()? .downcast::()? - .to_str()? - .to_owned(); - let sys = py.import("sys")?; + .to_cow()? + .into_owned(); + let sys = py.import_bound("sys")?; sys.setattr("stderr", self.oldstderr)?; Ok(payload) } diff --git a/tests/test_coroutine.rs b/tests/test_coroutine.rs index fa50fe65..549d54aa 100644 --- a/tests/test_coroutine.rs +++ b/tests/test_coroutine.rs @@ -127,7 +127,7 @@ fn cancelled_coroutine() { await task asyncio.run(main()) "#; - let globals = gil.import("__main__").unwrap().dict().as_borrowed(); + let globals = gil.import_bound("__main__").unwrap().dict(); globals.set_item("sleep", sleep).unwrap(); let err = gil .run_bound( @@ -166,7 +166,7 @@ fn coroutine_cancel_handle() { return await task assert asyncio.run(main()) == 0 "#; - let globals = gil.import("__main__").unwrap().dict().as_borrowed(); + let globals = gil.import_bound("__main__").unwrap().dict(); globals .set_item("cancellable_sleep", cancellable_sleep) .unwrap(); @@ -198,7 +198,7 @@ fn coroutine_is_cancelled() { await task asyncio.run(main()) "#; - let globals = gil.import("__main__").unwrap().dict().as_borrowed(); + let globals = gil.import_bound("__main__").unwrap().dict(); globals.set_item("sleep_loop", sleep_loop).unwrap(); gil.run_bound( &pyo3::unindent::unindent(&handle_windows(test)), diff --git a/tests/test_datetime.rs b/tests/test_datetime.rs index de8efa9b..8a9d190f 100644 --- a/tests/test_datetime.rs +++ b/tests/test_datetime.rs @@ -10,7 +10,7 @@ fn _get_subclasses<'py>( args: &str, ) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyAny>, Bound<'py, PyAny>)> { // Import the class from Python and create some subclasses - let datetime = py.import("datetime")?; + let datetime = py.import_bound("datetime")?; let locals = [(py_type, datetime.getattr(py_type)?)].into_py_dict_bound(py); diff --git a/tests/test_datetime_import.rs b/tests/test_datetime_import.rs index bf0001b8..619df891 100644 --- a/tests/test_datetime_import.rs +++ b/tests/test_datetime_import.rs @@ -1,6 +1,6 @@ #![cfg(not(Py_LIMITED_API))] -use pyo3::{types::PyDate, Python}; +use pyo3::{prelude::*, types::PyDate}; #[test] #[should_panic(expected = "module 'datetime' has no attribute 'datetime_CAPI'")] @@ -14,7 +14,7 @@ fn test_bad_datetime_module_panic() { std::fs::File::create(tmpdir.join("datetime.py")).unwrap(); Python::with_gil(|py: Python<'_>| { - let sys = py.import("sys").unwrap(); + let sys = py.import_bound("sys").unwrap(); sys.getattr("path") .unwrap() .call_method1("insert", (0, tmpdir)) diff --git a/tests/test_various.rs b/tests/test_various.rs index 6560610f..d0df8d4a 100644 --- a/tests/test_various.rs +++ b/tests/test_various.rs @@ -134,7 +134,7 @@ impl PickleSupport { } fn add_module(py: Python<'_>, module: &PyModule) -> PyResult<()> { - py.import("sys")? + py.import_bound("sys")? .dict() .get_item("modules") .unwrap() diff --git a/tests/ui/invalid_intern_arg.rs b/tests/ui/invalid_intern_arg.rs index fa9e1e59..3c7bd592 100644 --- a/tests/ui/invalid_intern_arg.rs +++ b/tests/ui/invalid_intern_arg.rs @@ -2,5 +2,5 @@ use pyo3::Python; fn main() { let foo = if true { "foo" } else { "bar" }; - Python::with_gil(|py| py.import(pyo3::intern!(py, foo)).unwrap()); + Python::with_gil(|py| py.import_bound(pyo3::intern!(py, foo)).unwrap()); } diff --git a/tests/ui/invalid_intern_arg.stderr b/tests/ui/invalid_intern_arg.stderr index bb84d00e..dce2d85b 100644 --- a/tests/ui/invalid_intern_arg.stderr +++ b/tests/ui/invalid_intern_arg.stderr @@ -1,8 +1,8 @@ error[E0435]: attempt to use a non-constant value in a constant - --> tests/ui/invalid_intern_arg.rs:5:55 + --> tests/ui/invalid_intern_arg.rs:5:61 | -5 | Python::with_gil(|py| py.import(pyo3::intern!(py, foo)).unwrap()); - | ------------------^^^- - | | | - | | non-constant value - | help: consider using `let` instead of `static`: `let INTERNED` +5 | Python::with_gil(|py| py.import_bound(pyo3::intern!(py, foo)).unwrap()); + | ------------------^^^- + | | | + | | non-constant value + | help: consider using `let` instead of `static`: `let INTERNED`