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 76f06670e feat(bindings/python)!: Add stubs for remaining types (#6720)
76f06670e is described below
commit 76f06670efe95462cf4f1f474fae5b94301623fd
Author: Chitral Verma <[email protected]>
AuthorDate: Wed Oct 22 12:52:58 2025 +0530
feat(bindings/python)!: Add stubs for remaining types (#6720)
* Stubs for Layers
* Stubs for Metadata, Entry, and EntryMode
* Add to API Reference
* Add stubs for operator and file
* update stub-gen and add AsyncFile
* fix docs
* Stubs for operator
* Stubs for AsyncOpertor
* Remove operator module and fix tests
* fix tests
---
bindings/python/Cargo.toml | 2 +-
bindings/python/docs/api/async_file.md | 4 +-
bindings/python/docs/api/capability.md | 4 +-
bindings/python/docs/api/file.md | 4 +-
bindings/python/docs/api/types.md | 16 +-
bindings/python/pyrightconfig.json | 3 +-
bindings/python/python/opendal/__init__.pyi | 1337 +++++++++++++++------------
bindings/python/python/opendal/file.pyi | 317 +++++++
bindings/python/python/opendal/layers.pyi | 17 +-
bindings/python/python/opendal/types.pyi | 26 +
bindings/python/ruff.toml | 2 +-
bindings/python/src/file.rs | 323 ++++++-
bindings/python/src/layers.rs | 13 +-
bindings/python/src/lib.rs | 22 +-
bindings/python/src/operator.rs | 1162 ++++++++++++++++++++---
bindings/python/tests/conftest.py | 4 +-
bindings/python/tests/test_capability.py | 4 +-
17 files changed, 2436 insertions(+), 824 deletions(-)
diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml
index 3ac16216a..9b4ad00b9 100644
--- a/bindings/python/Cargo.toml
+++ b/bindings/python/Cargo.toml
@@ -173,7 +173,7 @@ opendal = { version = ">=0", path = "../../core", features
= [
] }
pyo3 = { version = "0.26.0", features = ["generate-import-lib", "jiff-02"] }
pyo3-async-runtimes = { version = "0.26.0", features = ["tokio-runtime"] }
-pyo3-stub-gen = { version = "0.15" }
+pyo3-stub-gen = { version = "0.16" }
tokio = "1"
[target.'cfg(unix)'.dependencies.opendal]
diff --git a/bindings/python/docs/api/async_file.md
b/bindings/python/docs/api/async_file.md
index b06891f2f..6a2b9f421 100644
--- a/bindings/python/docs/api/async_file.md
+++ b/bindings/python/docs/api/async_file.md
@@ -1,6 +1,6 @@
-::: opendal.AsyncFile
+::: opendal.file.AsyncFile
options:
- heading: "opendal.AsyncFile"
+ heading: "opendal.file.AsyncFile"
heading_level: 2
show_source: false
show_bases: false
diff --git a/bindings/python/docs/api/capability.md
b/bindings/python/docs/api/capability.md
index 14bac70df..68174b5f5 100644
--- a/bindings/python/docs/api/capability.md
+++ b/bindings/python/docs/api/capability.md
@@ -1,6 +1,6 @@
-::: opendal.Capability
+::: opendal.capability.Capability
options:
- heading: "opendal.Capability"
+ heading: "opendal.capability.Capability"
heading_level: 2
show_source: false
show_bases: false
diff --git a/bindings/python/docs/api/file.md b/bindings/python/docs/api/file.md
index 437c77062..b47290759 100644
--- a/bindings/python/docs/api/file.md
+++ b/bindings/python/docs/api/file.md
@@ -1,6 +1,6 @@
-::: opendal.File
+::: opendal.file.File
options:
- heading: "opendal.File"
+ heading: "opendal.file.File"
heading_level: 2
show_source: false
show_bases: false
diff --git a/bindings/python/docs/api/types.md
b/bindings/python/docs/api/types.md
index 396d9bee4..736a088c4 100644
--- a/bindings/python/docs/api/types.md
+++ b/bindings/python/docs/api/types.md
@@ -3,9 +3,9 @@
This page documents all types in OpenDAL.
## Entry
-::: opendal.Entry
+::: opendal.types.Entry
options:
- heading: "opendal.Entry"
+ heading: "opendal.types.Entry"
heading_level: 2
show_source: false
show_bases: false
@@ -13,13 +13,21 @@ This page documents all types in OpenDAL.
## EntryMode
::: opendal.types.EntryMode
options:
- heading: "opendal.EntryMode"
+ heading: "opendal.types.EntryMode"
heading_level: 2
## Metadata
::: opendal.types.Metadata
options:
- heading: "opendal.Metadata"
+ heading: "opendal.types.Metadata"
+ heading_level: 2
+ show_source: false
+ show_bases: false
+
+## PresignedRequest
+::: opendal.types.PresignedRequest
+ options:
+ heading: "opendal.types.PresignedRequest"
heading_level: 2
show_source: false
show_bases: false
diff --git a/bindings/python/pyrightconfig.json
b/bindings/python/pyrightconfig.json
index a76866465..c792ffe00 100644
--- a/bindings/python/pyrightconfig.json
+++ b/bindings/python/pyrightconfig.json
@@ -2,5 +2,6 @@
"include": ["python/opendal/"],
"ignore": [
"python/opendal/*.pyi"
- ]
+ ],
+ "reportIgnoreCommentWithoutRule": false
}
diff --git a/bindings/python/python/opendal/__init__.pyi
b/bindings/python/python/opendal/__init__.pyi
index 91ec09466..7e3ca6759 100644
--- a/bindings/python/python/opendal/__init__.pyi
+++ b/bindings/python/python/opendal/__init__.pyi
@@ -15,699 +15,898 @@
# specific language governing permissions and limitations
# under the License.
+# This file is automatically generated by pyo3_stub_gen
+# ruff: noqa: E501, F401
+
+import builtins
+import collections.abc
+import datetime
import os
-from collections.abc import AsyncIterable, Iterable
-from types import TracebackType
-from typing import TypeAlias, final
-
-try:
- from warnings import deprecated
-except ImportError:
- from typing_extensions import deprecated
-from opendal import exceptions as exceptions
-from opendal import layers as layers
-from opendal.__base import _Base
-from opendal.capability import Capability
-from opendal.layers import Layer
-from opendal.types import Entry, Metadata
+import pathlib
+import typing
-PathBuf: TypeAlias = str | os.PathLike
+from opendal import capability, exceptions, file, layers, types
+from opendal.layers import Layer
-@final
-class Operator(_Base):
- """The entry class for all public blocking APIs.
+__version__: builtins.str = "0.46.1"
- Args:
- scheme (str): The service name that OpenDAL supports.
- **options (any): The options for the service.
- See the documentation of each service for more details.
[email protected]
+class AsyncOperator:
+ r"""
+ The async equivalent of `Operator`.
- Example:
- ```python
- import opendal
+ `AsyncOperator` is the entry point for all async APIs.
- op = opendal.Operator(
- "s3", bucket="bucket", region="us-east-1"
- )
- op.write("hello.txt", b"hello world")
- ```
+ See Also
+ --------
+ Operator
"""
- def __init__(self, scheme: str, **options) -> None: ...
- def layer(self, layer: Layer) -> Operator:
- """Add new layers upon the current operator.
+ def __new__(cls, scheme: builtins.str, **kwargs: typing.Any) ->
AsyncOperator:
+ r"""
+ Create a new `AsyncOperator`.
- Args:
- layer (Layer): The layer to be added.
+ Parameters
+ ----------
+ scheme : str
+ The scheme of the service.
+ **kwargs : dict
+ The options for the service.
Returns
-------
- The new operator with the layer added.
- """
- def open(self, path: PathBuf, mode: str, **options) -> File:
- """Open a file at the given path for reading or writing.
-
- Args:
- path (str | Path): The path to the file.
- mode (str): The mode to open the file. Must be either `"rb"` for
reading or
- `"wb"` for writing.
- **options (Any): Additional options passed to the underlying
OpenDAL reader
- or writer.
- - If `mode == "rb"`: options match the
- [OpenDAL
`ReaderOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.ReaderOptions.html).
- - If `mode == "wb"`: options match the
- [OpenDAL
`WriteOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.WriteOptions.html).
+ AsyncOperator
+ The new async operator.
+ """
+ def layer(self, layer: Layer) -> AsyncOperator:
+ r"""
+ Add a new layer to the operator.
- Returns
- -------
- File: A file-like object that can be used to read or write the
file.
-
- Example:
- ```python
- import opendal
-
- op = opendal.Operator(
- "s3", bucket="bucket", region="us-east-1"
- )
- with op.open("hello.txt", "wb") as f:
- f.write(b"hello world")
- ```
- """
- def read(self, path: PathBuf, **options) -> bytes:
- """Read the content of the object at the given path.
-
- Args:
- path (str | Path): The path to the object.
- **options (Any): Optional read parameters matching the
- [OpenDAL
`ReadOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.ReadOptions.html):
-
- - offset (int): Byte offset to start reading from. Defaults to 0
- if not specified.
- - size (int): Number of bytes to read. If not specified, reads
until
- the end of the object.
- Together, `offset` and `size` define the byte range for
reading.
- - version (str): Specify the version of the object to read, if
- supported by the backend.
- - concurrent (int): Level of concurrency for reading. Defaults
to
- backend-specific value.
- - chunk (int): Read chunk size in bytes.
- - gap (int): Minimum gap (in bytes) between chunks to consider
- them separate.
- - if_match (str): Read only if the ETag matches the given
value.
- - if_none_match (str): Read-only if the ETag does not match the
- given value.
- - if_modified_since (datetime): Only read if the object was
modified
- since this timestamp. This timestamp must be in UTC.
- - if_unmodified_since (datetime): Only read if the object was
not
- modified since this timestamp. This timestamp must be in
UTC.
+ Parameters
+ ----------
+ layer : Layer
+ The layer to add.
Returns
-------
- bytes: The content of the object as bytes.
- """
- def write(self, path: PathBuf, bs: bytes, **options) -> None:
- """Write the content to the object at the given path.
-
- Args:
- path (str | Path): The path to the object.
- bs (bytes): The content to write.
- **options (Any): Optional write parameters matching the
- [OpenDAL
`WriteOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.WriteOptions.html):
-
- - append (bool): If True, append to the object instead of
overwriting.
- - chunk (int): Specify the chunk size in bytes for multipart
uploads.
- - concurrent (int): Number of concurrent upload parts. Larger
values can
- improve performance.
- - cache_control (str): Override the cache-control header for
the object.
- - content_type (str): Explicitly set the Content-Type header
for
- the object.
- - content_disposition (str): Sets how the object should be
presented
- (e.g., as an attachment).
- - content_encoding (str): Override the Content-Encoding header.
- - if_match (str): Perform the write only if the object's
current
- ETag matches the given one.
- - if_none_match (str): Perform the write only if the object's
- current ETag does NOT match the given one.
- - if_not_exists (bool): Only write the object if it doesn't
- already exist.
- - user_metadata (dict[str, str]): Custom user metadata to
associate
- with the object.
+ AsyncOperator
+ A new operator with the layer added.
+ """
+ def open(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ mode: builtins.str,
+ **kwargs: typing.Any,
+ ) -> collections.abc.Awaitable[file.AsyncFile]:
+ r"""
+ Open an async file-like object for the given path.
+
+ The returning async file-like object is a context manager.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ mode : str
+ The mode to open the file in. Only "rb" and "wb" are supported.
+ **kwargs : dict
+ Additional options for the underlying reader or writer.
Returns
-------
- None
- """
- def stat(self, path: PathBuf, **kwargs) -> Metadata:
- """Get the metadata of the object at the given path.
-
- Args:
- path (str | Path): The path to the object.
- **kwargs (Any): Optional stat parameters matching the
- [OpenDAL
`StatOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.StatOptions.html):
-
- - version (str): Specify the version of the object to read, if
- supported by the backend.
- - if_match (str): Read only if the ETag matches the given
value.
- - if_none_match (str): Read-only if the ETag does not match the
- given value.
- - if_modified_since (datetime): Only read if the object was
modified
- since this timestamp. This timestamp must be in UTC.
- - if_unmodified_since (datetime): Only read if the object was
not
- modified since this timestamp. This timestamp must be in
UTC.
- - cache_control (str): Override the cache-control header for
the object.
- - content_type (str): Explicitly set the Content-Type header
for
- the object.
- - content_disposition (str): Sets how the object should be
presented
- (e.g., as an attachment).
+ coroutine
+ An awaitable that returns a file-like object.
+ """
+ def read(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ *,
+ version: builtins.str | None = None,
+ concurrent: builtins.int | None = None,
+ chunk: builtins.int | None = None,
+ gap: builtins.int | None = None,
+ offset: builtins.int | None = None,
+ prefetch: builtins.int | None = None,
+ size: builtins.int | None = None,
+ if_match: builtins.str | None = None,
+ if_none_match: builtins.str | None = None,
+ if_modified_since: datetime.datetime = None,
+ if_unmodified_since: datetime.datetime = None,
+ content_type: builtins.str | None = None,
+ cache_control: builtins.str | None = None,
+ content_disposition: builtins.str | None = None,
+ ) -> collections.abc.Awaitable[builtins.bytes]:
+ r"""
+ Read the entire contents of a file at the given path.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ version : str, optional
+ The version of the file.
+ concurrent : int, optional
+ The number of concurrent readers.
+ chunk : int, optional
+ The size of each chunk.
+ gap : int, optional
+ The gap between each chunk.
+ offset : int, optional
+ The offset of the file.
+ prefetch : int, optional
+ The number of bytes to prefetch.
+ size : int, optional
+ The size of the file.
+ if_match : str, optional
+ The ETag of the file.
+ if_none_match : str, optional
+ The ETag of the file.
+ if_modified_since : str, optional
+ The last modified time of the file.
+ if_unmodified_since : str, optional
+ The last modified time of the file.
+ content_type : str, optional
+ The content type of the file.
+ cache_control : str, optional
+ The cache control of the file.
+ content_disposition : str, optional
+ The content disposition of the file.
Returns
-------
- Metadata: The metadata of the object.
+ coroutine
+ An awaitable that returns the contents of the file as bytes.
"""
- def create_dir(self, path: PathBuf) -> None:
- """Create a directory at the given path.
-
- Args:
- path (str|Path): The path to the directory.
- """
- def delete(self, path: PathBuf) -> None:
- """Delete the object at the given path.
-
- Args:
- path (str|Path): The path to the object.
- """
- def exists(self, path: PathBuf) -> bool:
- """Check if the object at the given path exists.
-
- Args:
- path (str|Path): The path to the object.
+ def write(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ bs: builtins.bytes,
+ *,
+ append: builtins.bool | None = None,
+ chunk: builtins.int | None = None,
+ concurrent: builtins.int | None = None,
+ cache_control: builtins.str | None = None,
+ content_type: builtins.str | None = None,
+ content_disposition: builtins.str | None = None,
+ content_encoding: builtins.str | None = None,
+ if_match: builtins.str | None = None,
+ if_none_match: builtins.str | None = None,
+ if_not_exists: builtins.bool | None = None,
+ user_metadata: typing.Mapping[builtins.str, builtins.str] | None =
None,
+ ) -> collections.abc.Awaitable[None]:
+ r"""
+ Write bytes to a file at the given path.
+
+ This function will create a file if it does not exist, and will
+ overwrite its contents if it does.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ bs : bytes
+ The contents to write to the file.
+ append : bool, optional
+ Whether to append to the file instead of overwriting it.
+ chunk : int, optional
+ The chunk size to use when writing the file.
+ concurrent : int, optional
+ The number of concurrent requests to make when writing the file.
+ cache_control : str, optional
+ The cache control header to set on the file.
+ content_type : str, optional
+ The content type header to set on the file.
+ content_disposition : str, optional
+ The content disposition header to set on the file.
+ content_encoding : str, optional
+ The content encoding header to set on the file.
+ if_match : str, optional
+ The ETag to match when writing the file.
+ if_none_match : str, optional
+ The ETag to not match when writing the file.
+ if_not_exists : bool, optional
+ Whether to fail if the file already exists.
+ user_metadata : dict, optional
+ The user metadata to set on the file.
Returns
-------
- True if the object exists, False otherwise.
- """
- def list(self, path: PathBuf, **kwargs) -> Iterable[Entry]:
- """List objects at the given path.
-
- Args:
- path (str | Path): The path to the directory/ prefix.
- **kwargs (Any): Optional listing parameters matching the
- [OpenDAL
`ListOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.ListOptions.html):
-
- - limit (int): The limit passed to the underlying service to
specify the
- max results that could return per-request. Users could use
this to
- control the memory usage of list operation. If not set,
all matching
- entries will be listed.
- - start_after (str): Start listing after this key. Useful for
pagination
- or resuming interrupted listings.
- - recursive (bool): Whether to list entries recursively
through all
- subdirectories. If False, lists only top-level entries
(entries
- under the given path).
- - versions (bool): Whether to include all versions of objects,
if the
- underlying service supports versioning.
- - deleted (bool): Whether to include deleted objects, if the
underlying
- service supports soft-deletes or versioning.
+ coroutine
+ An awaitable that completes when the write is finished.
+ """
+ def stat(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ *,
+ version: builtins.str | None = None,
+ if_match: builtins.str | None = None,
+ if_none_match: builtins.str | None = None,
+ if_modified_since: datetime.datetime = None,
+ if_unmodified_since: datetime.datetime = None,
+ content_type: builtins.str | None = None,
+ cache_control: builtins.str | None = None,
+ content_disposition: builtins.str | None = None,
+ ) -> collections.abc.Awaitable[types.Metadata]:
+ r"""
+ Get the metadata of a file at the given path.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ version : str, optional
+ The version of the file.
+ if_match : str, optional
+ The ETag of the file.
+ if_none_match : str, optional
+ The ETag of the file.
+ if_modified_since : datetime, optional
+ The last modified time of the file.
+ if_unmodified_since : datetime, optional
+ The last modified time of the file.
+ content_type : str, optional
+ The content type of the file.
+ cache_control : str, optional
+ The cache control of the file.
+ content_disposition : str, optional
+ The content disposition of the file.
Returns
-------
- Iterable[Entry]: An iterable of entries representing the objects
in the
- directory or prefix.
+ coroutine
+ An awaitable that returns the metadata of the file.
"""
- @deprecated("Use `list()` instead.")
- def scan(self, path: PathBuf, **kwargs) -> Iterable[Entry]:
- """Scan the objects at the given path recursively.
-
- Args:
- path (str | Path): The path to the directory/ prefix.
- **kwargs (Any): Optional listing parameters matching the
- [OpenDAL
`ListOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.ListOptions.html),
- excluding `recursive` which is always enforced as `True`
+ def copy(
+ self,
+ source: builtins.str | os.PathLike | pathlib.Path,
+ target: builtins.str | os.PathLike | pathlib.Path,
+ ) -> collections.abc.Awaitable[None]:
+ r"""
+ Copy a file from one path to another.
+
+ Parameters
+ ----------
+ source : str
+ The path to the source file.
+ target : str
+ The path to the target file.
Returns
-------
- Iterable[Entry]: An iterable of all entries under the given path,
- recursively traversing all subdirectories. Each entry
represents
- an object (e.g., file or directory) discovered within the full
- descendant hierarchy of the specified path.
+ coroutine
+ An awaitable that completes when the copy is finished.
"""
- def capability(self) -> Capability:
- """Get the capability of the operator.
+ def rename(
+ self,
+ source: builtins.str | os.PathLike | pathlib.Path,
+ target: builtins.str | os.PathLike | pathlib.Path,
+ ) -> collections.abc.Awaitable[None]:
+ r"""
+ Rename (move) a file from one path to another.
+
+ Parameters
+ ----------
+ source : str
+ The path to the source file.
+ target : str
+ The path to the target file.
Returns
-------
- The capability of the operator.
- """
- def copy(self, source: PathBuf, target: PathBuf) -> None:
- """Copy the object from source to target.
-
- Args:
- source (str|Path): The source path.
- target (str|Path): The target path.
+ coroutine
+ An awaitable that completes when the rename is finished.
"""
- def rename(self, source: PathBuf, target: PathBuf) -> None:
- """Rename the object from source to target.
-
- Args:
- source (str|Path): The source path.
- target (str|Path): The target path.
- """
- def remove_all(self, path: PathBuf) -> None:
- """Convert into an async operator."""
- def to_async_operator(self) -> AsyncOperator: ...
-
-@final
-class AsyncOperator(_Base):
- """The entry class for all public async APIs.
-
- Args:
- scheme (str): The service name that OpenDAL supports.
- **options (any): The options for the service.
- See the documentation of each service for more details.
-
- Example:
- ```python
- import opendal
-
- op = opendal.AsyncOperator(
- "s3", bucket="bucket", region="us-east-1"
- )
- await op.write("hello.txt", b"hello world")
- ```
- """
-
- def __init__(self, scheme: str, **options) -> None: ...
- def layer(self, layer: Layer) -> AsyncOperator: ...
- async def open(self, path: PathBuf, mode: str, **options) -> AsyncFile:
- """Open a file at the given path for reading or writing.
-
- Args:
- path (str | Path): The path to the file.
- mode (str): The mode to open the file. Must be either `"rb"` for
reading or
- `"wb"` for writing.
- **options (Any): Additional options passed to the underlying
OpenDAL reader
- or writer.
- - If `mode == "rb"`: options match the
- [OpenDAL
`ReaderOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.ReaderOptions.html).
- - If `mode == "wb"`: options match the
- [OpenDAL
`WriteOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.WriteOptions.html).
+ def remove_all(
+ self, path: builtins.str | os.PathLike | pathlib.Path
+ ) -> collections.abc.Awaitable[None]:
+ r"""
+ Recursively remove all files and directories at the given path.
- Returns
- -------
- AsyncFile: A file-like object that can be used to read or write
the file.
-
- Example:
- ```python
- import opendal
-
- op = opendal.AsyncOperator(
- "s3", bucket="bucket", region="us-east-1"
- )
- async with await op.open("hello.txt", "wb") as f:
- await f.write(b"hello world")
- ```
- """
- async def read(self, path: PathBuf, **options) -> bytes:
- """Read the content of the object at the given path.
-
- Args:
- path (str | Path): The path to the object.
- **options (Any): Optional read parameters matching the
- [OpenDAL
`ReadOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.ReadOptions.html):
-
- - offset (int): Byte offset to start reading from. Defaults to 0
- if not specified.
- - size (int): Number of bytes to read. If not specified, reads
until
- the end of the object.
- Together, `offset` and `size` define the byte range for
reading.
- - version (str): Specify the version of the object to read, if
- supported by the backend.
- - concurrent (int): Level of concurrency for reading. Defaults
to
- backend-specific value.
- - chunk (int): Read chunk size in bytes.
- - gap (int): Minimum gap (in bytes) between chunks to consider
- them separate.
- - override_content_type (str): Override the returned content
type.
- - if_match (str): Read only if the ETag matches the given
value.
- - if_none_match (str): Read-only if the ETag does not match the
- given value.
- - if_modified_since (datetime): Only read if the object was
modified
- since this timestamp. This timestamp must be in UTC.
- - if_unmodified_since (datetime): Only read if the object was
not
- modified since this timestamp. This timestamp must be in
UTC.
+ Parameters
+ ----------
+ path : str
+ The path to remove.
Returns
-------
- The content of the object as bytes.
- """
- async def write(self, path: PathBuf, bs: bytes, **options) -> None:
- """Write the content to the object at the given path.
-
- Args:
- path (str | Path): The path to the object.
- bs (bytes): The content to write.
- **options (Any): Optional write parameters matching the
- [OpenDAL
`WriteOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.WriteOptions.html):
-
- - append (bool): If True, append to the object instead of
overwriting.
- - chunk (int): Specify the chunk size in bytes for multipart
uploads.
- - concurrent (int): Number of concurrent upload parts. Larger
values can
- improve performance.
- - cache_control (str): Override the cache-control header for
the object.
- - content_type (str): Explicitly set the Content-Type header
for
- the object.
- - content_disposition (str): Sets how the object should be
presented
- (e.g., as an attachment).
- - content_encoding (str): Override the Content-Encoding header.
- - if_match (str): Perform the write only if the object's
current
- ETag matches the given one.
- - if_none_match (str): Perform the write only if the object's
- current ETag does NOT match the given one.
- - if_not_exists (bool): Only write the object if it doesn't
- already exist.
- - user_metadata (dict[str, str]): Custom user metadata to
associate
- with the object.
+ coroutine
+ An awaitable that completes when the removal is finished.
+ """
+ def check(self) -> collections.abc.Awaitable[None]:
+ r"""
+ Check if the operator is able to work correctly.
Returns
-------
- None
- """
- async def stat(self, path: PathBuf, **kwargs) -> Metadata:
- """Get the metadata of the object at the given path.
-
- Args:
- path (str | Path): The path to the object.
- **kwargs (Any): Optional stat parameters matching the
- [OpenDAL
`StatOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.StatOptions.html):
-
- - version (str): Specify the version of the object to read, if
- supported by the backend.
- - if_match (str): Read only if the ETag matches the given
value.
- - if_none_match (str): Read-only if the ETag does not match the
- given value.
- - if_modified_since (datetime): Only read if the object was
modified
- since this timestamp. This timestamp must be in UTC.
- - if_unmodified_since (datetime): Only read if the object was
not
- modified since this timestamp. This timestamp must be in
UTC.
- - cache_control (str): Override the cache-control header for
the object.
- - content_type (str): Explicitly set the Content-Type header
for
- the object.
- - content_disposition (str): Sets how the object should be
presented
- (e.g., as an attachment).
+ coroutine
+ An awaitable that completes when the check is finished.
+
+ Raises
+ ------
+ Exception
+ If the operator is not able to work correctly.
+ """
+ def create_dir(
+ self, path: builtins.str | os.PathLike | pathlib.Path
+ ) -> collections.abc.Awaitable[None]:
+ r"""
+ Create a directory at the given path.
+
+ Notes
+ -----
+ To indicate that a path is a directory, it must end with a `/`.
+ This operation is always recursive, like `mkdir -p`.
+
+ Parameters
+ ----------
+ path : str
+ The path to the directory.
Returns
-------
- Metadata: The metadata of the object.
+ coroutine
+ An awaitable that completes when the directory is created.
"""
- async def create_dir(self, path: PathBuf) -> None:
- """Create a directory at the given path.
+ def delete(
+ self, path: builtins.str | os.PathLike | pathlib.Path
+ ) -> collections.abc.Awaitable[None]:
+ r"""
+ Delete a file at the given path.
- Args:
- path (str|Path): The path to the directory.
- """
- async def delete(self, path: PathBuf) -> None:
- """Delete the object at the given path.
-
- Args:
- path (str|Path): The path to the object.
- """
- async def exists(self, path: PathBuf) -> bool:
- """Check if the object at the given path exists.
+ Notes
+ -----
+ This operation will not return an error if the path does not exist.
- Args:
- path (str|Path): The path to the object.
+ Parameters
+ ----------
+ path : str
+ The path to the file.
Returns
-------
- True if the object exists, False otherwise.
- """
- async def list(self, path: PathBuf, **kwargs) -> AsyncIterable[Entry]:
- """List objects at the given path.
-
- Args:
- path (str | Path): The path to the directory/ prefix.
- **kwargs (Any): Optional listing parameters matching the
- [OpenDAL
`ListOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.ListOptions.html):
-
- - limit (int): The limit passed to the underlying service to
specify the
- max results that could return per-request. Users could use
this to
- control the memory usage of list operation. If not set,
all matching
- entries will be listed.
- - start_after (str): Start listing after this key. Useful for
pagination
- or resuming interrupted listings.
- - recursive (bool): Whether to list entries recursively
through all
- subdirectories. If False, lists only top-level entries
(entries
- under the given path).
- - versions (bool): Whether to include all versions of objects,
if the
- underlying service supports versioning.
- - deleted (bool): Whether to include deleted objects, if the
underlying
- service supports soft-deletes or versioning.
+ coroutine
+ An awaitable that completes when the file is deleted.
+ """
+ def exists(
+ self, path: builtins.str | os.PathLike | pathlib.Path
+ ) -> collections.abc.Awaitable[builtins.bool]:
+ r"""
+ Check if a path exists.
+
+ Parameters
+ ----------
+ path : str
+ The path to check.
Returns
-------
- Iterable[Entry]: An iterable of entries representing the objects
in the
- directory or prefix.
+ coroutine
+ An awaitable that returns True if the path exists, False otherwise.
"""
- @deprecated("Use `list()` instead.")
- async def scan(self, path: PathBuf, **kwargs) -> AsyncIterable[Entry]:
- """Scan the objects at the given path recursively.
-
- Args:
- path (str | Path): The path to the directory/ prefix.
- **kwargs (Any): Optional listing parameters matching the
- [OpenDAL
`ListOptions`](https://opendal.apache.org/docs/rust/opendal/options/struct.ListOptions.html),
- excluding `recursive` which is always enforced as `True`
+ def list(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ *,
+ limit: builtins.int | None = None,
+ start_after: builtins.str | None = None,
+ recursive: builtins.bool | None = None,
+ versions: builtins.bool | None = None,
+ deleted: builtins.bool | None = None,
+ ) -> collections.abc.AsyncIterable[types.Entry]:
+ r"""
+ List entries in the given directory.
+
+ Parameters
+ ----------
+ path : str
+ The path to the directory.
+ limit : int, optional
+ The maximum number of entries to return.
+ start_after : str, optional
+ The entry to start after.
+ recursive : bool, optional
+ Whether to list recursively.
+ versions : bool, optional
+ Whether to list versions.
+ deleted : bool, optional
+ Whether to list deleted entries.
Returns
-------
- Iterable[Entry]: An iterable of all entries under the given path,
- recursively traversing all subdirectories. Each entry
represents
- an object (e.g., file or directory) discovered within the full
- descendant hierarchy of the specified path.
+ coroutine
+ An awaitable that returns an async iterator over the entries.
"""
- async def presign_stat(self, path: PathBuf, expire_second: int) ->
PresignedRequest:
- """Generate a presigned URL for stat operation.
-
- Args:
- path (str|Path): The path to the object.
- expire_second (int): The expiration time in seconds.
+ def presign_stat(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ expire_second: builtins.int,
+ ) -> types.PresignedRequest:
+ r"""
+ Create a presigned request for a stat operation.
+
+ Parameters
+ ----------
+ path : str
+ The path of the object to stat.
+ expire_second : int
+ The number of seconds until the presigned URL expires.
Returns
-------
- A presigned request object.
+ coroutine
+ An awaitable that returns a presigned request object.
"""
- async def presign_read(self, path: PathBuf, expire_second: int) ->
PresignedRequest:
- """Generate a presigned URL for read operation.
-
- Args:
- path (str|Path): The path to the object.
- expire_second (int): The expiration time in seconds.
+ def presign_read(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ expire_second: builtins.int,
+ ) -> types.PresignedRequest:
+ r"""
+ Create a presigned request for a read operation.
+
+ Parameters
+ ----------
+ path : str
+ The path of the object to read.
+ expire_second : int
+ The number of seconds until the presigned URL expires.
Returns
-------
- A presigned request object.
+ coroutine
+ An awaitable that returns a presigned request object.
"""
- async def presign_write(
- self, path: PathBuf, expire_second: int
- ) -> PresignedRequest:
- """Generate a presigned URL for write operation.
-
- Args:
- path (str|Path): The path to the object.
- expire_second (int): The expiration time in seconds.
+ def presign_write(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ expire_second: builtins.int,
+ ) -> types.PresignedRequest:
+ r"""
+ Create a presigned request for a write operation.
+
+ Parameters
+ ----------
+ path : str
+ The path of the object to write to.
+ expire_second : int
+ The number of seconds until the presigned URL expires.
Returns
-------
- A presigned request object.
+ coroutine
+ An awaitable that returns a presigned request object.
"""
- async def presign_delete(
- self, path: PathBuf, expire_second: int
- ) -> PresignedRequest:
- """Generate a presigned URL for delete operation.
-
- Args:
- path (str|Path): The path to the object.
- expire_second (int): The expiration time in seconds.
+ def presign_delete(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ expire_second: builtins.int,
+ ) -> types.PresignedRequest:
+ r"""
+ Create a presigned request for a delete operation.
+
+ Parameters
+ ----------
+ path : str
+ The path of the object to delete.
+ expire_second : int
+ The number of seconds until the presigned URL expires.
Returns
-------
- A presigned request object.
+ coroutine
+ An awaitable that returns a presigned request object.
"""
- def capability(self) -> Capability: ...
- async def copy(self, source: PathBuf, target: PathBuf) -> None:
- """Copy the object from source to target.
+ def full_capability(self) -> capability.Capability:
+ r"""
+ Get all capabilities of this operator.
- Args:
- source (str|Path): The source path.
- target (str|Path): The target path.
+ Returns
+ -------
+ Capability
+ The capability of the operator.
"""
- async def rename(self, source: PathBuf, target: PathBuf) -> None:
- """Rename the object from source to target.
+ def to_operator(self) -> Operator:
+ r"""
+ Create a new blocking `Operator` from this async operator.
- Args:
- source (str|Path): The source path.
- target (str|Path): The target path.
+ Returns
+ -------
+ Operator
+ The blocking operator.
"""
- async def remove_all(self, path: PathBuf) -> None:
- """Remove all objects at the given path.
- Args:
- path (str|Path): The path to the directory.
- """
- def to_operator(self) -> Operator: ...
[email protected]
+class Operator:
+ r"""
+ The blocking equivalent of `AsyncOperator`.
-@final
-class File:
- """
- A file-like object for reading and writing data.
+ `Operator` is the entry point for all blocking APIs.
- Created by the `open` method of the `Operator` class.
+ See Also
+ --------
+ AsyncOperator
"""
- def read(self, size: int | None = None) -> bytes:
- """Read the content of the file.
+ def __new__(cls, scheme: builtins.str, **kwargs: typing.Any) -> Operator:
+ r"""
+ Create a new blocking `Operator`.
- Args:
- size (int): The number of bytes to read. If None, read all.
+ Parameters
+ ----------
+ scheme : str
+ The scheme of the service.
+ **kwargs : dict
+ The options for the service.
Returns
-------
- The content of the file as bytes.
+ Operator
+ The new operator.
"""
- def readline(self, size: int | None = None) -> bytes:
- """Read a single line from the file.
+ def layer(self, layer: Layer) -> Operator:
+ r"""
+ Add a new layer to this operator.
- Args:
- size (int): The number of bytes to read. If None, read until
newline.
+ Parameters
+ ----------
+ layer : Layer
+ The layer to add.
Returns
-------
- The line read from the file as bytes.
- """
- def write(self, bs: bytes) -> None:
- """Write the content to the file.
-
- Args:
- bs (bytes): The content to write.
+ Operator
+ A new operator with the layer added.
"""
- def seek(self, pos: int, whence: int = 0) -> int:
- """Set the file's current position.
-
- Args:
- pos (int): The position to set.
- whence (int): The reference point for the position. Can be 0, 1,
or 2.
+ def open(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ mode: builtins.str,
+ **kwargs: typing.Any,
+ ) -> file.File:
+ r"""
+ Open a file-like object for the given path.
+
+ The returning file-like object is a context manager.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ mode : str
+ The mode to open the file in. Only "rb" and "wb" are supported.
+ **kwargs
+ Additional options for the underlying reader or writer.
Returns
-------
- The new position in the file.
+ File
+ A file-like object.
"""
- def tell(self) -> int:
- """Get the current position in the file.
+ def read(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ *,
+ version: builtins.str | None = None,
+ concurrent: builtins.int | None = None,
+ chunk: builtins.int | None = None,
+ gap: builtins.int | None = None,
+ offset: builtins.int | None = None,
+ prefetch: builtins.int | None = None,
+ size: builtins.int | None = None,
+ if_match: builtins.str | None = None,
+ if_none_match: builtins.str | None = None,
+ if_modified_since: datetime.datetime = None,
+ if_unmodified_since: datetime.datetime = None,
+ content_type: builtins.str | None = None,
+ cache_control: builtins.str | None = None,
+ content_disposition: builtins.str | None = None,
+ ) -> builtins.bytes:
+ r"""
+ Read the entire contents of a file at the given path.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ version : str, optional
+ The version of the file.
+ concurrent : int, optional
+ The number of concurrent readers.
+ chunk : int, optional
+ The size of each chunk.
+ gap : int, optional
+ The gap between each chunk.
+ offset : int, optional
+ The offset of the file.
+ prefetch : int, optional
+ The number of bytes to prefetch.
+ size : int, optional
+ The size of the file.
+ if_match : str, optional
+ The ETag of the file.
+ if_none_match : str, optional
+ The ETag of the file.
+ if_modified_since : str, optional
+ The last modified time of the file.
+ if_unmodified_since : str, optional
+ The last modified time of the file.
+ content_type : str, optional
+ The content type of the file.
+ cache_control : str, optional
+ The cache control of the file.
+ content_disposition : str, optional
+ The content disposition of the file.
Returns
-------
- The current position in the file.
+ bytes
+ The contents of the file as bytes.
"""
- def close(self) -> None:
- """Close the file."""
- def __enter__(self) -> File:
- """Enter the runtime context related to this object."""
- def __exit__(
+ def write(
self,
- exc_type: type[BaseException] | None,
- exc_value: BaseException | None,
- traceback: TracebackType | None,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ bs: builtins.bytes,
+ *,
+ append: builtins.bool | None = None,
+ chunk: builtins.int | None = None,
+ concurrent: builtins.int | None = None,
+ cache_control: builtins.str | None = None,
+ content_type: builtins.str | None = None,
+ content_disposition: builtins.str | None = None,
+ content_encoding: builtins.str | None = None,
+ if_match: builtins.str | None = None,
+ if_none_match: builtins.str | None = None,
+ if_not_exists: builtins.bool | None = None,
+ user_metadata: typing.Mapping[builtins.str, builtins.str] | None =
None,
) -> None:
- """Exit the runtime context related to this object."""
- @property
- def closed(self) -> bool:
- """Check if the file is closed."""
- def flush(self) -> None:
- """Flush the internal buffer."""
- def readable(self) -> bool:
- """Check if the file is readable."""
- def readinto(self, buffer: bytes | bytearray) -> int:
- """Read bytes into a buffer.
-
- Args:
- buffer (bytes|bytearray): The buffer to read into.
+ r"""
+ Write bytes to a file at the given path.
+
+ This function will create a file if it does not exist, and will
+ overwrite its contents if it does.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ bs : bytes
+ The contents to write to the file.
+ append : bool, optional
+ Whether to append to the file instead of overwriting it.
+ chunk : int, optional
+ The chunk size to use when writing the file.
+ concurrent : int, optional
+ The number of concurrent requests to make when writing the file.
+ cache_control : str, optional
+ The cache control header to set on the file.
+ content_type : str, optional
+ The content type header to set on the file.
+ content_disposition : str, optional
+ The content disposition header to set on the file.
+ content_encoding : str, optional
+ The content encoding header to set on the file.
+ if_match : str, optional
+ The ETag to match when writing the file.
+ if_none_match : str, optional
+ The ETag to not match when writing the file.
+ if_not_exists : bool, optional
+ Whether to fail if the file already exists.
+ user_metadata : dict, optional
+ The user metadata to set on the file.
+ """
+ def stat(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ *,
+ version: builtins.str | None = None,
+ if_match: builtins.str | None = None,
+ if_none_match: builtins.str | None = None,
+ if_modified_since: datetime.datetime = None,
+ if_unmodified_since: datetime.datetime = None,
+ content_type: builtins.str | None = None,
+ cache_control: builtins.str | None = None,
+ content_disposition: builtins.str | None = None,
+ ) -> types.Metadata:
+ r"""
+ Get the metadata of a file at the given path.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ version : str, optional
+ The version of the file.
+ if_match : str, optional
+ The ETag of the file.
+ if_none_match : str, optional
+ The ETag of the file.
+ if_modified_since : datetime, optional
+ The last modified time of the file.
+ if_unmodified_since : datetime, optional
+ The last modified time of the file.
+ content_type : str, optional
+ The content type of the file.
+ cache_control : str, optional
+ The cache control of the file.
+ content_disposition : str, optional
+ The content disposition of the file.
Returns
-------
- The number of bytes read.
+ Metadata
+ The metadata of the file.
"""
- def seekable(self) -> bool:
- """Check if the file supports seeking."""
- def writable(self) -> bool:
- """Check if the file is writable."""
-
-@final
-class AsyncFile:
- """
- A file-like object for reading and writing data.
-
- Created by the `open` method of the `AsyncOperator` class.
- """
-
- async def read(self, size: int | None = None) -> bytes:
- """Read the content of the file.
+ def copy(
+ self,
+ source: builtins.str | os.PathLike | pathlib.Path,
+ target: builtins.str | os.PathLike | pathlib.Path,
+ ) -> None:
+ r"""
+ Copy a file from one path to another.
- Args:
- size (int): The number of bytes to read. If None, read all.
+ Parameters
+ ----------
+ source : str
+ The path to the source file.
+ target : str
+ The path to the target file.
+ """
+ def rename(
+ self,
+ source: builtins.str | os.PathLike | pathlib.Path,
+ target: builtins.str | os.PathLike | pathlib.Path,
+ ) -> None:
+ r"""
+ Rename (move) a file from one path to another.
+
+ Parameters
+ ----------
+ source : str
+ The path to the source file.
+ target : str
+ The path to the target file.
+ """
+ def remove_all(self, path: builtins.str | os.PathLike | pathlib.Path) ->
None:
+ r"""
+ Recursively remove all files and directories at the given path.
+
+ Parameters
+ ----------
+ path : str
+ The path to remove.
+ """
+ def create_dir(self, path: builtins.str | os.PathLike | pathlib.Path) ->
None:
+ r"""
+ Create a directory at the given path.
+
+ Notes
+ -----
+ To indicate that a path is a directory, it must end with a `/`.
+ This operation is always recursive, like `mkdir -p`.
+
+ Parameters
+ ----------
+ path : str
+ The path to the directory.
+ """
+ def delete(self, path: builtins.str | os.PathLike | pathlib.Path) -> None:
+ r"""
+ Delete a file at the given path.
+
+ Notes
+ -----
+ This operation will not return an error if the path does not exist.
+
+ Parameters
+ ----------
+ path : str
+ The path to the file.
+ """
+ def exists(self, path: builtins.str | os.PathLike | pathlib.Path) ->
builtins.bool:
+ r"""
+ Check if a path exists.
+
+ Parameters
+ ----------
+ path : str
+ The path to check.
Returns
-------
- The content of the file as bytes.
+ bool
+ True if the path exists, False otherwise.
"""
- async def write(self, bs: bytes) -> None:
- """Write the content to the file.
+ def list(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ *,
+ limit: builtins.int | None = None,
+ start_after: builtins.str | None = None,
+ recursive: builtins.bool | None = None,
+ versions: builtins.bool | None = None,
+ deleted: builtins.bool | None = None,
+ ) -> collections.abc.Iterable[types.Entry]:
+ r"""
+ List entries in the given directory.
+
+ Parameters
+ ----------
+ path : str
+ The path to the directory.
+ limit : int, optional
+ The maximum number of entries to return.
+ start_after : str, optional
+ The entry to start after.
+ recursive : bool, optional
+ Whether to list recursively.
+ versions : bool, optional
+ Whether to list versions.
+ deleted : bool, optional
+ Whether to list deleted entries.
- Args:
- bs (bytes): The content to write.
+ Returns
+ -------
+ BlockingLister
+ An iterator over the entries in the directory.
"""
- async def seek(self, pos: int, whence: int = 0) -> int:
- """Set the file's current position.
+ def scan(
+ self,
+ path: builtins.str | os.PathLike | pathlib.Path,
+ *,
+ limit: builtins.int | None = None,
+ start_after: builtins.str | None = None,
+ versions: builtins.bool | None = None,
+ deleted: builtins.bool | None = None,
+ ) -> collections.abc.Iterable[types.Entry]:
+ r"""
+ Recursively list entries in the given directory.
+
+ Deprecated
+ ----------
+ Use `list()` with `recursive=True` instead.
+
+ Parameters
+ ----------
+ path : str
+ The path to the directory.
+ limit : int, optional
+ The maximum number of entries to return.
+ start_after : str, optional
+ The entry to start after.
+ versions : bool, optional
+ Whether to list versions.
+ deleted : bool, optional
+ Whether to list deleted entries.
- Args:
- pos (int): The position to set.
- whence (int): The reference point for the position. Can be 0, 1,
or 2.
+ Returns
+ -------
+ BlockingLister
+ An iterator over the entries in the directory.
+ """
+ def full_capability(self) -> capability.Capability:
+ r"""
+ Get all capabilities of this operator.
Returns
-------
- The new position in the file.
+ Capability
+ The capability of the operator.
+ """
+ def check(self) -> None:
+ r"""
+ Check if the operator is able to work correctly.
+
+ Raises
+ ------
+ Exception
+ If the operator is not able to work correctly.
"""
- async def tell(self) -> int:
- """Get the current position in the file.
+ def to_async_operator(self) -> AsyncOperator:
+ r"""
+ Create a new `AsyncOperator` from this blocking operator.
Returns
-------
- The current position in the file.
+ AsyncOperator
+ The async operator.
"""
- async def close(self) -> None:
- """Close the file."""
- def __aenter__(self) -> AsyncFile:
- """Enter the runtime context related to this object."""
- def __aexit__(
- self,
- exc_type: type[BaseException] | None,
- exc_value: BaseException | None,
- traceback: TracebackType | None,
- ) -> None:
- """Exit the runtime context related to this object."""
- @property
- async def closed(self) -> bool:
- """Check if the file is closed."""
- async def readable(self) -> bool:
- """Check if the file is readable."""
- async def seekable(self) -> bool:
- """Check if the file supports seeking."""
- async def writable(self) -> bool:
- """Check if the file is writable."""
-
-@final
-class PresignedRequest:
- @property
- def url(self) -> str: ...
- @property
- def method(self) -> str: ...
- @property
- def headers(self) -> dict[str, str]: ...
diff --git a/bindings/python/python/opendal/file.pyi
b/bindings/python/python/opendal/file.pyi
new file mode 100644
index 000000000..b6d59207c
--- /dev/null
+++ b/bindings/python/python/opendal/file.pyi
@@ -0,0 +1,317 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# This file is automatically generated by pyo3_stub_gen
+# ruff: noqa: E501, F401
+
+import builtins
+import collections.abc
+import types
+import typing
+
[email protected]
+class AsyncFile:
+ r"""
+ An async file-like object for reading and writing data.
+
+ Created by the `open` method of the `AsyncOperator` class.
+ """
+
+ @property
+ def closed(self) -> collections.abc.Awaitable[builtins.bool]:
+ r"""
+ Whether this file is closed.
+
+ Returns
+ -------
+ coroutine
+ An awaitable that returns True if this file is closed.
+ """
+ def read(
+ self, size: builtins.int | None = None
+ ) -> collections.abc.Awaitable[builtins.bytes]:
+ r"""
+ Read at most `size` bytes from this file asynchronously.
+
+ If `size` is not specified, read until EOF.
+
+ Parameters
+ ----------
+ size : int, optional
+ The maximum number of bytes to read.
+
+ Returns
+ -------
+ coroutine
+ An awaitable that returns the bytes read from the stream.
+ """
+ def write(self, bs: builtins.bytes) ->
collections.abc.Awaitable[builtins.int]:
+ r"""
+ Write bytes to this file asynchronously.
+
+ Parameters
+ ----------
+ bs : bytes
+ The bytes to write to the file.
+
+ Returns
+ -------
+ coroutine
+ An awaitable that returns the number of bytes written.
+ """
+ def seek(
+ self, pos: builtins.int, whence: builtins.int = 0
+ ) -> collections.abc.Awaitable[builtins.int]:
+ r"""
+ Change the position of this file to the given byte offset.
+
+ Parameters
+ ----------
+ pos : int
+ The byte offset (position) to set.
+ whence : int, optional
+ The reference point for the offset.
+ 0: start of file (default); 1: current position; 2: end of file.
+
+ Returns
+ -------
+ coroutine
+ An awaitable that returns the current absolute position.
+ """
+ def tell(self) -> collections.abc.Awaitable[builtins.int]:
+ r"""
+ Return the current position of this file.
+
+ Returns
+ -------
+ coroutine
+ An awaitable that returns the current absolute position.
+ """
+ def close(self) -> collections.abc.Awaitable[None]:
+ r"""
+ Close this file.
+
+ This also flushes write buffers, if applicable.
+
+ Notes
+ -----
+ A closed file cannot be used for further I/O operations.
+ """
+ def __aenter__(self) -> typing.Self: ...
+ def __aexit__(
+ self,
+ exc_type: type[builtins.BaseException] | None,
+ exc_value: builtins.BaseException | None,
+ traceback: types.TracebackType | None,
+ ) -> None: ...
+ def readable(self) -> collections.abc.Awaitable[builtins.bool]:
+ r"""
+ Whether this file can be read from.
+
+ Returns
+ -------
+ coroutine
+ An awaitable that returns True if this file can be read from.
+ """
+ def writable(self) -> collections.abc.Awaitable[builtins.bool]:
+ r"""
+ Whether this file can be written to.
+
+ Returns
+ -------
+ coroutine
+ An awaitable that returns True if this file can be written to.
+ """
+ def seekable(self) -> collections.abc.Awaitable[builtins.bool]:
+ r"""
+ Whether this file can be repositioned.
+
+ Notes
+ -----
+ This is only applicable to *readable* files.
+
+ Returns
+ -------
+ coroutine
+ An awaitable that returns True if this file can be repositioned.
+ """
+
[email protected]
+class File:
+ r"""
+ A file-like object for reading and writing data.
+
+ Created by the `open` method of the `Operator` class.
+ """
+
+ @property
+ def closed(self) -> builtins.bool:
+ r"""
+ Whether this file is closed.
+
+ Returns
+ -------
+ bool
+ True if this file is closed.
+ """
+ def read(self, size: builtins.int | None = None) -> builtins.bytes:
+ r"""
+ Read at most `size` bytes from this file.
+
+ If `size` is not specified, read until EOF.
+
+ Parameters
+ ----------
+ size : int, optional
+ The maximum number of bytes to read.
+
+ Returns
+ -------
+ bytes
+ The bytes read from this file.
+ """
+ def readline(self, size: builtins.int | None = None) -> builtins.bytes:
+ r"""
+ Read one line from this file.
+
+ If `size` is not specified, read until newline.
+
+ Parameters
+ ----------
+ size : int, optional
+ The maximum number of bytes to read.
+
+ Notes
+ -----
+ Retains newline characters after each line, unless
+ the file’s last line has no terminating newline.
+
+ Returns
+ -------
+ bytes
+ The bytes read from this file.
+ """
+ def readinto(self, buffer: builtins.bytes | builtins.bytearray) ->
builtins.int:
+ r"""
+ Read bytes into a pre-allocated buffer.
+
+ Parameters
+ ----------
+ buffer : bytes | bytearray
+ A writable, pre-allocated buffer to read into.
+
+ Returns
+ -------
+ int
+ The number of bytes read.
+ """
+ def write(self, bs: builtins.bytes) -> builtins.int:
+ r"""
+ Write bytes to this file.
+
+ Parameters
+ ----------
+ bs : bytes
+ The bytes to write to the file.
+
+ Returns
+ -------
+ int
+ The number of bytes written.
+ """
+ def seek(self, pos: builtins.int, whence: builtins.int = 0) ->
builtins.int:
+ r"""
+ Change the position of this file to the given byte offset.
+
+ Parameters
+ ----------
+ pos : int
+ The byte offset (position) to set.
+ whence : int, optional
+ The reference point for the offset.
+ 0: start of file (default); 1: current position; 2: end of file.
+
+ Returns
+ -------
+ int
+ The new absolute position.
+ """
+ def tell(self) -> builtins.int:
+ r"""
+ Return the current position of this file.
+
+ Returns
+ -------
+ int
+ The current absolute position.
+ """
+ def close(self) -> None:
+ r"""
+ Close this file.
+
+ This also flushes write buffers, if applicable.
+
+ Notes
+ -----
+ A closed file cannot be used for further I/O operations.
+ """
+ def __enter__(self, slf: File) -> File: ...
+ def __exit__(
+ self,
+ exc_type: type[builtins.BaseException] | None,
+ exc_value: builtins.BaseException | None,
+ traceback: types.TracebackType | None,
+ ) -> None: ...
+ def flush(self) -> None:
+ r"""
+ Flush the underlying writer.
+
+ Notes
+ -----
+ Is a no-op if the file is not `writable`.
+ """
+ def readable(self) -> builtins.bool:
+ r"""
+ Whether this file can be read from.
+
+ Returns
+ -------
+ bool
+ True if this file can be read from.
+ """
+ def writable(self) -> builtins.bool:
+ r"""
+ Whether this file can be written to.
+
+ Returns
+ -------
+ bool
+ True if this file can be written to.
+ """
+ def seekable(self) -> builtins.bool:
+ r"""
+ Whether this file can be repositioned.
+
+ Notes
+ -----
+ This is only applicable to *readable* files.
+
+ Returns
+ -------
+ bool
+ True if this file can be repositioned.
+ """
diff --git a/bindings/python/python/opendal/layers.pyi
b/bindings/python/python/opendal/layers.pyi
index 8dbd071c9..d46e6f5e1 100644
--- a/bindings/python/python/opendal/layers.pyi
+++ b/bindings/python/python/opendal/layers.pyi
@@ -24,9 +24,7 @@ import typing
@typing.final
class ConcurrentLimitLayer(Layer):
r"""
- ConcurrentLimitLayer.
-
- Create a layer that limits the number of concurrent operations.
+ A layer that limits the number of concurrent operations.
Notes
-----
@@ -51,19 +49,12 @@ class ConcurrentLimitLayer(Layer):
"""
class Layer:
- r"""
- Layer.
-
- Layers are used to intercept the operations on the underlying storage.
- """
+ r"""Layers are used to intercept the operations on the underlying
storage."""
@typing.final
class MimeGuessLayer(Layer):
r"""
- MimeGuessLayer.
-
- Create a layer that guesses MIME types for objects based on their
- paths or content.
+ A layer that guesses MIME types for objects based on their paths or
content.
This layer uses the `mime_guess` crate
(see https://crates.io/crates/mime_guess) to infer the
@@ -91,8 +82,6 @@ class MimeGuessLayer(Layer):
@typing.final
class RetryLayer(Layer):
r"""
- RetryLayer.
-
A layer that retries operations that fail with temporary errors.
Operations are retried if they fail with an error for which
diff --git a/bindings/python/python/opendal/types.pyi
b/bindings/python/python/opendal/types.pyi
index 48377f206..189c66d08 100644
--- a/bindings/python/python/opendal/types.pyi
+++ b/bindings/python/python/opendal/types.pyi
@@ -99,6 +99,32 @@ class Metadata:
def user_metadata(self) -> builtins.dict[builtins.str, builtins.str] |
None:
r"""The user-defined metadata of this entry."""
[email protected]
+class PresignedRequest:
+ r"""
+ A presigned request.
+
+ This contains the information required to make a request to the
+ underlying service, including the URL, method, and headers.
+ """
+
+ @property
+ def url(self) -> builtins.str:
+ r"""The URL of this request."""
+ @property
+ def method(self) -> builtins.str:
+ r"""The HTTP method of this request."""
+ @property
+ def headers(self) -> builtins.dict[builtins.str, builtins.str]:
+ r"""
+ The HTTP headers of this request.
+
+ Returns
+ -------
+ dict
+ The HTTP headers of this request.
+ """
+
@typing.final
class EntryMode(enum.Enum):
r"""
diff --git a/bindings/python/ruff.toml b/bindings/python/ruff.toml
index 6d47e327b..82ab34682 100644
--- a/bindings/python/ruff.toml
+++ b/bindings/python/ruff.toml
@@ -73,6 +73,6 @@ strict = true
known-first-party = ["opendal"]
[lint.per-file-ignores]
-"*.pyi" = ["PYI021", "ANN003", "RUF100"]
+"*.pyi" = ["PYI021", "ANN003", "RUF100", "ANN401"]
"benchmark/*" = ["D100", "D101", "D103", "ANN201"]
"tests/*" = ["D101", "D100", "D103", "ANN201", "ANN001"]
diff --git a/bindings/python/src/file.rs b/bindings/python/src/file.rs
index 4037a6c97..3a5547351 100644
--- a/bindings/python/src/file.rs
+++ b/bindings/python/src/file.rs
@@ -36,9 +36,11 @@ use tokio::sync::Mutex;
use crate::*;
-/// A file-like object.
-/// Can be used as a context manager.
-#[pyclass(module = "opendal")]
+/// A file-like object for reading and writing data.
+///
+/// Created by the `open` method of the `Operator` class.
+#[gen_stub_pyclass]
+#[pyclass(module = "opendal.file")]
pub struct File(FileState);
enum FileState {
@@ -57,10 +59,24 @@ impl File {
}
}
+#[gen_stub_pymethods]
#[pymethods]
impl File {
- /// Read and return at most size bytes, or if size is not given, until EOF.
- #[pyo3(signature = (size=None,))]
+ /// Read at most `size` bytes from this file.
+ ///
+ /// If `size` is not specified, read until EOF.
+ ///
+ /// Parameters
+ /// ----------
+ /// size : int, optional
+ /// The maximum number of bytes to read.
+ ///
+ /// Returns
+ /// -------
+ /// bytes
+ /// The bytes read from this file.
+ #[gen_stub(override_return_type(type_repr = "builtins.bytes",
imports=("builtins")))]
+ #[pyo3(signature = (size=None))]
pub fn read<'p>(
&'p mut self,
py: Python<'p>,
@@ -101,10 +117,26 @@ impl File {
Buffer::new(buffer).into_bytes_ref(py)
}
- /// Read a single line from the file.
- /// A newline character (`\n`) is left at the end of the string, and is
only omitted on the last line of the file if the file doesn’t end in a newline.
- /// If size is specified, at most size bytes will be read.
- #[pyo3(signature = (size=None,))]
+ /// Read one line from this file.
+ ///
+ /// If `size` is not specified, read until newline.
+ ///
+ /// Parameters
+ /// ----------
+ /// size : int, optional
+ /// The maximum number of bytes to read.
+ ///
+ /// Notes
+ /// -----
+ /// Retains newline characters after each line, unless
+ /// the file’s last line has no terminating newline.
+ ///
+ /// Returns
+ /// -------
+ /// bytes
+ /// The bytes read from this file.
+ #[gen_stub(override_return_type(type_repr = "builtins.bytes",
imports=("builtins")))]
+ #[pyo3(signature = (size=None))]
pub fn readline<'p>(
&'p mut self,
py: Python<'p>,
@@ -146,8 +178,22 @@ impl File {
Buffer::new(buffer).into_bytes_ref(py)
}
- /// Read bytes into a pre-allocated, writable buffer
- pub fn readinto(&mut self, buffer: PyBuffer<u8>) -> PyResult<usize> {
+ /// Read bytes into a pre-allocated buffer.
+ ///
+ /// Parameters
+ /// ----------
+ /// buffer : bytes | bytearray
+ /// A writable, pre-allocated buffer to read into.
+ ///
+ /// Returns
+ /// -------
+ /// int
+ /// The number of bytes read.
+ pub fn readinto(
+ &mut self,
+ #[gen_stub(override_type(type_repr = "builtins.bytes |
builtins.bytearray", imports=("builtins")))]
+ buffer: PyBuffer<u8>,
+ ) -> PyResult<usize> {
let reader = match &mut self.0 {
FileState::Reader(r) => r,
FileState::Writer(_) => {
@@ -181,8 +227,21 @@ impl File {
})
}
- /// Write bytes into the file.
- pub fn write(&mut self, bs: &[u8]) -> PyResult<usize> {
+ /// Write bytes to this file.
+ ///
+ /// Parameters
+ /// ----------
+ /// bs : bytes
+ /// The bytes to write to the file.
+ ///
+ /// Returns
+ /// -------
+ /// int
+ /// The number of bytes written.
+ pub fn write(
+ &mut self,
+ #[gen_stub(override_type(type_repr = "builtins.bytes",
imports=("builtins")))] bs: &[u8],
+ ) -> PyResult<usize> {
let writer = match &mut self.0 {
FileState::Reader(_) => {
return Err(PyIOError::new_err(
@@ -203,15 +262,20 @@ impl File {
.map_err(|err| PyIOError::new_err(err.to_string()))
}
- /// Change the stream position to the given byte offset.
- /// Offset is interpreted relative to the position indicated by `whence`.
- /// The default value for whence is `SEEK_SET`. Values for `whence` are:
+ /// Change the position of this file to the given byte offset.
///
- /// * `SEEK_SET` or `0` – start of the stream (the default); offset should
be zero or positive
- /// * `SEEK_CUR` or `1` – current stream position; offset may be negative
- /// * `SEEK_END` or `2` – end of the stream; offset is usually negative
+ /// Parameters
+ /// ----------
+ /// pos : int
+ /// The byte offset (position) to set.
+ /// whence : int, optional
+ /// The reference point for the offset.
+ /// 0: start of file (default); 1: current position; 2: end of file.
///
- /// Return the new absolute position.
+ /// Returns
+ /// -------
+ /// int
+ /// The new absolute position.
#[pyo3(signature = (pos, whence = 0))]
pub fn seek(&mut self, pos: i64, whence: u8) -> PyResult<u64> {
if !self.seekable()? {
@@ -245,7 +309,12 @@ impl File {
.map_err(|err| PyIOError::new_err(err.to_string()))
}
- /// Return the current stream position.
+ /// Return the current position of this file.
+ ///
+ /// Returns
+ /// -------
+ /// int
+ /// The current absolute position.
pub fn tell(&mut self) -> PyResult<u64> {
let reader = match &mut self.0 {
FileState::Reader(r) => r,
@@ -266,6 +335,13 @@ impl File {
.map_err(|err| PyIOError::new_err(err.to_string()))
}
+ /// Close this file.
+ ///
+ /// This also flushes write buffers, if applicable.
+ ///
+ /// Notes
+ /// -----
+ /// A closed file cannot be used for further I/O operations.
fn close(&mut self) -> PyResult<()> {
if let FileState::Writer(w) = &mut self.0 {
w.close().map_err(format_pyerr_from_io_error)?;
@@ -278,16 +354,25 @@ impl File {
slf
}
+ #[allow(unused_variables)]
+ #[pyo3(signature = (exc_type, exc_value, traceback))]
pub fn __exit__(
&mut self,
- _exc_type: Py<PyAny>,
- _exc_value: Py<PyAny>,
- _traceback: Py<PyAny>,
+ #[gen_stub(override_type(type_repr = "type[builtins.BaseException] |
None", imports=("builtins")))]
+ exc_type: Py<PyAny>,
+ #[gen_stub(override_type(type_repr = "builtins.BaseException | None",
imports=("builtins")))]
+ exc_value: Py<PyAny>,
+ #[gen_stub(override_type(type_repr = "types.TracebackType | None",
imports=("types")))]
+ traceback: Py<PyAny>,
) -> PyResult<()> {
self.close()
}
- /// Flush the underlying writer. Is a no-op if the file is opened in
reading mode.
+ /// Flush the underlying writer.
+ ///
+ /// Notes
+ /// -----
+ /// Is a no-op if the file is not `writable`.
pub fn flush(&mut self) -> PyResult<()> {
if matches!(self.0, FileState::Reader(_)) {
Ok(())
@@ -301,19 +386,36 @@ impl File {
}
}
- /// Return True if the stream can be read from.
+ /// Whether this file can be read from.
+ ///
+ /// Returns
+ /// -------
+ /// bool
+ /// True if this file can be read from.
pub fn readable(&self) -> PyResult<bool> {
Ok(matches!(self.0, FileState::Reader(_)))
}
- /// Return True if the stream can be written to.
+ /// Whether this file can be written to.
+ ///
+ /// Returns
+ /// -------
+ /// bool
+ /// True if this file can be written to.
pub fn writable(&self) -> PyResult<bool> {
Ok(matches!(self.0, FileState::Writer(_)))
}
- /// Return True if the stream can be repositioned.
+ /// Whether this file can be repositioned.
+ ///
+ /// Notes
+ /// -----
+ /// This is only applicable to *readable* files.
///
- /// In OpenDAL this is limited to only *readable* streams.
+ /// Returns
+ /// -------
+ /// bool
+ /// True if this file can be repositioned.
pub fn seekable(&self) -> PyResult<bool> {
match &self.0 {
FileState::Reader(_) => Ok(true),
@@ -321,16 +423,23 @@ impl File {
}
}
- /// Return True if the stream is closed.
+ /// Whether this file is closed.
+ ///
+ /// Returns
+ /// -------
+ /// bool
+ /// True if this file is closed.
#[getter]
pub fn closed(&self) -> PyResult<bool> {
Ok(matches!(self.0, FileState::Closed))
}
}
-/// A file-like async reader.
-/// Can be used as an async context manager.
-#[pyclass(module = "opendal")]
+/// An async file-like object for reading and writing data.
+///
+/// Created by the `open` method of the `AsyncOperator` class.
+#[gen_stub_pyclass]
+#[pyclass(module = "opendal.file")]
pub struct AsyncFile(Arc<Mutex<AsyncFileState>>);
enum AsyncFileState {
@@ -349,9 +458,26 @@ impl AsyncFile {
}
}
+#[gen_stub_pymethods]
#[pymethods]
impl AsyncFile {
- /// Read and return at most size bytes, or if size is not given, until EOF.
+ /// Read at most `size` bytes from this file asynchronously.
+ ///
+ /// If `size` is not specified, read until EOF.
+ ///
+ /// Parameters
+ /// ----------
+ /// size : int, optional
+ /// The maximum number of bytes to read.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns the bytes read from the stream.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.bytes]",
+ imports=("collections.abc", "builtins")
+ ))]
#[pyo3(signature = (size=None))]
pub fn read<'p>(&'p self, py: Python<'p>, size: Option<usize>) ->
PyResult<Bound<'p, PyAny>> {
let state = self.0.clone();
@@ -397,8 +523,27 @@ impl AsyncFile {
})
}
- /// Write bytes into the file.
- pub fn write<'p>(&'p mut self, py: Python<'p>, bs: &'p [u8]) ->
PyResult<Bound<'p, PyAny>> {
+ /// Write bytes to this file asynchronously.
+ ///
+ /// Parameters
+ /// ----------
+ /// bs : bytes
+ /// The bytes to write to the file.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns the number of bytes written.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.int]",
+ imports=("collections.abc", "builtins")
+ ))]
+ pub fn write<'p>(
+ &'p mut self,
+ py: Python<'p>,
+ #[gen_stub(override_type(type_repr = "builtins.bytes",
imports=("builtins")))]
+ bs: &'p [u8],
+ ) -> PyResult<Bound<'p, PyAny>> {
let state = self.0.clone();
// FIXME: can we avoid this clone?
@@ -429,15 +574,24 @@ impl AsyncFile {
})
}
- /// Change the stream position to the given byte offset.
- /// offset is interpreted relative to the position indicated by `whence`.
- /// The default value for whence is `SEEK_SET`. Values for `whence` are:
+ /// Change the position of this file to the given byte offset.
///
- /// * `SEEK_SET` or `0` – start of the stream (the default); offset should
be zero or positive
- /// * `SEEK_CUR` or `1` – current stream position; offset may be negative
- /// * `SEEK_END` or `2` – end of the stream; offset is usually negative
+ /// Parameters
+ /// ----------
+ /// pos : int
+ /// The byte offset (position) to set.
+ /// whence : int, optional
+ /// The reference point for the offset.
+ /// 0: start of file (default); 1: current position; 2: end of file.
///
- /// Return the new absolute position.
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns the current absolute position.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.int]",
+ imports=("collections.abc", "builtins")
+ ))]
#[pyo3(signature = (pos, whence = 0))]
pub fn seek<'p>(
&'p mut self,
@@ -479,7 +633,16 @@ impl AsyncFile {
.and_then(|pos| pos.into_bound_py_any(py))
}
- /// Return the current stream position.
+ /// Return the current position of this file.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns the current absolute position.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.int]",
+ imports=("collections.abc", "builtins")
+ ))]
pub fn tell<'p>(&'p mut self, py: Python<'p>) -> PyResult<Bound<'p,
PyAny>> {
let state = self.0.clone();
@@ -508,6 +671,17 @@ impl AsyncFile {
.and_then(|pos| pos.into_bound_py_any(py))
}
+ /// Close this file.
+ ///
+ /// This also flushes write buffers, if applicable.
+ ///
+ /// Notes
+ /// -----
+ /// A closed file cannot be used for further I/O operations.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[None]",
+ imports=("collections.abc")
+ ))]
fn close<'p>(&'p mut self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>> {
let state = self.0.clone();
future_into_py(py, async move {
@@ -520,22 +694,38 @@ impl AsyncFile {
})
}
+ #[gen_stub(override_return_type(type_repr="typing.Self",
imports=("typing")))]
fn __aenter__<'a>(slf: PyRef<'a, Self>, py: Python<'a>) ->
PyResult<Bound<'a, PyAny>> {
let slf = slf.into_py_any(py)?;
future_into_py(py, async move { Ok(slf) })
}
+ #[allow(unused_variables)]
+ #[gen_stub(override_return_type(type_repr = "None"))]
+ #[pyo3(signature = (exc_type, exc_value, traceback))]
fn __aexit__<'a>(
&'a mut self,
py: Python<'a>,
- _exc_type: &Bound<'a, PyAny>,
- _exc_value: &Bound<'a, PyAny>,
- _traceback: &Bound<'a, PyAny>,
+ #[gen_stub(override_type(type_repr = "type[builtins.BaseException] |
None", imports=("builtins")))]
+ exc_type: &Bound<'a, PyAny>,
+ #[gen_stub(override_type(type_repr = "builtins.BaseException | None",
imports=("builtins")))]
+ exc_value: &Bound<'a, PyAny>,
+ #[gen_stub(override_type(type_repr = "types.TracebackType | None",
imports=("types")))]
+ traceback: &Bound<'a, PyAny>,
) -> PyResult<Bound<'a, PyAny>> {
self.close(py)
}
- /// Check if the stream may be read from.
+ /// Whether this file can be read from.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns True if this file can be read from.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.bool]",
+ imports=("collections.abc", "builtins")
+ ))]
pub fn readable<'p>(&'p self, py: Python<'p>) -> PyResult<Bound<'p,
PyAny>> {
let state = self.0.clone();
future_into_py(py, async move {
@@ -544,7 +734,16 @@ impl AsyncFile {
})
}
- /// Check if the stream may be written to.
+ /// Whether this file can be written to.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns True if this file can be written to.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.bool]",
+ imports=("collections.abc", "builtins")
+ ))]
pub fn writable<'p>(&'p self, py: Python<'p>) -> PyResult<Bound<'p,
PyAny>> {
let state = self.0.clone();
future_into_py(py, async move {
@@ -553,7 +752,20 @@ impl AsyncFile {
})
}
- /// Check if the stream reader may be re-located.
+ /// Whether this file can be repositioned.
+ ///
+ /// Notes
+ /// -----
+ /// This is only applicable to *readable* files.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns True if this file can be repositioned.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.bool]",
+ imports=("collections.abc", "builtins")
+ ))]
pub fn seekable<'p>(&'p self, py: Python<'p>) -> PyResult<Bound<'p,
PyAny>> {
if true {
self.readable(py)
@@ -562,7 +774,16 @@ impl AsyncFile {
}
}
- /// Check if the stream is closed.
+ /// Whether this file is closed.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns True if this file is closed.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.bool]",
+ imports=("collections.abc", "builtins")
+ ))]
#[getter]
pub fn closed<'p>(&'p self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>> {
let state = self.0.clone();
diff --git a/bindings/python/src/layers.rs b/bindings/python/src/layers.rs
index 3948f30d6..84365f88e 100644
--- a/bindings/python/src/layers.rs
+++ b/bindings/python/src/layers.rs
@@ -24,15 +24,11 @@ pub trait PythonLayer: Send + Sync {
fn layer(&self, op: Operator) -> Operator;
}
-/// Layer
-///
/// Layers are used to intercept the operations on the underlying storage.
#[gen_stub_pyclass]
#[pyclass(module = "opendal.layers", subclass)]
pub struct Layer(pub Box<dyn PythonLayer>);
-/// RetryLayer
-///
/// A layer that retries operations that fail with temporary errors.
///
/// Operations are retried if they fail with an error for which
@@ -117,9 +113,7 @@ impl RetryLayer {
}
}
-/// ConcurrentLimitLayer
-///
-/// Create a layer that limits the number of concurrent operations.
+/// A layer that limits the number of concurrent operations.
///
/// Notes
/// -----
@@ -163,10 +157,7 @@ impl ConcurrentLimitLayer {
}
}
-/// MimeGuessLayer
-///
-/// Create a layer that guesses MIME types for objects based on their
-/// paths or content.
+/// A layer that guesses MIME types for objects based on their paths or
content.
///
/// This layer uses the `mime_guess` crate
/// (see https://crates.io/crates/mime_guess) to infer the
diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs
index f86b5fa22..c4133ecc9 100644
--- a/bindings/python/src/lib.rs
+++ b/bindings/python/src/lib.rs
@@ -38,15 +38,15 @@ mod errors;
pub use errors::*;
mod options;
pub use options::*;
-use pyo3_stub_gen::{define_stub_info_gatherer, derive::*};
+use pyo3_stub_gen::{define_stub_info_gatherer, derive::*, module_variable};
+
+// Add version
+module_variable!("opendal", "__version__", &str, env!("CARGO_PKG_VERSION"));
#[pymodule(gil_used = false)]
fn _opendal(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
- m.add_class::<Operator>()?;
- m.add_class::<AsyncOperator>()?;
-
- m.add_class::<File>()?;
- m.add_class::<AsyncFile>()?;
+ // File module
+ add_pymodule!(py, m, "file", [File, AsyncFile])?;
// Capability module
add_pymodule!(py, m, "capability", [Capability])?;
@@ -60,9 +60,15 @@ fn _opendal(py: Python, m: &Bound<'_, PyModule>) ->
PyResult<()> {
)?;
// Types module
- add_pymodule!(py, m, "types", [Entry, EntryMode, Metadata])?;
+ add_pymodule!(
+ py,
+ m,
+ "types",
+ [Entry, EntryMode, Metadata, PresignedRequest]
+ )?;
- m.add_class::<PresignedRequest>()?;
+ m.add_class::<Operator>()?;
+ m.add_class::<AsyncOperator>()?;
m.add_class::<WriteOptions>()?;
m.add_class::<ReadOptions>()?;
diff --git a/bindings/python/src/operator.rs b/bindings/python/src/operator.rs
index 5300256fa..993cda599 100644
--- a/bindings/python/src/operator.rs
+++ b/bindings/python/src/operator.rs
@@ -49,9 +49,14 @@ fn build_blocking_operator(
Ok(op)
}
-/// `Operator` is the entry for all public blocking APIs
+/// The blocking equivalent of `AsyncOperator`.
///
-/// Create a new blocking `Operator` with the given `scheme` and
options(`**kwargs`).
+/// `Operator` is the entry point for all blocking APIs.
+///
+/// See also
+/// --------
+/// AsyncOperator
+#[gen_stub_pyclass]
#[pyclass(module = "opendal")]
pub struct Operator {
core: ocore::blocking::Operator,
@@ -59,18 +64,32 @@ pub struct Operator {
__map: HashMap<String, String>,
}
+#[gen_stub_pymethods]
#[pymethods]
impl Operator {
+ /// Create a new blocking `Operator`.
+ ///
+ /// Parameters
+ /// ----------
+ /// scheme : str
+ /// The scheme of the service.
+ /// **kwargs : dict
+ /// The options for the service.
+ ///
+ /// Returns
+ /// -------
+ /// Operator
+ /// The new operator.
#[new]
- #[pyo3(signature = (scheme, *, **map))]
- pub fn new(scheme: &str, map: Option<&Bound<PyDict>>) -> PyResult<Self> {
+ #[pyo3(signature = (scheme, *, **kwargs))]
+ pub fn new(scheme: &str, kwargs: Option<&Bound<PyDict>>) -> PyResult<Self>
{
let scheme = ocore::Scheme::from_str(scheme)
.map_err(|err| {
ocore::Error::new(ocore::ErrorKind::Unexpected, "unsupported
scheme")
.set_source(err)
})
.map_err(format_pyerr)?;
- let map = map
+ let map = kwargs
.map(|v| {
v.extract::<HashMap<String, String>>()
.expect("must be valid hashmap")
@@ -84,7 +103,17 @@ impl Operator {
})
}
- /// Add new layers upon the existing operator
+ /// Add a new layer to this operator.
+ ///
+ /// Parameters
+ /// ----------
+ /// layer : Layer
+ /// The layer to add.
+ ///
+ /// Returns
+ /// -------
+ /// Operator
+ /// A new operator with the layer added.
pub fn layer(&self, layer: &layers::Layer) -> PyResult<Self> {
let op = layer.0.layer(self.core.clone().into());
@@ -98,7 +127,24 @@ impl Operator {
})
}
- /// Open a file-like reader for the given path.
+ /// Open a file-like object for the given path.
+ ///
+ /// The returning file-like object is a context manager.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
+ /// mode : str
+ /// The mode to open the file in. Only "rb" and "wb" are supported.
+ /// **kwargs
+ /// Additional options for the underlying reader or writer.
+ ///
+ /// Returns
+ /// -------
+ /// File
+ /// A file-like object.
+ #[gen_stub(override_return_type(type_repr = "file.File"))]
#[pyo3(signature = (path, mode, *, **kwargs))]
pub fn open(
&self,
@@ -141,150 +187,476 @@ impl Operator {
}
}
- /// Read the whole path into bytes.
- #[pyo3(signature = (path, **kwargs))]
+ /// Read the entire contents of a file at the given path.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
+ /// version : str, optional
+ /// The version of the file.
+ /// concurrent : int, optional
+ /// The number of concurrent readers.
+ /// chunk : int, optional
+ /// The size of each chunk.
+ /// gap : int, optional
+ /// The gap between each chunk.
+ /// offset : int, optional
+ /// The offset of the file.
+ /// prefetch : int, optional
+ /// The number of bytes to prefetch.
+ /// size : int, optional
+ /// The size of the file.
+ /// if_match : str, optional
+ /// The ETag of the file.
+ /// if_none_match : str, optional
+ /// The ETag of the file.
+ /// if_modified_since : str, optional
+ /// The last modified time of the file.
+ /// if_unmodified_since : str, optional
+ /// The last modified time of the file.
+ /// content_type : str, optional
+ /// The content type of the file.
+ /// cache_control : str, optional
+ /// The cache control of the file.
+ /// content_disposition : str, optional
+ /// The content disposition of the file.
+ ///
+ /// Returns
+ /// -------
+ /// bytes
+ /// The contents of the file as bytes.
+ #[allow(clippy::too_many_arguments)]
+ #[gen_stub(override_return_type(type_repr = "builtins.bytes",
imports=("builtins")))]
+ #[pyo3(signature = (path, *,
+ version=None,
+ concurrent=None,
+ chunk=None,
+ gap=None,
+ offset=None,
+ prefetch=None,
+ size=None,
+ if_match=None,
+ if_none_match=None,
+ if_modified_since=None,
+ if_unmodified_since=None,
+ content_type=None,
+ cache_control=None,
+ content_disposition=None))]
pub fn read<'p>(
&'p self,
py: Python<'p>,
path: PathBuf,
- kwargs: Option<ReadOptions>,
+ version: Option<String>,
+ concurrent: Option<usize>,
+ chunk: Option<usize>,
+ gap: Option<usize>,
+ offset: Option<usize>,
+ prefetch: Option<usize>,
+ size: Option<usize>,
+ if_match: Option<String>,
+ if_none_match: Option<String>,
+ #[gen_stub(override_type(type_repr = "datetime.datetime",
imports=("datetime")))]
+ if_modified_since: Option<jiff::Timestamp>,
+ #[gen_stub(override_type(type_repr = "datetime.datetime",
imports=("datetime")))]
+ if_unmodified_since: Option<jiff::Timestamp>,
+ content_type: Option<String>,
+ cache_control: Option<String>,
+ content_disposition: Option<String>,
) -> PyResult<Bound<'p, PyAny>> {
let path = path.to_string_lossy().to_string();
- let kwargs = kwargs.unwrap_or_default();
+ let opts = ReadOptions {
+ version,
+ concurrent,
+ chunk,
+ gap,
+ offset,
+ prefetch,
+ size,
+ if_match,
+ if_none_match,
+ if_modified_since,
+ if_unmodified_since,
+ content_type,
+ cache_control,
+ content_disposition,
+ };
let buffer = self
.core
- .read_options(&path, kwargs.into())
+ .read_options(&path, opts.into())
.map_err(format_pyerr)?
.to_vec();
Buffer::new(buffer).into_bytes_ref(py)
}
- /// Write bytes into a given path.
- #[pyo3(signature = (path, bs, **kwargs))]
- pub fn write(&self, path: PathBuf, bs: Vec<u8>, kwargs:
Option<WriteOptions>) -> PyResult<()> {
+ /// Write bytes to a file at the given path.
+ ///
+ /// This function will create a file if it does not exist, and will
+ /// overwrite its contents if it does.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
+ /// bs : bytes
+ /// The contents to write to the file.
+ /// append : bool, optional
+ /// Whether to append to the file instead of overwriting it.
+ /// chunk : int, optional
+ /// The chunk size to use when writing the file.
+ /// concurrent : int, optional
+ /// The number of concurrent requests to make when writing the file.
+ /// cache_control : str, optional
+ /// The cache control header to set on the file.
+ /// content_type : str, optional
+ /// The content type header to set on the file.
+ /// content_disposition : str, optional
+ /// The content disposition header to set on the file.
+ /// content_encoding : str, optional
+ /// The content encoding header to set on the file.
+ /// if_match : str, optional
+ /// The ETag to match when writing the file.
+ /// if_none_match : str, optional
+ /// The ETag to not match when writing the file.
+ /// if_not_exists : bool, optional
+ /// Whether to fail if the file already exists.
+ /// user_metadata : dict, optional
+ /// The user metadata to set on the file.
+ #[allow(clippy::too_many_arguments)]
+ #[pyo3(signature = (path, bs, *,
+ append= None,
+ chunk = None,
+ concurrent = None,
+ cache_control = None,
+ content_type = None,
+ content_disposition = None,
+ content_encoding = None,
+ if_match = None,
+ if_none_match = None,
+ if_not_exists = None,
+ user_metadata = None))]
+ pub fn write(
+ &self,
+ path: PathBuf,
+ #[gen_stub(override_type(type_repr = "builtins.bytes",
imports=("builtins")))] bs: Vec<u8>,
+ append: Option<bool>,
+ chunk: Option<usize>,
+ concurrent: Option<usize>,
+ cache_control: Option<String>,
+ content_type: Option<String>,
+ content_disposition: Option<String>,
+ content_encoding: Option<String>,
+ if_match: Option<String>,
+ if_none_match: Option<String>,
+ if_not_exists: Option<bool>,
+ user_metadata: Option<HashMap<String, String>>,
+ ) -> PyResult<()> {
let path = path.to_string_lossy().to_string();
- let kwargs = kwargs.unwrap_or_default();
+ let opts = WriteOptions {
+ append,
+ chunk,
+ concurrent,
+ cache_control,
+ content_type,
+ content_disposition,
+ content_encoding,
+ if_match,
+ if_none_match,
+ if_not_exists,
+ user_metadata,
+ };
+
self.core
- .write_options(&path, bs, kwargs.into())
+ .write_options(&path, bs, opts.into())
.map(|_| ())
.map_err(format_pyerr)
}
- /// Get metadata for the current path **without cache** directly.
- #[pyo3(signature = (path, **kwargs))]
- pub fn stat(&self, path: PathBuf, kwargs: Option<&Bound<PyDict>>) ->
PyResult<Metadata> {
+ /// Get the metadata of a file at the given path.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
+ /// version : str, optional
+ /// The version of the file.
+ /// if_match : str, optional
+ /// The ETag of the file.
+ /// if_none_match : str, optional
+ /// The ETag of the file.
+ /// if_modified_since : datetime, optional
+ /// The last modified time of the file.
+ /// if_unmodified_since : datetime, optional
+ /// The last modified time of the file.
+ /// content_type : str, optional
+ /// The content type of the file.
+ /// cache_control : str, optional
+ /// The cache control of the file.
+ /// content_disposition : str, optional
+ /// The content disposition of the file.
+ ///
+ /// Returns
+ /// -------
+ /// 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,
+ if_match=None,
+ if_none_match=None,
+ if_modified_since=None,
+ if_unmodified_since=None,
+ content_type=None,
+ cache_control=None,
+ content_disposition=None))]
+ pub fn stat(
+ &self,
+ path: PathBuf,
+ version: Option<String>,
+ if_match: Option<String>,
+ if_none_match: Option<String>,
+ #[gen_stub(override_type(type_repr = "datetime.datetime",
imports=("datetime")))]
+ if_modified_since: Option<jiff::Timestamp>,
+ #[gen_stub(override_type(type_repr = "datetime.datetime",
imports=("datetime")))]
+ if_unmodified_since: Option<jiff::Timestamp>,
+ content_type: Option<String>,
+ cache_control: Option<String>,
+ content_disposition: Option<String>,
+ ) -> PyResult<Metadata> {
let path = path.to_string_lossy().to_string();
- let kwargs = kwargs
- .map(|v| v.extract::<StatOptions>())
- .transpose()?
- .unwrap_or_default();
+ let opts = StatOptions {
+ version,
+ if_match,
+ if_none_match,
+ if_modified_since,
+ if_unmodified_since,
+ content_type,
+ cache_control,
+ content_disposition,
+ };
self.core
- .stat_options(&path, kwargs.into())
+ .stat_options(&path, opts.into())
.map_err(format_pyerr)
.map(Metadata::new)
}
- /// Copy the source to the target.
+ /// Copy a file from one path to another.
+ ///
+ /// Parameters
+ /// ----------
+ /// source : str
+ /// The path to the source file.
+ /// target : str
+ /// The path to the target file.
pub fn copy(&self, source: PathBuf, target: PathBuf) -> PyResult<()> {
let source = source.to_string_lossy().to_string();
let target = target.to_string_lossy().to_string();
self.core.copy(&source, &target).map_err(format_pyerr)
}
- /// Rename filename.
+ /// Rename (move) a file from one path to another.
+ ///
+ /// Parameters
+ /// ----------
+ /// source : str
+ /// The path to the source file.
+ /// target : str
+ /// The path to the target file.
pub fn rename(&self, source: PathBuf, target: PathBuf) -> PyResult<()> {
let source = source.to_string_lossy().to_string();
let target = target.to_string_lossy().to_string();
self.core.rename(&source, &target).map_err(format_pyerr)
}
- /// Remove all files
+ /// Recursively remove all files and directories at the given path.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to remove.
pub fn remove_all(&self, path: PathBuf) -> PyResult<()> {
let path = path.to_string_lossy().to_string();
self.core.remove_all(&path).map_err(format_pyerr)
}
- /// Create a dir at the given path.
- ///
- /// # Notes
- ///
- /// To indicate that a path is a directory, it is compulsory to include
- /// a trailing / in the path. Failure to do so may result in
- /// a ` NotADirectory ` error being returned by OpenDAL.
+ /// Create a directory at the given path.
///
- /// # Behavior
+ /// Notes
+ /// -----
+ /// To indicate that a path is a directory, it must end with a `/`.
+ /// This operation is always recursive, like `mkdir -p`.
///
- /// - Create on existing dir will succeed.
- /// - Create dir is always recursive, works like `mkdir -p`
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the directory.
pub fn create_dir(&self, path: PathBuf) -> PyResult<()> {
let path = path.to_string_lossy().to_string();
self.core.create_dir(&path).map_err(format_pyerr)
}
- /// Delete given path.
+ /// Delete a file at the given path.
///
- /// # Notes
+ /// Notes
+ /// -----
+ /// This operation will not return an error if the path does not exist.
///
- /// - Delete not existing error won't return errors.
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
pub fn delete(&self, path: PathBuf) -> PyResult<()> {
let path = path.to_string_lossy().to_string();
self.core.delete(&path).map_err(format_pyerr)
}
- /// Checks if the given path exists.
+ /// Check if a path exists.
///
- /// # Notes
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to check.
///
- /// - Check not existing path won't return errors.
+ /// Returns
+ /// -------
+ /// bool
+ /// True if the path exists, False otherwise.
pub fn exists(&self, path: PathBuf) -> PyResult<bool> {
let path = path.to_string_lossy().to_string();
self.core.exists(&path).map_err(format_pyerr)
}
- /// List current dir path.
- #[pyo3(signature = (path, **kwargs))]
- pub fn list(&self, path: PathBuf, kwargs: Option<&Bound<PyDict>>) ->
PyResult<BlockingLister> {
+ /// List entries in the given directory.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the directory.
+ /// limit : int, optional
+ /// The maximum number of entries to return.
+ /// start_after : str, optional
+ /// The entry to start after.
+ /// recursive : bool, optional
+ /// Whether to list recursively.
+ /// versions : bool, optional
+ /// Whether to list versions.
+ /// deleted : bool, optional
+ /// Whether to list deleted entries.
+ ///
+ /// Returns
+ /// -------
+ /// BlockingLister
+ /// An iterator over the entries in the directory.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Iterable[types.Entry]",
+ imports=("collections.abc")
+ ))]
+ #[pyo3(signature = (path, *,
+ limit=None,
+ start_after=None,
+ recursive=None,
+ versions=None,
+ deleted=None))]
+ pub fn list(
+ &self,
+ path: PathBuf,
+ limit: Option<usize>,
+ start_after: Option<String>,
+ recursive: Option<bool>,
+ versions: Option<bool>,
+ deleted: Option<bool>,
+ ) -> PyResult<BlockingLister> {
let path = path.to_string_lossy().to_string();
- let kwargs = kwargs
- .map(|v| v.extract::<ListOptions>())
- .transpose()?
- .unwrap_or_default();
+ let opts = ListOptions {
+ limit,
+ start_after,
+ recursive,
+ versions,
+ deleted,
+ };
let l = self
.core
- .lister_options(&path, kwargs.into())
+ .lister_options(&path, opts.into())
.map_err(format_pyerr)?;
Ok(BlockingLister::new(l))
}
- /// List dir in a flat way.
- #[pyo3(signature = (path, **kwargs))]
- pub fn scan<'p>(
+ /// Recursively list entries in the given directory.
+ ///
+ /// Deprecated
+ /// ----------
+ /// Use `list()` with `recursive=True` instead.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the directory.
+ /// limit : int, optional
+ /// The maximum number of entries to return.
+ /// start_after : str, optional
+ /// The entry to start after.
+ /// versions : bool, optional
+ /// Whether to list versions.
+ /// deleted : bool, optional
+ /// Whether to list deleted entries.
+ ///
+ /// Returns
+ /// -------
+ /// BlockingLister
+ /// An iterator over the entries in the directory.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Iterable[types.Entry]",
+ imports=("collections.abc")
+ ))]
+ #[pyo3(signature = (path, *,
+ limit=None,
+ start_after=None,
+ versions=None,
+ deleted=None))]
+ pub fn scan(
&self,
- py: Python<'p>,
path: PathBuf,
- kwargs: Option<&Bound<PyDict>>,
+ limit: Option<usize>,
+ start_after: Option<String>,
+ versions: Option<bool>,
+ deleted: Option<bool>,
) -> PyResult<BlockingLister> {
- let d = PyDict::new(py);
- let kwargs = kwargs.unwrap_or(&d);
- kwargs.set_item("recursive", true)?;
-
- self.list(path, Some(kwargs))
+ self.list(path, limit, start_after, Some(true), versions, deleted)
}
- pub fn capability(&self) -> PyResult<capability::Capability> {
+ /// Get all capabilities of this operator.
+ ///
+ /// Returns
+ /// -------
+ /// Capability
+ /// The capability of the operator.
+ #[gen_stub(override_return_type(type_repr = "capability.Capability"))]
+ pub fn full_capability(&self) -> PyResult<capability::Capability> {
Ok(capability::Capability::new(
self.core.info().full_capability(),
))
}
- /// Check if this operator can work correctly.
+ /// Check if the operator is able to work correctly.
+ ///
+ /// Raises
+ /// ------
+ /// Exception
+ /// If the operator is not able to work correctly.
pub fn check(&self) -> PyResult<()> {
self.core.check().map_err(format_pyerr)
}
+ /// Create a new `AsyncOperator` from this blocking operator.
+ ///
+ /// Returns
+ /// -------
+ /// AsyncOperator
+ /// The async operator.
pub fn to_async_operator(&self) -> PyResult<AsyncOperator> {
Ok(AsyncOperator {
core: self.core.clone().into(),
@@ -307,6 +679,7 @@ impl Operator {
}
}
+ #[gen_stub(skip)]
fn __getnewargs_ex__(&self, py: Python) -> PyResult<Py<PyAny>> {
let args = vec![self.__scheme.to_string()];
let args = PyTuple::new(py, args)?.into_py_any(py)?;
@@ -315,9 +688,14 @@ impl Operator {
}
}
-/// `AsyncOperator` is the entry for all public async APIs
+/// The async equivalent of `Operator`.
+///
+/// `AsyncOperator` is the entry point for all async APIs.
///
-/// Create a new `AsyncOperator` with the given `scheme` and
options(`**kwargs`).
+/// See also
+/// --------
+/// Operator
+#[gen_stub_pyclass]
#[pyclass(module = "opendal")]
pub struct AsyncOperator {
core: ocore::Operator,
@@ -325,18 +703,32 @@ pub struct AsyncOperator {
__map: HashMap<String, String>,
}
+#[gen_stub_pymethods]
#[pymethods]
impl AsyncOperator {
+ /// Create a new `AsyncOperator`.
+ ///
+ /// Parameters
+ /// ----------
+ /// scheme : str
+ /// The scheme of the service.
+ /// **kwargs : dict
+ /// The options for the service.
+ ///
+ /// Returns
+ /// -------
+ /// AsyncOperator
+ /// The new async operator.
#[new]
- #[pyo3(signature = (scheme, *, **map))]
- pub fn new(scheme: &str, map: Option<&Bound<PyDict>>) -> PyResult<Self> {
+ #[pyo3(signature = (scheme, * ,**kwargs))]
+ pub fn new(scheme: &str, kwargs: Option<&Bound<PyDict>>) -> PyResult<Self>
{
let scheme = ocore::Scheme::from_str(scheme)
.map_err(|err| {
ocore::Error::new(ocore::ErrorKind::Unexpected, "unsupported
scheme")
.set_source(err)
})
.map_err(format_pyerr)?;
- let map = map
+ let map = kwargs
.map(|v| {
v.extract::<HashMap<String, String>>()
.expect("must be valid hashmap")
@@ -350,7 +742,17 @@ impl AsyncOperator {
})
}
- /// Add new layers upon the existing operator
+ /// Add a new layer to the operator.
+ ///
+ /// Parameters
+ /// ----------
+ /// layer : Layer
+ /// The layer to add.
+ ///
+ /// Returns
+ /// -------
+ /// AsyncOperator
+ /// A new operator with the layer added.
pub fn layer(&self, layer: &layers::Layer) -> PyResult<Self> {
let op = layer.0.layer(self.core.clone());
Ok(Self {
@@ -360,7 +762,27 @@ impl AsyncOperator {
})
}
- /// Open a file-like reader for the given path.
+ /// Open an async file-like object for the given path.
+ ///
+ /// The returning async file-like object is a context manager.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
+ /// mode : str
+ /// The mode to open the file in. Only "rb" and "wb" are supported.
+ /// **kwargs : dict
+ /// Additional options for the underlying reader or writer.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns a file-like object.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[file.AsyncFile]",
+ imports=("collections.abc")
+ ))]
#[pyo3(signature = (path, mode, *, **kwargs))]
pub fn open<'p>(
&'p self,
@@ -410,21 +832,108 @@ impl AsyncOperator {
})
}
- /// Read the whole path into bytes.
- #[pyo3(signature = (path, **kwargs))]
+ /// Read the entire contents of a file at the given path.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
+ /// version : str, optional
+ /// The version of the file.
+ /// concurrent : int, optional
+ /// The number of concurrent readers.
+ /// chunk : int, optional
+ /// The size of each chunk.
+ /// gap : int, optional
+ /// The gap between each chunk.
+ /// offset : int, optional
+ /// The offset of the file.
+ /// prefetch : int, optional
+ /// The number of bytes to prefetch.
+ /// size : int, optional
+ /// The size of the file.
+ /// if_match : str, optional
+ /// The ETag of the file.
+ /// if_none_match : str, optional
+ /// The ETag of the file.
+ /// if_modified_since : str, optional
+ /// The last modified time of the file.
+ /// if_unmodified_since : str, optional
+ /// The last modified time of the file.
+ /// content_type : str, optional
+ /// The content type of the file.
+ /// cache_control : str, optional
+ /// The cache control of the file.
+ /// content_disposition : str, optional
+ /// The content disposition of the file.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns the contents of the file as bytes.
+ #[allow(clippy::too_many_arguments)]
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.bytes]",
+ imports=("collections.abc", "builtins")
+ ))]
+ #[pyo3(signature = (path, *,
+ version=None,
+ concurrent=None,
+ chunk=None,
+ gap=None,
+ offset=None,
+ prefetch=None,
+ size=None,
+ if_match=None,
+ if_none_match=None,
+ if_modified_since=None,
+ if_unmodified_since=None,
+ content_type=None,
+ cache_control=None,
+ content_disposition=None))]
pub fn read<'p>(
&'p self,
py: Python<'p>,
path: PathBuf,
- kwargs: Option<ReadOptions>,
+ version: Option<String>,
+ concurrent: Option<usize>,
+ chunk: Option<usize>,
+ gap: Option<usize>,
+ offset: Option<usize>,
+ prefetch: Option<usize>,
+ size: Option<usize>,
+ if_match: Option<String>,
+ if_none_match: Option<String>,
+ #[gen_stub(override_type(type_repr = "datetime.datetime",
imports=("datetime")))]
+ if_modified_since: Option<jiff::Timestamp>,
+ #[gen_stub(override_type(type_repr = "datetime.datetime",
imports=("datetime")))]
+ if_unmodified_since: Option<jiff::Timestamp>,
+ content_type: Option<String>,
+ cache_control: Option<String>,
+ content_disposition: Option<String>,
) -> PyResult<Bound<'p, PyAny>> {
let this = self.core.clone();
let path = path.to_string_lossy().to_string();
- let kwargs = kwargs.unwrap_or_default();
+ let opts = ReadOptions {
+ version,
+ concurrent,
+ chunk,
+ gap,
+ offset,
+ prefetch,
+ size,
+ if_match,
+ if_none_match,
+ if_modified_since,
+ if_unmodified_since,
+ content_type,
+ cache_control,
+ content_disposition,
+ };
future_into_py(py, async move {
- let range = kwargs.make_range();
+ let range = opts.make_range();
let res = this
- .reader_options(&path, kwargs.into())
+ .reader_options(&path, opts.into())
.await
.map_err(format_pyerr)?
.read(range.to_range())
@@ -435,61 +944,176 @@ impl AsyncOperator {
})
}
- /// Write bytes into given path.
- #[pyo3(signature = (path, bs, **kwargs))]
+ /// Write bytes to a file at the given path.
+ ///
+ /// This function will create a file if it does not exist, and will
+ /// overwrite its contents if it does.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
+ /// bs : bytes
+ /// The contents to write to the file.
+ /// append : bool, optional
+ /// Whether to append to the file instead of overwriting it.
+ /// chunk : int, optional
+ /// The chunk size to use when writing the file.
+ /// concurrent : int, optional
+ /// The number of concurrent requests to make when writing the file.
+ /// cache_control : str, optional
+ /// The cache control header to set on the file.
+ /// content_type : str, optional
+ /// The content type header to set on the file.
+ /// content_disposition : str, optional
+ /// The content disposition header to set on the file.
+ /// content_encoding : str, optional
+ /// The content encoding header to set on the file.
+ /// if_match : str, optional
+ /// The ETag to match when writing the file.
+ /// if_none_match : str, optional
+ /// The ETag to not match when writing the file.
+ /// if_not_exists : bool, optional
+ /// Whether to fail if the file already exists.
+ /// user_metadata : dict, optional
+ /// The user metadata to set on the file.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that completes when the write is finished.
+ #[allow(clippy::too_many_arguments)]
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[None]",
+ imports=("collections.abc")
+ ))]
+ #[pyo3(signature = (path, bs, *,
+ append= None,
+ chunk = None,
+ concurrent = None,
+ cache_control = None,
+ content_type = None,
+ content_disposition = None,
+ content_encoding = None,
+ if_match = None,
+ if_none_match = None,
+ if_not_exists = None,
+ user_metadata = None))]
pub fn write<'p>(
&'p self,
py: Python<'p>,
path: PathBuf,
- bs: &Bound<PyBytes>,
- kwargs: Option<WriteOptions>,
+ #[gen_stub(override_type(type_repr = "builtins.bytes",
imports=("builtins")))] bs: &Bound<
+ PyBytes,
+ >,
+ append: Option<bool>,
+ chunk: Option<usize>,
+ concurrent: Option<usize>,
+ cache_control: Option<String>,
+ content_type: Option<String>,
+ content_disposition: Option<String>,
+ content_encoding: Option<String>,
+ if_match: Option<String>,
+ if_none_match: Option<String>,
+ if_not_exists: Option<bool>,
+ user_metadata: Option<HashMap<String, String>>,
) -> PyResult<Bound<'p, PyAny>> {
- let mut kwargs = kwargs.unwrap_or_default();
+ let opts = WriteOptions {
+ append,
+ chunk,
+ concurrent,
+ cache_control,
+ content_type,
+ content_disposition,
+ content_encoding,
+ if_match,
+ if_none_match,
+ if_not_exists,
+ user_metadata,
+ };
let this = self.core.clone();
let bs = bs.as_bytes().to_vec();
let path = path.to_string_lossy().to_string();
future_into_py(py, async move {
- let mut write = this
- .write_with(&path, bs)
- .append(kwargs.append.unwrap_or(false));
- if let Some(buffer) = kwargs.chunk {
- write = write.chunk(buffer);
- }
- if let Some(content_type) = &kwargs.content_type {
- write = write.content_type(content_type);
- }
- if let Some(content_disposition) = &kwargs.content_disposition {
- write = write.content_disposition(content_disposition);
- }
- if let Some(cache_control) = &kwargs.cache_control {
- write = write.cache_control(cache_control);
- }
- if let Some(user_metadata) = kwargs.user_metadata.take() {
- write = write.user_metadata(user_metadata);
- }
-
- write.await.map(|_| ()).map_err(format_pyerr)
+ this.write_options(&path, bs, opts.into())
+ .await
+ .map(|_| ())
+ .map_err(format_pyerr)
})
}
- /// Get metadata for the current path **without cache** directly.
- #[pyo3(signature = (path, **kwargs))]
+ /// Get the metadata of a file at the given path.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
+ /// version : str, optional
+ /// The version of the file.
+ /// if_match : str, optional
+ /// The ETag of the file.
+ /// if_none_match : str, optional
+ /// The ETag of the file.
+ /// if_modified_since : datetime, optional
+ /// The last modified time of the file.
+ /// if_unmodified_since : datetime, optional
+ /// The last modified time of the file.
+ /// content_type : str, optional
+ /// The content type of the file.
+ /// cache_control : str, optional
+ /// The cache control of the file.
+ /// content_disposition : str, optional
+ /// The content disposition of the file.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// 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]",
+ imports=("collections.abc")
+ ))]
+ #[pyo3(signature = (path, *,
+ version=None,
+ if_match=None,
+ if_none_match=None,
+ if_modified_since=None,
+ if_unmodified_since=None,
+ content_type=None,
+ cache_control=None,
+ content_disposition=None))]
pub fn stat<'p>(
&'p self,
py: Python<'p>,
path: PathBuf,
- kwargs: Option<&Bound<PyDict>>,
+ version: Option<String>,
+ if_match: Option<String>,
+ if_none_match: Option<String>,
+ #[gen_stub(override_type(type_repr = "datetime.datetime",
imports=("datetime")))]
+ if_modified_since: Option<jiff::Timestamp>,
+ #[gen_stub(override_type(type_repr = "datetime.datetime",
imports=("datetime")))]
+ if_unmodified_since: Option<jiff::Timestamp>,
+ content_type: Option<String>,
+ cache_control: Option<String>,
+ content_disposition: Option<String>,
) -> PyResult<Bound<'p, PyAny>> {
let this = self.core.clone();
let path = path.to_string_lossy().to_string();
- let kwargs = kwargs
- .map(|v| v.extract::<StatOptions>())
- .transpose()?
- .unwrap_or_default();
+ let opts = StatOptions {
+ version,
+ if_match,
+ if_none_match,
+ if_modified_since,
+ if_unmodified_since,
+ content_type,
+ cache_control,
+ content_disposition,
+ };
future_into_py(py, async move {
let res: Metadata = this
- .stat_options(&path, kwargs.into())
+ .stat_options(&path, opts.into())
.await
.map_err(format_pyerr)
.map(Metadata::new)?;
@@ -498,7 +1122,23 @@ impl AsyncOperator {
})
}
- /// Copy source to target.``
+ /// Copy a file from one path to another.
+ ///
+ /// Parameters
+ /// ----------
+ /// source : str
+ /// The path to the source file.
+ /// target : str
+ /// The path to the target file.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that completes when the copy is finished.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[None]",
+ imports=("collections.abc")
+ ))]
pub fn copy<'p>(
&'p self,
py: Python<'p>,
@@ -513,7 +1153,23 @@ impl AsyncOperator {
})
}
- /// Rename filename
+ /// Rename (move) a file from one path to another.
+ ///
+ /// Parameters
+ /// ----------
+ /// source : str
+ /// The path to the source file.
+ /// target : str
+ /// The path to the target file.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that completes when the rename is finished.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[None]",
+ imports=("collections.abc")
+ ))]
pub fn rename<'p>(
&'p self,
py: Python<'p>,
@@ -528,7 +1184,21 @@ impl AsyncOperator {
})
}
- /// Remove all file
+ /// Recursively remove all files and directories at the given path.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to remove.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that completes when the removal is finished.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[None]",
+ imports=("collections.abc")
+ ))]
pub fn remove_all<'p>(&'p self, py: Python<'p>, path: PathBuf) ->
PyResult<Bound<'p, PyAny>> {
let this = self.core.clone();
let path = path.to_string_lossy().to_string();
@@ -537,24 +1207,46 @@ impl AsyncOperator {
})
}
- /// Check if this operator can work correctly.
+ /// Check if the operator is able to work correctly.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that completes when the check is finished.
+ ///
+ /// Raises
+ /// ------
+ /// Exception
+ /// If the operator is not able to work correctly.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[None]",
+ imports=("collections.abc")
+ ))]
pub fn check<'p>(&'p self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>> {
let this = self.core.clone();
future_into_py(py, async move {
this.check().await.map_err(format_pyerr) })
}
- /// Create a dir at given path.
+ /// Create a directory at the given path.
///
- /// # Notes
+ /// Notes
+ /// -----
+ /// To indicate that a path is a directory, it must end with a `/`.
+ /// This operation is always recursive, like `mkdir -p`.
///
- /// To indicate that a path is a directory, it is compulsory to include
- /// a trailing / in the path. Failure to do so may result in
- /// `NotADirectory` error being returned by OpenDAL.
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the directory.
///
- /// # Behavior
- ///
- /// - Create on existing dir will succeed.
- /// - Create dir is always recursive, works like `mkdir -p`
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that completes when the directory is created.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[None]",
+ imports=("collections.abc")
+ ))]
pub fn create_dir<'p>(&'p self, py: Python<'p>, path: PathBuf) ->
PyResult<Bound<'p, PyAny>> {
let this = self.core.clone();
let path = path.to_string_lossy().to_string();
@@ -563,11 +1255,25 @@ impl AsyncOperator {
})
}
- /// Delete given path.
+ /// Delete a file at the given path.
+ ///
+ /// Notes
+ /// -----
+ /// This operation will not return an error if the path does not exist.
///
- /// # Notes
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the file.
///
- /// - Delete not existing error won't return errors.
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that completes when the file is deleted.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[None]",
+ imports=("collections.abc")
+ ))]
pub fn delete<'p>(&'p self, py: Python<'p>, path: PathBuf) ->
PyResult<Bound<'p, PyAny>> {
let this = self.core.clone();
let path = path.to_string_lossy().to_string();
@@ -577,11 +1283,21 @@ impl AsyncOperator {
)
}
- /// Check given path is exists.
+ /// Check if a path exists.
///
- /// # Notes
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to check.
///
- /// - Check not existing path won't return errors.
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns True if the path exists, False otherwise.
+ #[gen_stub(override_return_type(
+ type_repr="collections.abc.Awaitable[builtins.bool]",
+ imports=("collections.abc", "builtins")
+ ))]
pub fn exists<'p>(&'p self, py: Python<'p>, path: PathBuf) ->
PyResult<Bound<'p, PyAny>> {
let this = self.core.clone();
let path = path.to_string_lossy().to_string();
@@ -591,24 +1307,58 @@ impl AsyncOperator {
)
}
- /// List current dir path.
- #[pyo3(signature = (path, **kwargs))]
+ /// List entries in the given directory.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the directory.
+ /// limit : int, optional
+ /// The maximum number of entries to return.
+ /// start_after : str, optional
+ /// The entry to start after.
+ /// recursive : bool, optional
+ /// Whether to list recursively.
+ /// versions : bool, optional
+ /// Whether to list versions.
+ /// deleted : bool, optional
+ /// Whether to list deleted entries.
+ ///
+ /// Returns
+ /// -------
+ /// 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]"))]
+ #[pyo3(signature = (path, *,
+ limit=None,
+ start_after=None,
+ recursive=None,
+ versions=None,
+ deleted=None))]
pub fn list<'p>(
&'p self,
py: Python<'p>,
path: PathBuf,
- kwargs: Option<&Bound<PyDict>>,
+ limit: Option<usize>,
+ start_after: Option<String>,
+ recursive: Option<bool>,
+ versions: Option<bool>,
+ deleted: Option<bool>,
) -> PyResult<Bound<'p, PyAny>> {
let this = self.core.clone();
let path = path.to_string_lossy().to_string();
- let kwargs = kwargs
- .map(|v| v.extract::<ListOptions>())
- .transpose()?
- .unwrap_or_default();
+ let opts = ListOptions {
+ limit,
+ start_after,
+ recursive,
+ versions,
+ deleted,
+ };
future_into_py(py, async move {
let lister = this
- .lister_options(&path, kwargs.into())
+ .lister_options(&path, opts.into())
.await
.map_err(format_pyerr)?;
let pylister = Python::attach(|py|
AsyncLister::new(lister).into_py_any(py))?;
@@ -617,22 +1367,62 @@ impl AsyncOperator {
})
}
- /// List dir in a flat way.
- #[pyo3(signature = (path, **kwargs))]
+ /// Recursively list entries in the given directory.
+ ///
+ /// Deprecated
+ /// ----------
+ /// Use `list()` with `recursive=True` instead.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path to the directory.
+ /// limit : int, optional
+ /// The maximum number of entries to return.
+ /// start_after : str, optional
+ /// The entry to start after.
+ /// versions : bool, optional
+ /// Whether to list versions.
+ /// deleted : bool, optional
+ /// Whether to list deleted entries.
+ ///
+ /// Returns
+ /// -------
+ /// 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(skip)]
+ #[pyo3(signature = (path, *,
+ limit=None,
+ start_after=None,
+ versions=None,
+ deleted=None))]
pub fn scan<'p>(
&'p self,
py: Python<'p>,
path: PathBuf,
- kwargs: Option<&Bound<PyDict>>,
+ limit: Option<usize>,
+ start_after: Option<String>,
+ versions: Option<bool>,
+ deleted: Option<bool>,
) -> PyResult<Bound<'p, PyAny>> {
- let d = PyDict::new(py);
- let kwargs = kwargs.unwrap_or(&d);
- kwargs.set_item("recursive", true)?;
-
- self.list(py, path, Some(kwargs))
+ self.list(py, path, limit, start_after, Some(true), versions, deleted)
}
- /// Presign an operation for stat(head) which expires after
`expire_second` seconds.
+ /// Create a presigned request for a stat operation.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path of the object to stat.
+ /// expire_second : int
+ /// The number of seconds until the presigned URL expires.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns a presigned request object.
+ #[gen_stub(override_return_type(type_repr = "types.PresignedRequest"))]
pub fn presign_stat<'p>(
&'p self,
py: Python<'p>,
@@ -652,7 +1442,20 @@ impl AsyncOperator {
})
}
- /// Presign an operation for read which expires after `expire_second`
seconds.
+ /// Create a presigned request for a read operation.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path of the object to read.
+ /// expire_second : int
+ /// The number of seconds until the presigned URL expires.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns a presigned request object.
+ #[gen_stub(override_return_type(type_repr = "types.PresignedRequest"))]
pub fn presign_read<'p>(
&'p self,
py: Python<'p>,
@@ -672,7 +1475,20 @@ impl AsyncOperator {
})
}
- /// Presign an operation for write which expires after `expire_second`
seconds.
+ /// Create a presigned request for a write operation.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path of the object to write to.
+ /// expire_second : int
+ /// The number of seconds until the presigned URL expires.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns a presigned request object.
+ #[gen_stub(override_return_type(type_repr = "types.PresignedRequest"))]
pub fn presign_write<'p>(
&'p self,
py: Python<'p>,
@@ -692,7 +1508,20 @@ impl AsyncOperator {
})
}
- /// Presign an operation for delete which expires after `expire_second`
seconds.
+ /// Create a presigned request for a delete operation.
+ ///
+ /// Parameters
+ /// ----------
+ /// path : str
+ /// The path of the object to delete.
+ /// expire_second : int
+ /// The number of seconds until the presigned URL expires.
+ ///
+ /// Returns
+ /// -------
+ /// coroutine
+ /// An awaitable that returns a presigned request object.
+ #[gen_stub(override_return_type(type_repr = "types.PresignedRequest"))]
pub fn presign_delete<'p>(
&'p self,
py: Python<'p>,
@@ -712,12 +1541,25 @@ impl AsyncOperator {
})
}
- pub fn capability(&self) -> PyResult<capability::Capability> {
+ /// Get all capabilities of this operator.
+ ///
+ /// Returns
+ /// -------
+ /// Capability
+ /// The capability of the operator.
+ #[gen_stub(override_return_type(type_repr = "capability.Capability"))]
+ pub fn full_capability(&self) -> PyResult<Capability> {
Ok(capability::Capability::new(
self.core.info().full_capability(),
))
}
+ /// Create a new blocking `Operator` from this async operator.
+ ///
+ /// Returns
+ /// -------
+ /// Operator
+ /// The blocking operator.
pub fn to_operator(&self) -> PyResult<Operator> {
let runtime = pyo3_async_runtimes::tokio::get_runtime();
let _guard = runtime.enter();
@@ -748,6 +1590,7 @@ impl AsyncOperator {
}
}
+ #[gen_stub(skip)]
fn __getnewargs_ex__(&self, py: Python) -> PyResult<Py<PyAny>> {
let args = vec![self.__scheme.to_string()];
let args = PyTuple::new(py, args)?.into_py_any(py)?;
@@ -756,24 +1599,35 @@ impl AsyncOperator {
}
}
-#[pyclass(module = "opendal")]
+/// A presigned request.
+///
+/// This contains the information required to make a request to the
+/// underlying service, including the URL, method, and headers.
+#[gen_stub_pyclass]
+#[pyclass(module = "opendal.types")]
pub struct PresignedRequest(ocore::raw::PresignedRequest);
+#[gen_stub_pymethods]
#[pymethods]
impl PresignedRequest {
- /// Return the URL of this request.
+ /// The URL of this request.
#[getter]
pub fn url(&self) -> String {
self.0.uri().to_string()
}
- /// Return the HTTP method of this request.
+ /// The HTTP method of this request.
#[getter]
pub fn method(&self) -> &str {
self.0.method().as_str()
}
- /// Return the HTTP headers of this request.
+ /// The HTTP headers of this request.
+ ///
+ /// Returns
+ /// -------
+ /// dict
+ /// The HTTP headers of this request.
#[getter]
pub fn headers(&self) -> PyResult<HashMap<&str, &str>> {
let mut headers = HashMap::new();
diff --git a/bindings/python/tests/conftest.py
b/bindings/python/tests/conftest.py
index 5bf32d545..38a689628 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.capability(), x) for x in marker.args]
- + [getattr(async_operator.capability(), x) for x in marker.args]
+ [getattr(operator.full_capability(), x) for x in marker.args]
+ + [getattr(async_operator.full_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 240816418..b22decdb4 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.capability()
+ cap = operator.full_capability()
assert cap is not None
assert cap.read is not None
def test_capability_exception(service_name, operator):
- cap = operator.capability()
+ cap = operator.full_capability()
assert cap is not None
with pytest.raises(AttributeError):
_ = cap.read_demo