diff --git a/bindings/python/CONTRIBUTING.md b/bindings/python/CONTRIBUTING.md index 0cce0a8f0f63..e8c8dec0f5f6 100644 --- a/bindings/python/CONTRIBUTING.md +++ b/bindings/python/CONTRIBUTING.md @@ -46,7 +46,7 @@ After `venv` has been prepared, you can activate it by `source venv/bin/activate To simplify our work, we will utilize the tool [`maturin`](https://github.com/PyO3/maturin). Kindly install it beforehand. ```shell -pip install maturin[patchelf] +pip install 'maturin[patchelf]' ``` ## Build diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml index bee110942267..2625c1559089 100644 --- a/bindings/python/Cargo.toml +++ b/bindings/python/Cargo.toml @@ -163,10 +163,8 @@ futures = "0.3.28" opendal = { version = ">=0", path = "../../core", features = [ "layers-blocking", ] } -pyo3 = "0.22.5" -pyo3-async-runtimes = { version = "0.22.0", features = [ - "tokio-runtime", -] } +pyo3 = "0.23.2" +pyo3-async-runtimes = { version = "0.23.0", features = ["tokio-runtime"] } tokio = "1" [target.'cfg(unix)'.dependencies.opendal] diff --git a/bindings/python/src/file.rs b/bindings/python/src/file.rs index 374db32ded04..2c2172324bb7 100644 --- a/bindings/python/src/file.rs +++ b/bindings/python/src/file.rs @@ -32,6 +32,7 @@ use pyo3::buffer::PyBuffer; use pyo3::exceptions::PyIOError; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; +use pyo3::IntoPyObjectExt; use pyo3_async_runtimes::tokio::future_into_py; use tokio::sync::Mutex; @@ -463,12 +464,13 @@ impl AsyncFile { } }; - let ret = reader + let pos = reader .seek(whence) .await .map_err(|err| PyIOError::new_err(err.to_string()))?; - Ok(Python::with_gil(|py| ret.into_py(py))) + Ok(pos) }) + .and_then(|pos| pos.into_bound_py_any(py)) } /// Return the current stream position. @@ -495,8 +497,9 @@ impl AsyncFile { .stream_position() .await .map_err(|err| PyIOError::new_err(err.to_string()))?; - Ok(Python::with_gil(|py| pos.into_py(py))) + Ok(pos) }) + .and_then(|pos| pos.into_bound_py_any(py)) } fn close<'p>(&'p mut self, py: Python<'p>) -> PyResult> { @@ -514,7 +517,7 @@ impl AsyncFile { } fn __aenter__<'a>(slf: PyRef<'a, Self>, py: Python<'a>) -> PyResult> { - let slf = slf.into_py(py); + let slf = slf.into_py_any(py)?; future_into_py(py, async move { Ok(slf) }) } diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs index b499dc42aef2..f05b4b4de85b 100644 --- a/bindings/python/src/lib.rs +++ b/bindings/python/src/lib.rs @@ -87,35 +87,29 @@ fn _opendal(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; // Layer module - let layers_module = PyModule::new_bound(py, "layers")?; + let layers_module = PyModule::new(py, "layers")?; layers_module.add_class::()?; layers_module.add_class::()?; layers_module.add_class::()?; m.add_submodule(&layers_module)?; - py.import_bound("sys")? + py.import("sys")? .getattr("modules")? .set_item("opendal.layers", layers_module)?; - let exception_module = PyModule::new_bound(py, "exceptions")?; - exception_module.add("Error", py.get_type_bound::())?; - exception_module.add("Unexpected", py.get_type_bound::())?; - exception_module.add("Unsupported", py.get_type_bound::())?; - exception_module.add("ConfigInvalid", py.get_type_bound::())?; - exception_module.add("NotFound", py.get_type_bound::())?; - exception_module.add( - "PermissionDenied", - py.get_type_bound::(), - )?; - exception_module.add("IsADirectory", py.get_type_bound::())?; - exception_module.add("NotADirectory", py.get_type_bound::())?; - exception_module.add("AlreadyExists", py.get_type_bound::())?; - exception_module.add("IsSameFile", py.get_type_bound::())?; - exception_module.add( - "ConditionNotMatch", - py.get_type_bound::(), - )?; + let exception_module = PyModule::new(py, "exceptions")?; + exception_module.add("Error", py.get_type::())?; + exception_module.add("Unexpected", py.get_type::())?; + exception_module.add("Unsupported", py.get_type::())?; + exception_module.add("ConfigInvalid", py.get_type::())?; + exception_module.add("NotFound", py.get_type::())?; + exception_module.add("PermissionDenied", py.get_type::())?; + exception_module.add("IsADirectory", py.get_type::())?; + exception_module.add("NotADirectory", py.get_type::())?; + exception_module.add("AlreadyExists", py.get_type::())?; + exception_module.add("IsSameFile", py.get_type::())?; + exception_module.add("ConditionNotMatch", py.get_type::())?; m.add_submodule(&exception_module)?; - py.import_bound("sys")? + py.import("sys")? .getattr("modules")? .set_item("opendal.exceptions", exception_module)?; Ok(()) diff --git a/bindings/python/src/lister.rs b/bindings/python/src/lister.rs index e2074016fae3..6019689de282 100644 --- a/bindings/python/src/lister.rs +++ b/bindings/python/src/lister.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use futures::TryStreamExt; use pyo3::exceptions::PyStopAsyncIteration; -use pyo3::prelude::*; +use pyo3::{prelude::*, IntoPyObjectExt}; use pyo3_async_runtimes::tokio::future_into_py; use tokio::sync::Mutex; @@ -42,7 +42,7 @@ impl BlockingLister { } fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult> { match slf.0.next() { - Some(Ok(entry)) => Ok(Some(Entry::new(entry).into_py(slf.py()))), + Some(Ok(entry)) => Ok(Some(Entry::new(entry).into_py_any(slf.py())?)), Some(Err(err)) => { let pyerr = format_pyerr(err); Err(pyerr) @@ -72,10 +72,17 @@ impl AsyncLister { let mut lister = lister.lock().await; let entry = lister.try_next().await.map_err(format_pyerr)?; match entry { - Some(entry) => Ok(Python::with_gil(|py| Entry::new(entry).into_py(py))), + Some(entry) => Python::with_gil(|py| { + let py_obj = Entry::new(entry).into_py_any(py)?; + Ok(Some(py_obj)) + }), None => Err(PyStopAsyncIteration::new_err("stream exhausted")), } - })?; - Ok(Some(fut.into())) + }); + + match fut { + Ok(fut) => Ok(Some(fut.into())), + Err(e) => Err(e), + } } } diff --git a/bindings/python/src/operator.rs b/bindings/python/src/operator.rs index c412cdc919c5..76cdb09f8653 100644 --- a/bindings/python/src/operator.rs +++ b/bindings/python/src/operator.rs @@ -23,6 +23,7 @@ use pyo3::prelude::*; use pyo3::types::PyBytes; use pyo3::types::PyDict; use pyo3::types::PyTuple; +use pyo3::IntoPyObjectExt; use pyo3_async_runtimes::tokio::future_into_py; use crate::*; @@ -228,10 +229,10 @@ impl Operator { } fn __getnewargs_ex__(&self, py: Python) -> PyResult { - let args = vec![self.__scheme.to_string().to_object(py)]; - let args = PyTuple::new_bound(py, args); - let kwargs = self.__map.clone().into_py(py); - Ok(PyTuple::new_bound(py, [args.to_object(py), kwargs.to_object(py)]).to_object(py)) + let args = vec![self.__scheme.to_string()]; + let args = PyTuple::new(py, args)?.into_py_any(py)?; + let kwargs = self.__map.clone().into_py_any(py)?; + Ok(PyTuple::new(py, [args, kwargs])?.into_py_any(py)?) } } @@ -434,7 +435,8 @@ impl AsyncOperator { let this = self.core.clone(); future_into_py(py, async move { let lister = this.lister(&path).await.map_err(format_pyerr)?; - let pylister: PyObject = Python::with_gil(|py| AsyncLister::new(lister).into_py(py)); + let pylister = Python::with_gil(|py| AsyncLister::new(lister).into_py_any(py))?; + Ok(pylister) }) } @@ -448,7 +450,8 @@ impl AsyncOperator { .recursive(true) .await .map_err(format_pyerr)?; - let pylister: PyObject = Python::with_gil(|py| AsyncLister::new(lister).into_py(py)); + let pylister: PyObject = + Python::with_gil(|py| AsyncLister::new(lister).into_py_any(py))?; Ok(pylister) }) } @@ -543,10 +546,10 @@ impl AsyncOperator { } fn __getnewargs_ex__(&self, py: Python) -> PyResult { - let args = vec![self.__scheme.to_string().to_object(py)]; - let args = PyTuple::new_bound(py, args); - let kwargs = self.__map.clone().into_py(py); - Ok(PyTuple::new_bound(py, [args.to_object(py), kwargs.to_object(py)]).to_object(py)) + let args = vec![self.__scheme.to_string()]; + let args = PyTuple::new(py, args)?.into_py_any(py)?; + let kwargs = self.__map.clone().into_py_any(py)?; + Ok(PyTuple::new(py, [args, kwargs])?.into_py_any(py)?) } } diff --git a/bindings/python/src/utils.rs b/bindings/python/src/utils.rs index eb58e85ef8e2..9970b3304e4f 100644 --- a/bindings/python/src/utils.rs +++ b/bindings/python/src/utils.rs @@ -19,6 +19,7 @@ use std::os::raw::c_int; use pyo3::ffi; use pyo3::prelude::*; +use pyo3::IntoPyObjectExt; /// A bytes-like object that implements buffer protocol. #[pyclass(module = "opendal")] @@ -33,14 +34,14 @@ impl Buffer { /// Consume self to build a bytes pub fn into_bytes(self, py: Python) -> PyResult> { - let buffer = self.into_py(py); + let buffer = self.into_py_any(py)?; unsafe { PyObject::from_owned_ptr_or_err(py, ffi::PyBytes_FromObject(buffer.as_ptr())) } } /// Consume self to build a bytes pub fn into_bytes_ref(self, py: Python) -> PyResult> { - let buffer = self.into_py(py); + let buffer = self.into_py_any(py)?; let view = unsafe { Bound::from_owned_ptr_or_err(py, ffi::PyBytes_FromObject(buffer.as_ptr()))? };