Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pyo3-object_store/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [0.10.0] - 2026-02-09

- Compatibility release with pyo3 0.28 and object_store 0.12.

## [0.9.0] - 2026-02-09

- Bump to pyo3 0.28.
Expand Down
4 changes: 2 additions & 2 deletions pyo3-object_store/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyo3-object_store"
version = "0.9.0"
version = "0.10.0"
authors = ["Kyle Barron <kyle@developmentseed.org>"]
edition = "2021"
description = "object_store integration for pyo3."
Expand Down Expand Up @@ -28,7 +28,7 @@ humantime = "2.1"
http = "1"
# This is already an object_store dependency
itertools = "0.14.0"
object_store = { version = "0.13.0", features = [
object_store = { version = "0.12.0", features = [
"aws",
"azure",
"gcp",
Expand Down
3 changes: 2 additions & 1 deletion pyo3-object_store/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,6 @@ We don't yet have a _great_ solution here for reusing the store builder type hin
| 0.7.x | 0.27 | 0.12 |
| 0.8.x | 0.27 | 0.13 |
| 0.9.x | 0.28 | 0.13 |
| 0.10.x | 0.28 | **0.12** :warning: |

Note that 0.3.x and 0.4.x are compatibility releases to use `pyo3-object_store` with older versions of `pyo3` and `object_store`.
Note that :warning: signifies compatibility releases to use `pyo3-object_store` with older versions of `pyo3` and/or `object_store`.
7 changes: 3 additions & 4 deletions pyo3-object_store/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,9 @@ impl From<PyObjectStoreError> for PyErr {
object_store::Error::NotModified { path: _, source: _ } => {
NotModifiedError::new_err(print_with_debug(err))
}
object_store::Error::NotImplemented {
operation: _,
implementer: _,
} => PyNotImplementedError::new_err(print_with_debug(err)),
object_store::Error::NotImplemented => {
PyNotImplementedError::new_err(print_with_debug(err))
}
object_store::Error::PermissionDenied { path: _, source: _ } => {
PermissionDeniedError::new_err(print_with_debug(err))
}
Expand Down
70 changes: 57 additions & 13 deletions pyo3-object_store/src/prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ use std::borrow::Cow;
use std::ops::Range;
use std::sync::OnceLock;

use object_store::{path::Path, CopyOptions};
use object_store::path::Path;
// Remove when updating to object_store 0.13
#[allow(deprecated)]
use object_store::{
GetOptions, GetResult, ListResult, MultipartUpload, ObjectMeta, ObjectStore,
PutMultipartOptions, PutOptions, PutPayload, PutResult, Result,
GetOptions, GetResult, ListResult, MultipartUpload, ObjectMeta, ObjectStore, PutMultipartOpts,
PutOptions, PutPayload, PutResult, Result,
};

static DEFAULT_PATH: OnceLock<Path> = OnceLock::new();
Expand Down Expand Up @@ -110,6 +112,11 @@ fn strip_meta(prefix: Option<&Path>, meta: ObjectMeta) -> ObjectMeta {
}
#[async_trait::async_trait]
impl<T: ObjectStore> ObjectStore for MaybePrefixedStore<T> {
async fn put(&self, location: &Path, payload: PutPayload) -> Result<PutResult> {
let full_path = self.full_path(location);
self.inner.put(&full_path, payload).await
}

async fn put_opts(
&self,
location: &Path,
Expand All @@ -120,17 +127,32 @@ impl<T: ObjectStore> ObjectStore for MaybePrefixedStore<T> {
self.inner.put_opts(&full_path, payload, opts).await
}

async fn put_multipart(&self, location: &Path) -> Result<Box<dyn MultipartUpload>> {
let full_path = self.full_path(location);
self.inner.put_multipart(&full_path).await
}

// Remove when updating to object_store 0.13
#[allow(deprecated)]
async fn put_multipart_opts(
&self,
location: &Path,
opts: PutMultipartOptions,
opts: PutMultipartOpts,
) -> Result<Box<dyn MultipartUpload>> {
let full_path = self.full_path(location);
self.inner.put_multipart_opts(&full_path, opts).await
}

async fn get(&self, location: &Path) -> Result<GetResult> {
let full_path = self.full_path(location);
self.inner.get(&full_path).await
}

async fn get_range(&self, location: &Path, range: Range<u64>) -> Result<Bytes> {
let full_path = self.full_path(location);
self.inner.get_range(&full_path, range).await
}

async fn get_opts(&self, location: &Path, options: GetOptions) -> Result<GetResult> {
let full_path = self.full_path(location);
self.inner.get_opts(&full_path, options).await
Expand All @@ -141,6 +163,17 @@ impl<T: ObjectStore> ObjectStore for MaybePrefixedStore<T> {
self.inner.get_ranges(&full_path, ranges).await
}

async fn head(&self, location: &Path) -> Result<ObjectMeta> {
let full_path = self.full_path(location);
let meta = self.inner.head(&full_path).await?;
Ok(self.strip_meta(meta))
}

async fn delete(&self, location: &Path) -> Result<()> {
let full_path = self.full_path(location);
self.inner.delete(&full_path).await
}

fn list(&self, prefix: Option<&Path>) -> BoxStream<'static, Result<ObjectMeta>> {
let prefix = self.full_path(prefix.unwrap_or(DEFAULT_PATH.get_or_init(Path::default)));
let s = self.inner.list(Some(&prefix));
Expand Down Expand Up @@ -181,16 +214,27 @@ impl<T: ObjectStore> ObjectStore for MaybePrefixedStore<T> {
})
}

async fn copy_opts(&self, from: &Path, to: &Path, options: CopyOptions) -> Result<()> {
let from_full = self.full_path(from);
let to_full = self.full_path(to);
self.inner.copy_opts(&from_full, &to_full, options).await
async fn copy(&self, from: &Path, to: &Path) -> Result<()> {
let full_from = self.full_path(from);
let full_to = self.full_path(to);
self.inner.copy(&full_from, &full_to).await
}

fn delete_stream(
&self,
locations: BoxStream<'static, Result<Path>>,
) -> BoxStream<'static, Result<Path>> {
self.inner.delete_stream(locations)
async fn rename(&self, from: &Path, to: &Path) -> Result<()> {
let full_from = self.full_path(from);
let full_to = self.full_path(to);
self.inner.rename(&full_from, &full_to).await
}

async fn copy_if_not_exists(&self, from: &Path, to: &Path) -> Result<()> {
let full_from = self.full_path(from);
let full_to = self.full_path(to);
self.inner.copy_if_not_exists(&full_from, &full_to).await
}

async fn rename_if_not_exists(&self, from: &Path, to: &Path) -> Result<()> {
let full_from = self.full_path(from);
let full_to = self.full_path(to);
self.inner.rename_if_not_exists(&full_from, &full_to).await
}
}
Loading