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: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Changelog

## [0.5.0] - 2025-03-10
## [0.5.0] - XXXX-XX-XX

### New Features :magic_wand:

Expand All @@ -16,6 +16,8 @@

### Breaking changes :wrench:

- `obstore.exceptions` moved to `obspec.exceptions`

#### Object store methods

No breaking changes.
Expand Down
3 changes: 0 additions & 3 deletions docs/api/exceptions.md

This file was deleted.

1 change: 0 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ nav:
- api/put.md
- api/rename.md
- api/sign.md
- api/exceptions.md
- api/file.md
- obstore.fsspec: api/fsspec.md
- Advanced Topics:
Expand Down
2 changes: 1 addition & 1 deletion obstore/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "maturin"
[project]
name = "obstore"
requires-python = ">=3.9"
dependencies = []
dependencies = ["obspec>=0.1.0-beta.3"]
classifiers = [
"Programming Language :: Rust",
"Programming Language :: Python :: Implementation :: CPython",
Expand Down
5 changes: 1 addition & 4 deletions obstore/python/obstore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,14 @@
)

if TYPE_CHECKING:
from . import _store, exceptions
from . import _exceptions, _store
from ._obstore import (
HTTP_METHOD,
AsyncReadableFile,
AsyncWritableFile,
Bytes,
BytesStream,
GetResult,
ListChunkType,
ListResult,
ListStream,
ReadableFile,
SignCapableStore,
WritableFile,
Expand Down
1 change: 1 addition & 0 deletions obstore/python/obstore/_obstore.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import _exceptions as _exceptions
from . import _store as _store
from ._buffered import AsyncReadableFile as AsyncReadableFile
from ._buffered import AsyncWritableFile as AsyncWritableFile
Expand Down
69 changes: 69 additions & 0 deletions obstore/python/obstore/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Exceptions."""

import obspec.exceptions as obspec_exc

from obstore._obstore import _exceptions as pyo3_exc


class BaseError(obspec_exc.BaseError, pyo3_exc.BaseError):
"""The base Python-facing exception from which all other errors subclass."""


class GenericError(obspec_exc.GenericError, pyo3_exc.GenericError):
"""A fallback error type when no variant matches."""


class NotFoundError(obspec_exc.NotFoundError, pyo3_exc.NotFoundError):
"""Error when the object is not found at given location."""


class InvalidPathError(obspec_exc.InvalidPathError, pyo3_exc.InvalidPathError):
"""Error for invalid path."""


class JoinError(obspec_exc.JoinError, pyo3_exc.JoinError):
"""Error when tokio::spawn failed."""


class NotSupportedError(obspec_exc.NotSupportedError, pyo3_exc.NotSupportedError):
"""Error when the attempted operation is not supported."""


class AlreadyExistsError(obspec_exc.AlreadyExistsError, pyo3_exc.AlreadyExistsError):
"""Error when the object already exists."""


class PreconditionError(obspec_exc.PreconditionError, pyo3_exc.PreconditionError):
"""Error when the required conditions failed for the operation."""


class NotModifiedError(obspec_exc.NotModifiedError, pyo3_exc.NotModifiedError):
"""Error when the object at the location isn't modified."""


class NotImplementedError(obspec_exc.NotImplementedError): # noqa: A001
"""Error when an operation is not implemented.

Subclasses from the built-in [NotImplementedError][].
"""


class PermissionDeniedError(
obspec_exc.PermissionDeniedError,
pyo3_exc.PermissionDeniedError,
):
"""Error when the used credentials don't have enough permission to perform the requested operation.""" # noqa: E501


class UnauthenticatedError(
obspec_exc.UnauthenticatedError,
pyo3_exc.UnauthenticatedError,
):
"""Error when the used credentials lack valid authentication."""


class UnknownConfigurationKeyError(
obspec_exc.UnknownConfigurationKeyError,
pyo3_exc.UnknownConfigurationKeyError,
):
"""Error when a configuration key is invalid for the store used."""
14 changes: 8 additions & 6 deletions obstore/python/obstore/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Literal, TypeAlias, Unpack, overload
from typing import TYPE_CHECKING, Any, Literal, Self, TypeAlias, Unpack, overload

import obspec

import obstore as obs
from obstore._obstore import _store
from obstore._obstore import _exceptions, _store
from obstore._obstore import parse_scheme as _parse_scheme
from obstore.exceptions import BaseError
from obstore.exceptions import GenericError

if TYPE_CHECKING:
import sys
Expand Down Expand Up @@ -703,7 +705,7 @@ def from_url( # noqa: C901
if scheme == "http":
if config or kwargs:
msg = "HTTPStore does not accept any configuration"
raise BaseError(msg)
raise GenericError(msg)

return HTTPStore.from_url(
url,
Expand All @@ -726,9 +728,9 @@ def from_url( # noqa: C901
if scheme == "memory":
if config or kwargs:
msg = "MemoryStore does not accept any configuration"
raise BaseError(msg)
raise GenericError(msg)

return MemoryStore()

msg = f"Unknown scheme: {url}"
raise BaseError(msg)
raise GenericError(msg)
17 changes: 9 additions & 8 deletions obstore/src/buffered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ use pyo3::types::PyString;
use pyo3::{intern, IntoPyObjectExt};
use pyo3_async_runtimes::tokio::future_into_py;
use pyo3_bytes::PyBytes;
use pyo3_object_store::{PyObjectStore, PyObjectStoreError, PyObjectStoreResult};
use pyo3_object_store::PyObjectStore;
use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt, Lines};
use tokio::sync::Mutex;

use crate::attributes::PyAttributes;
use crate::error::{PyObstoreError, PyObstoreResult};
use crate::list::PyObjectMeta;
use crate::runtime::get_runtime;
use crate::tags::PyTagSet;
Expand All @@ -26,7 +27,7 @@ pub(crate) fn open_reader(
store: PyObjectStore,
path: String,
buffer_size: usize,
) -> PyObjectStoreResult<PyReadableFile> {
) -> PyObstoreResult<PyReadableFile> {
let store = store.into_inner();
let runtime = get_runtime(py)?;
let (reader, meta) =
Expand All @@ -53,11 +54,11 @@ async fn create_reader(
store: Arc<dyn ObjectStore>,
path: String,
capacity: usize,
) -> PyObjectStoreResult<(BufReader, ObjectMeta)> {
) -> PyObstoreResult<(BufReader, ObjectMeta)> {
let meta = store
.head(&path.into())
.await
.map_err(PyObjectStoreError::ObjectStoreError)?;
.map_err(PyObstoreError::from)?;
Ok((BufReader::with_capacity(store, &meta, capacity), meta))
}

Expand All @@ -82,7 +83,7 @@ impl PyReadableFile {
impl PyReadableFile {
// Note: to enable this, we'd have to make the PyReadableFile contain an `Option<>` that here
// we could move out.
// async fn __aiter__(&mut self) -> PyObjectStoreResult<PyLinesReader> {
// async fn __aiter__(&mut self) -> PyObstoreResult<PyLinesReader> {
// let reader = self.reader.clone();
// let reader = reader.lock().await;
// let lines = reader.lines();
Expand Down Expand Up @@ -293,7 +294,7 @@ pub(crate) fn open_writer(
buffer_size: usize,
tags: Option<PyTagSet>,
max_concurrency: usize,
) -> PyObjectStoreResult<PyWritableFile> {
) -> PyObstoreResult<PyWritableFile> {
Ok(PyWritableFile::new(
create_writer(store, path, attributes, buffer_size, tags, max_concurrency),
false,
Expand Down Expand Up @@ -477,7 +478,7 @@ async fn abort_writer(writer: Arc<Mutex<Option<BufWriter>>>) -> PyResult<()> {
let mut writer = writer
.take()
.ok_or(PyIOError::new_err("Writer already closed."))?;
writer.abort().await.map_err(PyObjectStoreError::from)?;
writer.abort().await.map_err(PyObstoreError::from)?;
Ok(())
}

Expand Down Expand Up @@ -506,6 +507,6 @@ async fn write(writer: Arc<Mutex<Option<BufWriter>>>, buffer: PyBytes) -> PyResu
.ok_or(PyIOError::new_err("Writer already closed."))?;
let buffer = buffer.into_inner();
let buffer_length = buffer.len();
writer.put(buffer).await.map_err(PyObjectStoreError::from)?;
writer.put(buffer).await.map_err(PyObstoreError::from)?;
Ok(buffer_length)
}
9 changes: 5 additions & 4 deletions obstore/src/copy.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use object_store::ObjectStore;
use pyo3::prelude::*;
use pyo3_object_store::{PyObjectStore, PyObjectStoreError, PyObjectStoreResult};
use pyo3_object_store::PyObjectStore;

use crate::error::{PyObstoreError, PyObstoreResult};
use crate::runtime::get_runtime;
use crate::utils::PyNone;

Expand All @@ -13,7 +14,7 @@ pub(crate) fn copy(
from_: String,
to: String,
overwrite: bool,
) -> PyObjectStoreResult<()> {
) -> PyObstoreResult<()> {
let runtime = get_runtime(py)?;
let from_ = from_.into();
let to = to.into();
Expand All @@ -24,7 +25,7 @@ pub(crate) fn copy(
store.as_ref().copy_if_not_exists(&from_, &to)
};
runtime.block_on(fut)?;
Ok::<_, PyObjectStoreError>(())
Ok::<_, PyObstoreError>(())
})
}

Expand All @@ -45,7 +46,7 @@ pub(crate) fn copy_async(
} else {
store.as_ref().copy_if_not_exists(&from_, &to)
};
fut.await.map_err(PyObjectStoreError::ObjectStoreError)?;
fut.await.map_err(PyObstoreError::from)?;
Ok(PyNone)
})
}
14 changes: 6 additions & 8 deletions obstore/src/delete.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use futures::{StreamExt, TryStreamExt};
use pyo3::prelude::*;
use pyo3_object_store::{PyObjectStore, PyObjectStoreError, PyObjectStoreResult};
use pyo3_object_store::PyObjectStore;

use crate::error::{PyObstoreError, PyObstoreResult};
use crate::path::PyPaths;
use crate::runtime::get_runtime;
use crate::utils::PyNone;

#[pyfunction]
pub(crate) fn delete(py: Python, store: PyObjectStore, paths: PyPaths) -> PyObjectStoreResult<()> {
pub(crate) fn delete(py: Python, store: PyObjectStore, paths: PyPaths) -> PyObstoreResult<()> {
let runtime = get_runtime(py)?;
let store = store.into_inner();
py.allow_threads(|| {
Expand All @@ -22,7 +23,7 @@ pub(crate) fn delete(py: Python, store: PyObjectStore, paths: PyPaths) -> PyObje
runtime.block_on(stream.try_collect::<Vec<_>>())?;
}
};
Ok::<_, PyObjectStoreError>(())
Ok::<_, PyObstoreError>(())
})
}

Expand All @@ -36,10 +37,7 @@ pub(crate) fn delete_async(
pyo3_async_runtimes::tokio::future_into_py(py, async move {
match paths {
PyPaths::One(path) => {
store
.delete(&path)
.await
.map_err(PyObjectStoreError::ObjectStoreError)?;
store.delete(&path).await.map_err(PyObstoreError::from)?;
}
PyPaths::Many(paths) => {
// TODO: add option to allow some errors here?
Expand All @@ -48,7 +46,7 @@ pub(crate) fn delete_async(
stream
.try_collect::<Vec<_>>()
.await
.map_err(PyObjectStoreError::ObjectStoreError)?;
.map_err(PyObstoreError::from)?;
}
}
Ok(PyNone)
Expand Down
Loading
Loading