This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 6f22e6d7a feat(bindings/python)!: Stubs fix for operator and 
__version__ (#6728)
6f22e6d7a is described below

commit 6f22e6d7a66b905257ee931ced7f7315768c0943
Author: Chitral Verma <[email protected]>
AuthorDate: Wed Oct 22 15:40:50 2025 +0530

    feat(bindings/python)!: Stubs fix for operator and __version__ (#6728)
---
 bindings/python/python/opendal/__init__.py         |  9 ++++-
 .../python/opendal/{__init__.pyi => operator.pyi}  | 34 +++++++++--------
 bindings/python/src/lib.rs                         | 14 +++----
 bindings/python/src/operator.rs                    | 44 +++++++++++-----------
 bindings/python/tests/conftest.py                  |  4 +-
 bindings/python/tests/test_capability.py           |  4 +-
 6 files changed, 59 insertions(+), 50 deletions(-)

diff --git a/bindings/python/python/opendal/__init__.py 
b/bindings/python/python/opendal/__init__.py
index 91547a39b..c2b8430bd 100644
--- a/bindings/python/python/opendal/__init__.py
+++ b/bindings/python/python/opendal/__init__.py
@@ -16,7 +16,12 @@
 # under the License.
 
 # ruff: noqa: D104
+import builtins
 
-from opendal._opendal import *  # noqa: F403
+from opendal._opendal import *  # noqa: F403 # pyright:ignore
+from opendal.operator import AsyncOperator, Operator  # pyright:ignore
 
-__all__ = [_opendal.__all__]  # noqa: F405
+__version__: builtins.str
+
+__all__ = _opendal.__all__  # noqa: F405 # pyright:ignore
+__all__ += ["AsyncOperator", "Operator"]  # pyright:ignore
diff --git a/bindings/python/python/opendal/__init__.pyi 
b/bindings/python/python/opendal/operator.pyi
similarity index 97%
rename from bindings/python/python/opendal/__init__.pyi
rename to bindings/python/python/opendal/operator.pyi
index 7e3ca6759..564f8c9f8 100644
--- a/bindings/python/python/opendal/__init__.pyi
+++ b/bindings/python/python/opendal/operator.pyi
@@ -25,10 +25,12 @@ import os
 import pathlib
 import typing
 
-from opendal import capability, exceptions, file, layers, types
+import opendal.file
+import opendal.types
+from opendal.capability import Capability
+from opendal.file import File
 from opendal.layers import Layer
-
-__version__: builtins.str = "0.46.1"
+from opendal.types import Metadata
 
 @typing.final
 class AsyncOperator:
@@ -77,7 +79,7 @@ class AsyncOperator:
         path: builtins.str | os.PathLike | pathlib.Path,
         mode: builtins.str,
         **kwargs: typing.Any,
-    ) -> collections.abc.Awaitable[file.AsyncFile]:
+    ) -> collections.abc.Awaitable[opendal.file.AsyncFile]:
         r"""
         Open an async file-like object for the given path.
 
@@ -226,7 +228,7 @@ class AsyncOperator:
         content_type: builtins.str | None = None,
         cache_control: builtins.str | None = None,
         content_disposition: builtins.str | None = None,
-    ) -> collections.abc.Awaitable[types.Metadata]:
+    ) -> collections.abc.Awaitable[Metadata]:
         r"""
         Get the metadata of a file at the given path.
 
@@ -392,7 +394,7 @@ class AsyncOperator:
         recursive: builtins.bool | None = None,
         versions: builtins.bool | None = None,
         deleted: builtins.bool | None = None,
-    ) -> collections.abc.AsyncIterable[types.Entry]:
+    ) -> collections.abc.AsyncIterable[opendal.types.Entry]:
         r"""
         List entries in the given directory.
 
@@ -420,7 +422,7 @@ class AsyncOperator:
         self,
         path: builtins.str | os.PathLike | pathlib.Path,
         expire_second: builtins.int,
-    ) -> types.PresignedRequest:
+    ) -> opendal.types.PresignedRequest:
         r"""
         Create a presigned request for a stat operation.
 
@@ -440,7 +442,7 @@ class AsyncOperator:
         self,
         path: builtins.str | os.PathLike | pathlib.Path,
         expire_second: builtins.int,
-    ) -> types.PresignedRequest:
+    ) -> opendal.types.PresignedRequest:
         r"""
         Create a presigned request for a read operation.
 
@@ -460,7 +462,7 @@ class AsyncOperator:
         self,
         path: builtins.str | os.PathLike | pathlib.Path,
         expire_second: builtins.int,
-    ) -> types.PresignedRequest:
+    ) -> opendal.types.PresignedRequest:
         r"""
         Create a presigned request for a write operation.
 
@@ -480,7 +482,7 @@ class AsyncOperator:
         self,
         path: builtins.str | os.PathLike | pathlib.Path,
         expire_second: builtins.int,
-    ) -> types.PresignedRequest:
+    ) -> opendal.types.PresignedRequest:
         r"""
         Create a presigned request for a delete operation.
 
@@ -496,7 +498,7 @@ class AsyncOperator:
         coroutine
             An awaitable that returns a presigned request object.
         """
-    def full_capability(self) -> capability.Capability:
+    def capability(self) -> Capability:
         r"""
         Get all capabilities of this operator.
 
@@ -562,7 +564,7 @@ class Operator:
         path: builtins.str | os.PathLike | pathlib.Path,
         mode: builtins.str,
         **kwargs: typing.Any,
-    ) -> file.File:
+    ) -> File:
         r"""
         Open a file-like object for the given path.
 
@@ -706,7 +708,7 @@ class Operator:
         content_type: builtins.str | None = None,
         cache_control: builtins.str | None = None,
         content_disposition: builtins.str | None = None,
-    ) -> types.Metadata:
+    ) -> Metadata:
         r"""
         Get the metadata of a file at the given path.
 
@@ -825,7 +827,7 @@ class Operator:
         recursive: builtins.bool | None = None,
         versions: builtins.bool | None = None,
         deleted: builtins.bool | None = None,
-    ) -> collections.abc.Iterable[types.Entry]:
+    ) -> collections.abc.Iterable[opendal.types.Entry]:
         r"""
         List entries in the given directory.
 
@@ -857,7 +859,7 @@ class Operator:
         start_after: builtins.str | None = None,
         versions: builtins.bool | None = None,
         deleted: builtins.bool | None = None,
-    ) -> collections.abc.Iterable[types.Entry]:
+    ) -> collections.abc.Iterable[opendal.types.Entry]:
         r"""
         Recursively list entries in the given directory.
 
@@ -883,7 +885,7 @@ class Operator:
         BlockingLister
             An iterator over the entries in the directory.
         """
-    def full_capability(self) -> capability.Capability:
+    def capability(self) -> Capability:
         r"""
         Get all capabilities of this operator.
 
diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs
index c4133ecc9..46c41f430 100644
--- a/bindings/python/src/lib.rs
+++ b/bindings/python/src/lib.rs
@@ -38,13 +38,16 @@ mod errors;
 pub use errors::*;
 mod options;
 pub use options::*;
-use pyo3_stub_gen::{define_stub_info_gatherer, derive::*, module_variable};
-
-// Add version
-module_variable!("opendal", "__version__", &str, env!("CARGO_PKG_VERSION"));
+use pyo3_stub_gen::{define_stub_info_gatherer, derive::*};
 
 #[pymodule(gil_used = false)]
 fn _opendal(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
+    // Add version
+    m.add("__version__", env!("CARGO_PKG_VERSION"))?;
+
+    // Operator module
+    add_pymodule!(py, m, "operator", [Operator, AsyncOperator])?;
+
     // File module
     add_pymodule!(py, m, "file", [File, AsyncFile])?;
 
@@ -67,9 +70,6 @@ fn _opendal(py: Python, m: &Bound<'_, PyModule>) -> 
PyResult<()> {
         [Entry, EntryMode, Metadata, PresignedRequest]
     )?;
 
-    m.add_class::<Operator>()?;
-    m.add_class::<AsyncOperator>()?;
-
     m.add_class::<WriteOptions>()?;
     m.add_class::<ReadOptions>()?;
     m.add_class::<ListOptions>()?;
diff --git a/bindings/python/src/operator.rs b/bindings/python/src/operator.rs
index 993cda599..1225c854f 100644
--- a/bindings/python/src/operator.rs
+++ b/bindings/python/src/operator.rs
@@ -57,7 +57,7 @@ fn build_blocking_operator(
 /// --------
 /// AsyncOperator
 #[gen_stub_pyclass]
-#[pyclass(module = "opendal")]
+#[pyclass(module = "opendal.operator")]
 pub struct Operator {
     core: ocore::blocking::Operator,
     __scheme: ocore::Scheme,
@@ -144,7 +144,6 @@ impl Operator {
     /// -------
     /// File
     ///     A file-like object.
-    #[gen_stub(override_return_type(type_repr = "file.File"))]
     #[pyo3(signature = (path, mode, *, **kwargs))]
     pub fn open(
         &self,
@@ -400,7 +399,6 @@ impl Operator {
     /// -------
     /// Metadata
     ///     The metadata of the file.
-    #[gen_stub(override_return_type(type_repr = "types.Metadata"))]
     #[allow(clippy::too_many_arguments)]
     #[pyo3(signature = (path, *,
         version=None,
@@ -550,8 +548,8 @@ impl Operator {
     /// BlockingLister
     ///     An iterator over the entries in the directory.
     #[gen_stub(override_return_type(
-        type_repr="collections.abc.Iterable[types.Entry]",
-        imports=("collections.abc")
+        type_repr="collections.abc.Iterable[opendal.types.Entry]",
+        imports=("collections.abc", "opendal.types")
     ))]
     #[pyo3(signature = (path, *,
         limit=None,
@@ -609,8 +607,8 @@ impl Operator {
     /// BlockingLister
     ///     An iterator over the entries in the directory.
     #[gen_stub(override_return_type(
-        type_repr="collections.abc.Iterable[types.Entry]",
-        imports=("collections.abc")
+        type_repr="collections.abc.Iterable[opendal.types.Entry]",
+        imports=("collections.abc", "opendal.types")
     ))]
     #[pyo3(signature = (path, *,
         limit=None,
@@ -634,8 +632,7 @@ impl Operator {
     /// -------
     /// Capability
     ///     The capability of the operator.
-    #[gen_stub(override_return_type(type_repr = "capability.Capability"))]
-    pub fn full_capability(&self) -> PyResult<capability::Capability> {
+    pub fn capability(&self) -> PyResult<capability::Capability> {
         Ok(capability::Capability::new(
             self.core.info().full_capability(),
         ))
@@ -696,7 +693,7 @@ impl Operator {
 /// --------
 /// Operator
 #[gen_stub_pyclass]
-#[pyclass(module = "opendal")]
+#[pyclass(module = "opendal.operator")]
 pub struct AsyncOperator {
     core: ocore::Operator,
     __scheme: ocore::Scheme,
@@ -780,8 +777,8 @@ impl AsyncOperator {
     /// coroutine
     ///     An awaitable that returns a file-like object.
     #[gen_stub(override_return_type(
-        type_repr="collections.abc.Awaitable[file.AsyncFile]",
-        imports=("collections.abc")
+        type_repr="collections.abc.Awaitable[opendal.file.AsyncFile]",
+        imports=("collections.abc", "opendal.file")
     ))]
     #[pyo3(signature = (path, mode, *, **kwargs))]
     pub fn open<'p>(
@@ -1071,7 +1068,7 @@ impl AsyncOperator {
     ///     An awaitable that returns the metadata of the file.
     #[allow(clippy::too_many_arguments)]
     #[gen_stub(override_return_type(
-        type_repr="collections.abc.Awaitable[types.Metadata]",
+        type_repr="collections.abc.Awaitable[Metadata]",
         imports=("collections.abc")
     ))]
     #[pyo3(signature = (path, *,
@@ -1329,7 +1326,10 @@ impl AsyncOperator {
     /// coroutine
     ///     An awaitable that returns an async iterator over the entries.
     #[allow(clippy::too_many_arguments)]
-    #[gen_stub(override_return_type(type_repr = 
"collections.abc.AsyncIterable[types.Entry]"))]
+    #[gen_stub(override_return_type(
+        type_repr="collections.abc.AsyncIterable[opendal.types.Entry]",
+        imports=("collections.abc", "opendal.types")
+    ))]
     #[pyo3(signature = (path, *,
         limit=None,
         start_after=None,
@@ -1390,7 +1390,10 @@ impl AsyncOperator {
     /// -------
     /// coroutine
     ///     An awaitable that returns an async iterator over the entries.
-    #[gen_stub(override_return_type(type_repr = 
"collections.abc.AsyncIterable[types.Entry]",))]
+    #[gen_stub(override_return_type(
+        type_repr="collections.abc.AsyncIterable[opendal.types.Entry]",
+        imports=("collections.abc", "opendal.types")
+    ))]
     #[gen_stub(skip)]
     #[pyo3(signature = (path, *,
         limit=None,
@@ -1422,7 +1425,7 @@ impl AsyncOperator {
     /// -------
     /// coroutine
     ///     An awaitable that returns a presigned request object.
-    #[gen_stub(override_return_type(type_repr = "types.PresignedRequest"))]
+    #[gen_stub(override_return_type(type_repr = 
"opendal.types.PresignedRequest", imports=("opendal.types")))]
     pub fn presign_stat<'p>(
         &'p self,
         py: Python<'p>,
@@ -1455,7 +1458,7 @@ impl AsyncOperator {
     /// -------
     /// coroutine
     ///     An awaitable that returns a presigned request object.
-    #[gen_stub(override_return_type(type_repr = "types.PresignedRequest"))]
+    #[gen_stub(override_return_type(type_repr = 
"opendal.types.PresignedRequest", imports=("opendal.types")))]
     pub fn presign_read<'p>(
         &'p self,
         py: Python<'p>,
@@ -1488,7 +1491,7 @@ impl AsyncOperator {
     /// -------
     /// coroutine
     ///     An awaitable that returns a presigned request object.
-    #[gen_stub(override_return_type(type_repr = "types.PresignedRequest"))]
+    #[gen_stub(override_return_type(type_repr = 
"opendal.types.PresignedRequest", imports=("opendal.types")))]
     pub fn presign_write<'p>(
         &'p self,
         py: Python<'p>,
@@ -1521,7 +1524,7 @@ impl AsyncOperator {
     /// -------
     /// coroutine
     ///     An awaitable that returns a presigned request object.
-    #[gen_stub(override_return_type(type_repr = "types.PresignedRequest"))]
+    #[gen_stub(override_return_type(type_repr = 
"opendal.types.PresignedRequest", imports=("opendal.types")))]
     pub fn presign_delete<'p>(
         &'p self,
         py: Python<'p>,
@@ -1547,8 +1550,7 @@ impl AsyncOperator {
     /// -------
     /// Capability
     ///     The capability of the operator.
-    #[gen_stub(override_return_type(type_repr = "capability.Capability"))]
-    pub fn full_capability(&self) -> PyResult<Capability> {
+    pub fn capability(&self) -> PyResult<Capability> {
         Ok(capability::Capability::new(
             self.core.info().full_capability(),
         ))
diff --git a/bindings/python/tests/conftest.py 
b/bindings/python/tests/conftest.py
index 38a689628..5bf32d545 100644
--- a/bindings/python/tests/conftest.py
+++ b/bindings/python/tests/conftest.py
@@ -79,8 +79,8 @@ def check_capability(request, operator, async_operator) -> 
None:
         marker
         and marker.args
         and not all(
-            [getattr(operator.full_capability(), x) for x in marker.args]
-            + [getattr(async_operator.full_capability(), x) for x in 
marker.args]
+            [getattr(operator.capability(), x) for x in marker.args]
+            + [getattr(async_operator.capability(), x) for x in marker.args]
         )
     ):
         pytest.skip(f"skip because {marker.args} not supported")
diff --git a/bindings/python/tests/test_capability.py 
b/bindings/python/tests/test_capability.py
index b22decdb4..240816418 100644
--- a/bindings/python/tests/test_capability.py
+++ b/bindings/python/tests/test_capability.py
@@ -19,13 +19,13 @@ import pytest
 
 
 def test_capability(service_name, operator):
-    cap = operator.full_capability()
+    cap = operator.capability()
     assert cap is not None
     assert cap.read is not None
 
 
 def test_capability_exception(service_name, operator):
-    cap = operator.full_capability()
+    cap = operator.capability()
     assert cap is not None
     with pytest.raises(AttributeError):
         _ = cap.read_demo

Reply via email to