Skip to content

Commit

Permalink
Consolidate rename/rename_if_not_exists, copy/`copy_if_not_exis…
Browse files Browse the repository at this point in the history
…ts` (#18)

* Consolidate copy/rename if not exists

* fix lib
  • Loading branch information
kylebarron authored Oct 21, 2024
1 parent eb8d699 commit 902fd55
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 132 deletions.
39 changes: 12 additions & 27 deletions object-store-rs/python/object_store_rs/_copy.pyi
Original file line number Diff line number Diff line change
@@ -1,41 +1,26 @@
from .store import ObjectStore

def copy(store: ObjectStore, from_: str, to: str) -> None:
def copy(store: ObjectStore, from_: str, to: str, *, overwrite: bool = True) -> None:
"""Copy an object from one path to another in the same object store.
If there exists an object at the destination, it will be overwritten.
Args:
store: The ObjectStore instance to use.
from_: Source path
to: Destination path
"""

async def copy_async(store: ObjectStore, from_: str, to: str) -> None:
"""Call `copy` asynchronously.
Refer to the documentation for [copy][object_store_rs.copy].
"""

def copy_if_not_exists(store: ObjectStore, from_: str, to: str) -> None:
"""
Copy an object from one path to another, only if destination is empty.
Will return an error if the destination already has an object.
Performs an atomic operation if the underlying object storage supports it.
If atomic operations are not supported by the underlying object storage (like S3)
it will return an error.
Keyword Args:
overwrite: If `True`, if there exists an object at the destination, it will
be overwritten. Performs an atomic operation if the underlying object
storage supports it. If atomic operations are not supported by the
underlying object storage (like S3) it will return an error.
Args:
store: The ObjectStore instance to use.
from_: Source path
to: Destination path
If `False`, will return an error if the destination already has an object.
"""

async def copy_if_not_exists_async(store: ObjectStore, from_: str, to: str) -> None:
"""Call `copy_if_not_exists` asynchronously.
async def copy_async(
store: ObjectStore, from_: str, to: str, *, overwrite: bool = True
) -> None:
"""Call `copy` asynchronously.
Refer to the documentation for
[copy_if_not_exists][object_store_rs.copy_if_not_exists].
Refer to the documentation for [copy][object_store_rs.copy].
"""
32 changes: 9 additions & 23 deletions object-store-rs/python/object_store_rs/_rename.pyi
Original file line number Diff line number Diff line change
@@ -1,41 +1,27 @@
from .store import ObjectStore

def rename(store: ObjectStore, from_: str, to: str) -> None:
def rename(store: ObjectStore, from_: str, to: str, *, overwrite: bool = True) -> None:
"""
Move an object from one path to another in the same object store.
By default, this is implemented as a copy and then delete source. It may not check
when deleting source that it was the same object that was originally copied.
If there exists an object at the destination, it will be overwritten.
Args:
store: The ObjectStore instance to use.
from_: Source path
to: Destination path
Keyword Args:
overwrite: If `True`, if there exists an object at the destination, it will be
overwritten. If `False`, will return an error if the destination already has
an object.
"""

async def rename_async(store: ObjectStore, from_: str, to: str) -> None:
async def rename_async(
store: ObjectStore, from_: str, to: str, *, overwrite: bool = True
) -> None:
"""Call `rename` asynchronously.
Refer to the documentation for [rename][object_store_rs.rename].
"""

def rename_if_not_exists(store: ObjectStore, from_: str, to: str) -> None:
"""
Move an object from one path to another in the same object store.
Will return an error if the destination already has an object.
Args:
store: The ObjectStore instance to use.
from_: Source path
to: Destination path
"""

async def rename_if_not_exists_async(store: ObjectStore, from_: str, to: str) -> None:
"""Call `rename_if_not_exists` asynchronously.
Refer to the documentation for
[rename_if_not_exists][object_store_rs.rename_if_not_exists].
"""
57 changes: 20 additions & 37 deletions object-store-rs/src/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,46 @@ use pyo3_object_store::PyObjectStore;
use crate::runtime::get_runtime;

#[pyfunction]
#[pyo3(signature = (store, from_, to, *, overwrite = true))]
pub(crate) fn copy(
py: Python,
store: PyObjectStore,
from_: String,
to: String,
overwrite: bool,
) -> PyObjectStoreResult<()> {
let runtime = get_runtime(py)?;
let from_ = from_.into();
let to = to.into();
py.allow_threads(|| {
runtime.block_on(store.as_ref().copy(&from_.into(), &to.into()))?;
let fut = if overwrite {
store.as_ref().copy(&from_, &to)
} else {
store.as_ref().copy_if_not_exists(&from_, &to)
};
runtime.block_on(fut)?;
Ok::<_, PyObjectStoreError>(())
})
}

#[pyfunction]
#[pyo3(signature = (store, from_, to, *, overwrite = true))]
pub(crate) fn copy_async(
py: Python,
store: PyObjectStore,
from_: String,
to: String,
overwrite: bool,
) -> PyResult<Bound<PyAny>> {
let from_ = from_.into();
let to = to.into();
pyo3_async_runtimes::tokio::future_into_py(py, async move {
store
.as_ref()
.copy(&from_.into(), &to.into())
.await
.map_err(PyObjectStoreError::ObjectStoreError)?;
Ok(())
})
}

#[pyfunction]
pub(crate) fn copy_if_not_exists(
py: Python,
store: PyObjectStore,
from_: String,
to: String,
) -> PyObjectStoreResult<()> {
let runtime = get_runtime(py)?;
py.allow_threads(|| {
runtime.block_on(store.as_ref().copy_if_not_exists(&from_.into(), &to.into()))?;
Ok::<_, PyObjectStoreError>(())
})
}

#[pyfunction]
pub(crate) fn copy_if_not_exists_async(
py: Python,
store: PyObjectStore,
from_: String,
to: String,
) -> PyResult<Bound<PyAny>> {
pyo3_async_runtimes::tokio::future_into_py(py, async move {
store
.as_ref()
.copy_if_not_exists(&from_.into(), &to.into())
.await
.map_err(PyObjectStoreError::ObjectStoreError)?;
let fut = if overwrite {
store.as_ref().copy(&from_, &to)
} else {
store.as_ref().copy_if_not_exists(&from_, &to)
};
fut.await.map_err(PyObjectStoreError::ObjectStoreError)?;
Ok(())
})
}
4 changes: 0 additions & 4 deletions object-store-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ fn _object_store_rs(py: Python, m: &Bound<PyModule>) -> PyResult<()> {
pyo3_object_store::register_store_module(py, m, "object_store_rs")?;

m.add_wrapped(wrap_pyfunction!(copy::copy_async))?;
m.add_wrapped(wrap_pyfunction!(copy::copy_if_not_exists_async))?;
m.add_wrapped(wrap_pyfunction!(copy::copy_if_not_exists))?;
m.add_wrapped(wrap_pyfunction!(copy::copy))?;
m.add_wrapped(wrap_pyfunction!(delete::delete_async))?;
m.add_wrapped(wrap_pyfunction!(delete::delete))?;
Expand All @@ -45,8 +43,6 @@ fn _object_store_rs(py: Python, m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(put::put_file_async))?;
m.add_wrapped(wrap_pyfunction!(put::put_file))?;
m.add_wrapped(wrap_pyfunction!(rename::rename_async))?;
m.add_wrapped(wrap_pyfunction!(rename::rename_if_not_exists_async))?;
m.add_wrapped(wrap_pyfunction!(rename::rename_if_not_exists))?;
m.add_wrapped(wrap_pyfunction!(rename::rename))?;
m.add_wrapped(wrap_pyfunction!(signer::sign_url_async))?;
m.add_wrapped(wrap_pyfunction!(signer::sign_url))?;
Expand Down
61 changes: 20 additions & 41 deletions object-store-rs/src/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,46 @@ use pyo3_object_store::PyObjectStore;
use crate::runtime::get_runtime;

#[pyfunction]
#[pyo3(signature = (store, from_, to, *, overwrite = true))]
pub(crate) fn rename(
py: Python,
store: PyObjectStore,
from_: String,
to: String,
overwrite: bool,
) -> PyObjectStoreResult<()> {
let runtime = get_runtime(py)?;
let from_ = from_.into();
let to = to.into();
py.allow_threads(|| {
runtime.block_on(store.as_ref().rename(&from_.into(), &to.into()))?;
let fut = if overwrite {
store.as_ref().rename(&from_, &to)
} else {
store.as_ref().rename_if_not_exists(&from_, &to)
};
runtime.block_on(fut)?;
Ok::<_, PyObjectStoreError>(())
})
}

#[pyfunction]
#[pyo3(signature = (store, from_, to, *, overwrite = true))]
pub(crate) fn rename_async(
py: Python,
store: PyObjectStore,
from_: String,
to: String,
overwrite: bool,
) -> PyResult<Bound<PyAny>> {
let from_ = from_.into();
let to = to.into();
pyo3_async_runtimes::tokio::future_into_py(py, async move {
store
.as_ref()
.rename(&from_.into(), &to.into())
.await
.map_err(PyObjectStoreError::ObjectStoreError)?;
Ok(())
})
}

#[pyfunction]
pub(crate) fn rename_if_not_exists(
py: Python,
store: PyObjectStore,
from_: String,
to: String,
) -> PyObjectStoreResult<()> {
let runtime = get_runtime(py)?;
py.allow_threads(|| {
runtime.block_on(
store
.as_ref()
.rename_if_not_exists(&from_.into(), &to.into()),
)?;
Ok::<_, PyObjectStoreError>(())
})
}

#[pyfunction]
pub(crate) fn rename_if_not_exists_async(
py: Python,
store: PyObjectStore,
from_: String,
to: String,
) -> PyResult<Bound<PyAny>> {
pyo3_async_runtimes::tokio::future_into_py(py, async move {
store
.as_ref()
.rename_if_not_exists(&from_.into(), &to.into())
.await
.map_err(PyObjectStoreError::ObjectStoreError)?;
let fut = if overwrite {
store.as_ref().rename(&from_, &to)
} else {
store.as_ref().rename_if_not_exists(&from_, &to)
};
fut.await.map_err(PyObjectStoreError::ObjectStoreError)?;
Ok(())
})
}

0 comments on commit 902fd55

Please sign in to comment.