Skip to content

Commit 1e240da

Browse files
committed
Updated put docs
1 parent eb25002 commit 1e240da

File tree

2 files changed

+44
-10
lines changed

2 files changed

+44
-10
lines changed

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ Simple, fast integration with object storage services like Amazon S3, Google Clo
1212

1313
- Sync and async API.
1414
- Streaming downloads with configurable chunking.
15+
- Streaming uploads from async or sync iterators.
1516
- Streaming `list`, with no need to paginate.
1617
- File-like object API and [fsspec](https://github.com/fsspec/filesystem_spec) integration.
1718
- Support for conditional put ("put if not exists"), as well as custom tags and attributes.
1819
- Automatically uses [multipart uploads](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html) under the hood for large file objects.
1920
- Optionally return list results as [Arrow](https://arrow.apache.org/), which is faster than materializing Python `dict`/`list` objects.
2021
- Easy to install with no required Python dependencies.
2122
- The [underlying Rust library](https://docs.rs/object_store) is production quality and used in large scale production systems, such as the Rust package registry [crates.io](https://crates.io/).
22-
- Support for zero-copy data exchange from Rust into Python in `get_range` and `get_ranges`.
23+
- Zero-copy data exchange between Rust and Python in `get_range`, `get_ranges`, and `put` via the Python buffer protocol.
2324
- Simple API with static type checking.
2425
- Helpers for constructing from environment variables and `boto3.Session` objects
2526

@@ -56,6 +57,10 @@ Classes to construct a store are exported from the `obstore.store` submodule:
5657
- [`LocalStore`](https://developmentseed.org/obstore/latest/api/store/local/): Local filesystem storage providing the same object store interface.
5758
- [`MemoryStore`](https://developmentseed.org/obstore/latest/api/store/memory/): A fully in-memory implementation of ObjectStore.
5859

60+
Additionally, some middlewares exist:
61+
62+
- [`PrefixStore`](https://developmentseed.org/obstore/latest/api/store/middleware/#obstore.store.PrefixStore): Store wrapper that applies a constant prefix to all paths handled by the store.
63+
5964
#### Example
6065

6166
```py
@@ -81,7 +86,7 @@ All methods for interacting with a store are exported as **top-level functions**
8186
- [`get`](https://developmentseed.org/obstore/latest/api/get/): Return the bytes that are stored at the specified location.
8287
- [`head`](https://developmentseed.org/obstore/latest/api/head/): Return the metadata for the specified location
8388
- [`list`](https://developmentseed.org/obstore/latest/api/list/): List all the objects with the given prefix.
84-
- [`put`](https://developmentseed.org/obstore/latest/api/put/): Save the provided bytes to the specified location
89+
- [`put`](https://developmentseed.org/obstore/latest/api/put/): Save the provided buffer to the specified location.
8590
- [`rename`](https://developmentseed.org/obstore/latest/api/rename/): Move an object from one path to another in the same object store.
8691

8792
There are a few additional APIs useful for specific use cases:

obstore/python/obstore/_put.pyi

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from pathlib import Path
23
from typing import (
34
IO,
@@ -13,6 +14,11 @@ from typing import (
1314
from ._attributes import Attributes
1415
from .store import ObjectStore
1516

17+
if sys.version_info >= (3, 12):
18+
from collections.abc import Buffer
19+
else:
20+
from typing_extensions import Buffer
21+
1622
class UpdateVersion(TypedDict, total=False):
1723
"""
1824
Uniquely identifies a version of an object to update
@@ -62,7 +68,7 @@ class PutResult(TypedDict):
6268
def put(
6369
store: ObjectStore,
6470
path: str,
65-
file: IO[bytes] | Path | bytes | Iterator[bytes] | Iterable[bytes],
71+
file: IO[bytes] | Path | bytes | Buffer | Iterator[Buffer] | Iterable[Buffer],
6672
*,
6773
attributes: Attributes | None = None,
6874
tags: Dict[str, str] | None = None,
@@ -80,8 +86,16 @@ def put(
8086
Args:
8187
store: The ObjectStore instance to use.
8288
path: The path within ObjectStore for where to save the file.
83-
file: The object to upload. Can either be file-like, a `Path` to a local file,
84-
or a `bytes` object.
89+
file: The object to upload. Supports various input:
90+
91+
- A file-like object opened in binary read mode
92+
- A [`Path`][pathlib.Path] to a local file
93+
- A [`bytes`][] object.
94+
- Any object implementing the Python [buffer
95+
protocol](https://docs.python.org/3/c-api/buffer.html) (includes `bytes`
96+
but also `memoryview`, numpy arrays, and more).
97+
- An iterator or iterable of objects implementing the Python buffer
98+
protocol.
8599
86100
Keyword args:
87101
mode: Configure the `PutMode` for this operation. If this provided and is not `"overwrite"`, a non-multipart upload will be performed. Defaults to `"overwrite"`.
@@ -98,10 +112,11 @@ async def put_async(
98112
file: IO[bytes]
99113
| Path
100114
| bytes
101-
| AsyncIterator[bytes]
102-
| AsyncIterable[bytes]
103-
| Iterator[bytes]
104-
| Iterable[bytes],
115+
| Buffer
116+
| AsyncIterator[Buffer]
117+
| AsyncIterable[Buffer]
118+
| Iterator[Buffer]
119+
| Iterable[Buffer],
105120
*,
106121
attributes: Attributes | None = None,
107122
tags: Dict[str, str] | None = None,
@@ -112,5 +127,19 @@ async def put_async(
112127
) -> PutResult:
113128
"""Call `put` asynchronously.
114129
115-
Refer to the documentation for [put][obstore.put].
130+
Refer to the documentation for [`put`][obstore.put]. In addition to what the
131+
synchronous `put` allows for the `file` parameter, this **also supports an async
132+
iterator or iterable** of objects implementing the Python buffer protocol.
133+
134+
This means, for example, you can pass the result of `get_async` directly to
135+
`put_async`, and the request will be streamed through Python during the put
136+
operation:
137+
138+
```py
139+
import obstore as obs
140+
141+
# This only constructs the stream, it doesn't materialize the data in memory
142+
resp = await obs.get_async(store1, path1)
143+
await obs.put_async(store2, path2)
144+
```
116145
"""

0 commit comments

Comments
 (0)