icechunk 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {icechunk-0.2.2 → icechunk-0.2.4}/PKG-INFO +2 -2
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/Cargo.toml +1 -1
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/config.rs +13 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/repository.rs +10 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/storage/logging.rs +7 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/storage/mod.rs +19 -2
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/storage/object_store.rs +87 -3
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/storage/s3.rs +55 -13
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/Cargo.toml +2 -2
- icechunk-0.2.4/icechunk-python/examples/mpwrite.py +48 -0
- {icechunk-0.2.2 → icechunk-0.2.4/icechunk-python}/python/icechunk/__init__.py +18 -0
- {icechunk-0.2.2 → icechunk-0.2.4/icechunk-python}/python/icechunk/_icechunk_python.pyi +4 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/repository.py +10 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/src/config.rs +4 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/src/repository.rs +24 -0
- icechunk-0.2.4/icechunk-python/tests/test_debuginfo.py +6 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_pickle.py +12 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/pyproject.toml +1 -1
- {icechunk-0.2.2/icechunk-python → icechunk-0.2.4}/python/icechunk/__init__.py +18 -0
- {icechunk-0.2.2/icechunk-python → icechunk-0.2.4}/python/icechunk/_icechunk_python.pyi +4 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/repository.py +10 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/examples/low_level_dataset.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/examples/multithreaded_get_chunk_refs.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/examples/multithreaded_store.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/flatbuffers/all.fbs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/flatbuffers/manifest.fbs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/flatbuffers/object_ids.fbs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/flatbuffers/snapshot.fbs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/flatbuffers/transaction_log.fbs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/proptest-regressions/dataset.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/proptest-regressions/format/manifest.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/proptest-regressions/manifest.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/proptest-regressions/session.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/proptest-regressions/storage/mod.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/proptest-regressions/storage/s3.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/proptest-regressions/storage/virtual_ref.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/asset_manager.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/change_set.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/conflicts/basic_solver.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/conflicts/detector.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/conflicts/mod.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/error.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/format/attributes.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/format/flatbuffers/all_generated.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/format/manifest.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/format/mod.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/format/serializers/mod.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/format/snapshot.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/format/transaction_log.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/lib.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/ops/gc.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/ops/mod.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/refs.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/session.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/store.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/strategies.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/src/virtual_chunks.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/tests/test_concurrency.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/tests/test_distributed_writes.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/tests/test_gc.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/tests/test_storage.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk/tests/test_virtual_refs.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/.gitignore +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/Cargo.lock +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/__init__.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/coiled_runner.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/conftest.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/create_era5.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/datasets.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/envs/icechunk-alpha-12.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/envs/icechunk-alpha-release.txt +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/helpers.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/lib.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/most_recent.sh +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/runner.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/tasks.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/test_benchmark_reads.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/benchmarks/test_benchmark_writes.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/examples/dask_write.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/conflict.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/demo-azure-blob.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/demo-dummy-data.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/demo-gcs.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/demo-s3.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/environment.yml +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/memorystore.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/performance/era5_xarray-Icechunk.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/performance/era5_xarray-zarr2.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/performance/era5_xarray-zarr3.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/notebooks/version-control.ipynb +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/credentials.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/dask.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/distributed.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/py.typed +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/session.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/storage.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/store.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/vendor/__init__.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/vendor/xarray.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/python/icechunk/xarray.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/src/conflicts.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/src/errors.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/src/lib.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/src/session.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/src/store.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/src/streams.rs +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/__init__.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/conftest.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/chunks/09HEW2P03CSMHFAZY7DG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/chunks/52H0E4NSPN8SVRK9EVGG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/chunks/DWQ75SDC624XF9H326RG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/chunks/RW938N1KP2R4BHMW62QG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/config.yaml +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/manifests/CMYVHDWMSTG9R25780YG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/manifests/G3W2W8V6ZG09J6C21WE0 +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/manifests/Q04J7QW5RQ8D17TPA10G +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/manifests/SHTEAP8C784YMZSJKBM0 +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/branch.main/ref.json +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/branch.my-branch/ref.json +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/tag.deleted/ref.json +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/tag.deleted/ref.json.deleted +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/tag.it also works!/ref.json +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/tag.it works!/ref.json +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/4QF8JA0YPDN51MHSSYVG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/7XAF0Q905SH4938DN9CG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/GC4YVH5SKBPEZCENYQE0 +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/NXH3M0HJ7EEJ0699DPP0 +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/P874YS3J196959RDHX7G +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/XDZ162T1TYBEJMK99NPG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/4QF8JA0YPDN51MHSSYVG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/7XAF0Q905SH4938DN9CG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/GC4YVH5SKBPEZCENYQE0 +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/NXH3M0HJ7EEJ0699DPP0 +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/XDZ162T1TYBEJMK99NPG +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/run_xarray_backends_tests.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_can_read_old.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_commit_properties.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_concurrency.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_config.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_conflicts.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_credentials.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_dask.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_distributed_writers.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_error.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_gc.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_regressions.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_stateful_repo_ops.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_store.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_timetravel.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_virtual_ref.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_xarray.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/__init__.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_array.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_group.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_properties.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_stateful.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_store/__init__.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_store/test_core.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_store/test_icechunk_store.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/credentials.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/dask.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/distributed.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/py.typed +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/session.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/storage.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/store.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/vendor/__init__.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/vendor/xarray.py +0 -0
- {icechunk-0.2.2 → icechunk-0.2.4}/python/icechunk/xarray.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: icechunk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
|
8
8
|
Classifier: Programming Language :: Python :: 3.11
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
-
Requires-Dist: zarr>=3
|
|
10
|
+
Requires-Dist: zarr>=3,!=3.0.3
|
|
11
11
|
Requires-Dist: boto3 ; extra == 'test'
|
|
12
12
|
Requires-Dist: coverage ; extra == 'test'
|
|
13
13
|
Requires-Dist: mypy ; extra == 'test'
|
|
@@ -24,6 +24,19 @@ pub struct S3Options {
|
|
|
24
24
|
pub allow_http: bool,
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
impl fmt::Display for S3Options {
|
|
28
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
29
|
+
write!(
|
|
30
|
+
f,
|
|
31
|
+
"S3Options(region={}, endpoint_url={}, anonymous={}, allow_http={})",
|
|
32
|
+
self.region.as_deref().unwrap_or("None"),
|
|
33
|
+
self.endpoint_url.as_deref().unwrap_or("None"),
|
|
34
|
+
self.anonymous,
|
|
35
|
+
self.allow_http
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
|
28
41
|
#[serde(rename_all = "snake_case")]
|
|
29
42
|
pub enum ObjectStoreConfig {
|
|
@@ -331,6 +331,16 @@ impl Repository {
|
|
|
331
331
|
)
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
#[instrument(skip(bytes))]
|
|
335
|
+
pub fn from_bytes(bytes: Vec<u8>) -> RepositoryResult<Self> {
|
|
336
|
+
rmp_serde::from_slice(&bytes).err_into()
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
#[instrument(skip(self))]
|
|
340
|
+
pub fn as_bytes(&self) -> RepositoryResult<Vec<u8>> {
|
|
341
|
+
rmp_serde::to_vec(self).err_into()
|
|
342
|
+
}
|
|
343
|
+
|
|
334
344
|
#[instrument(skip_all)]
|
|
335
345
|
pub async fn fetch_config(
|
|
336
346
|
storage: &(dyn Storage + Send + Sync),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use std::{
|
|
2
|
+
fmt,
|
|
2
3
|
ops::Range,
|
|
3
4
|
sync::{Arc, Mutex},
|
|
4
5
|
};
|
|
@@ -37,6 +38,12 @@ impl LoggingStorage {
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
impl fmt::Display for LoggingStorage {
|
|
42
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
43
|
+
write!(f, "LoggingStorage(backend={})", self.backend)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
impl private::Sealed for LoggingStorage {}
|
|
41
48
|
|
|
42
49
|
#[async_trait]
|
|
@@ -298,7 +298,7 @@ pub enum WriteRefResult {
|
|
|
298
298
|
/// Implementations are free to assume files are never overwritten.
|
|
299
299
|
#[async_trait]
|
|
300
300
|
#[typetag::serde(tag = "type")]
|
|
301
|
-
pub trait Storage: fmt::Debug + private::Sealed + Sync + Send {
|
|
301
|
+
pub trait Storage: fmt::Debug + fmt::Display + private::Sealed + Sync + Send {
|
|
302
302
|
fn default_settings(&self) -> Settings {
|
|
303
303
|
Default::default()
|
|
304
304
|
}
|
|
@@ -712,10 +712,27 @@ pub async fn new_gcs_storage(
|
|
|
712
712
|
#[allow(clippy::unwrap_used, clippy::panic)]
|
|
713
713
|
mod tests {
|
|
714
714
|
|
|
715
|
-
use std::collections::HashSet;
|
|
715
|
+
use std::{collections::HashSet, fs::File, io::Write, path::PathBuf};
|
|
716
716
|
|
|
717
717
|
use super::*;
|
|
718
718
|
use proptest::prelude::*;
|
|
719
|
+
use tempfile::TempDir;
|
|
720
|
+
|
|
721
|
+
#[tokio::test]
|
|
722
|
+
async fn test_is_clean() {
|
|
723
|
+
let repo_dir = TempDir::new().unwrap();
|
|
724
|
+
let s = new_local_filesystem_storage(repo_dir.path()).await.unwrap();
|
|
725
|
+
assert!(s.root_is_clean().await.unwrap());
|
|
726
|
+
|
|
727
|
+
let mut file = File::create(repo_dir.path().join("foo.txt")).unwrap();
|
|
728
|
+
write!(file, "hello").unwrap();
|
|
729
|
+
assert!(!s.root_is_clean().await.unwrap());
|
|
730
|
+
|
|
731
|
+
let inside_existing =
|
|
732
|
+
PathBuf::from_iter([repo_dir.path().as_os_str().to_str().unwrap(), "foo"]);
|
|
733
|
+
let s = new_local_filesystem_storage(&inside_existing).await.unwrap();
|
|
734
|
+
assert!(s.root_is_clean().await.unwrap());
|
|
735
|
+
}
|
|
719
736
|
|
|
720
737
|
proptest! {
|
|
721
738
|
#![proptest_config(ProptestConfig {
|
|
@@ -27,7 +27,7 @@ use object_store::{
|
|
|
27
27
|
use serde::{Deserialize, Serialize};
|
|
28
28
|
use std::{
|
|
29
29
|
collections::HashMap,
|
|
30
|
-
fmt::Debug,
|
|
30
|
+
fmt::{self, Debug, Display},
|
|
31
31
|
fs::create_dir_all,
|
|
32
32
|
future::ready,
|
|
33
33
|
num::{NonZeroU16, NonZeroU64},
|
|
@@ -83,7 +83,6 @@ impl ObjectStorage {
|
|
|
83
83
|
Arc::new(LocalFileSystemObjectStoreBackend { path: prefix.to_path_buf() });
|
|
84
84
|
let client = backend.mk_object_store().await?;
|
|
85
85
|
let storage = ObjectStorage { backend, client: OnceCell::new_with(Some(client)) };
|
|
86
|
-
|
|
87
86
|
Ok(storage)
|
|
88
87
|
}
|
|
89
88
|
|
|
@@ -286,6 +285,12 @@ impl ObjectStorage {
|
|
|
286
285
|
}
|
|
287
286
|
}
|
|
288
287
|
|
|
288
|
+
impl fmt::Display for ObjectStorage {
|
|
289
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
290
|
+
write!(f, "ObjectStorage(backend={})", self.backend)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
289
294
|
impl private::Sealed for ObjectStorage {}
|
|
290
295
|
|
|
291
296
|
#[async_trait]
|
|
@@ -622,7 +627,7 @@ impl Storage for ObjectStorage {
|
|
|
622
627
|
|
|
623
628
|
#[async_trait]
|
|
624
629
|
#[typetag::serde(tag = "object_store_provider_type")]
|
|
625
|
-
pub trait ObjectStoreBackend: Debug + Sync + Send {
|
|
630
|
+
pub trait ObjectStoreBackend: Debug + Display + Sync + Send {
|
|
626
631
|
async fn mk_object_store(&self) -> Result<Arc<dyn ObjectStore>, StorageError>;
|
|
627
632
|
|
|
628
633
|
/// The prefix for the object store.
|
|
@@ -640,6 +645,12 @@ pub trait ObjectStoreBackend: Debug + Sync + Send {
|
|
|
640
645
|
#[derive(Debug, Serialize, Deserialize)]
|
|
641
646
|
pub struct InMemoryObjectStoreBackend;
|
|
642
647
|
|
|
648
|
+
impl fmt::Display for InMemoryObjectStoreBackend {
|
|
649
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
650
|
+
write!(f, "InMemoryObjectStoreBackend")
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
643
654
|
#[async_trait]
|
|
644
655
|
#[typetag::serde(name = "in_memory_object_store_provider")]
|
|
645
656
|
impl ObjectStoreBackend for InMemoryObjectStoreBackend {
|
|
@@ -672,6 +683,12 @@ pub struct LocalFileSystemObjectStoreBackend {
|
|
|
672
683
|
path: PathBuf,
|
|
673
684
|
}
|
|
674
685
|
|
|
686
|
+
impl fmt::Display for LocalFileSystemObjectStoreBackend {
|
|
687
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
688
|
+
write!(f, "LocalFileSystemObjectStoreBackend(path={})", self.path.display())
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
675
692
|
#[async_trait]
|
|
676
693
|
#[typetag::serde(name = "local_file_system_object_store_provider")]
|
|
677
694
|
impl ObjectStoreBackend for LocalFileSystemObjectStoreBackend {
|
|
@@ -720,6 +737,18 @@ pub struct S3ObjectStoreBackend {
|
|
|
720
737
|
config: Option<S3Options>,
|
|
721
738
|
}
|
|
722
739
|
|
|
740
|
+
impl fmt::Display for S3ObjectStoreBackend {
|
|
741
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
742
|
+
write!(
|
|
743
|
+
f,
|
|
744
|
+
"S3ObjectStoreBackend(bucket={}, prefix={}, config={})",
|
|
745
|
+
self.bucket,
|
|
746
|
+
self.prefix.as_deref().unwrap_or(""),
|
|
747
|
+
self.config.as_ref().map(|c| c.to_string()).unwrap_or("None".to_string())
|
|
748
|
+
)
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
723
752
|
#[async_trait]
|
|
724
753
|
#[typetag::serde(name = "s3_object_store_provider")]
|
|
725
754
|
impl ObjectStoreBackend for S3ObjectStoreBackend {
|
|
@@ -794,6 +823,18 @@ pub struct AzureObjectStoreBackend {
|
|
|
794
823
|
config: Option<HashMap<AzureConfigKey, String>>,
|
|
795
824
|
}
|
|
796
825
|
|
|
826
|
+
impl fmt::Display for AzureObjectStoreBackend {
|
|
827
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
828
|
+
write!(
|
|
829
|
+
f,
|
|
830
|
+
"AzureObjectStoreBackend(account={}, container={}, prefix={})",
|
|
831
|
+
self.account,
|
|
832
|
+
self.container,
|
|
833
|
+
self.prefix.as_deref().unwrap_or("")
|
|
834
|
+
)
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
797
838
|
#[async_trait]
|
|
798
839
|
#[typetag::serde(name = "azure_object_store_provider")]
|
|
799
840
|
impl ObjectStoreBackend for AzureObjectStoreBackend {
|
|
@@ -846,6 +887,17 @@ pub struct GcsObjectStoreBackend {
|
|
|
846
887
|
config: Option<HashMap<GoogleConfigKey, String>>,
|
|
847
888
|
}
|
|
848
889
|
|
|
890
|
+
impl fmt::Display for GcsObjectStoreBackend {
|
|
891
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
892
|
+
write!(
|
|
893
|
+
f,
|
|
894
|
+
"GcsObjectStoreBackend(bucket={}, prefix={})",
|
|
895
|
+
self.bucket,
|
|
896
|
+
self.prefix.as_deref().unwrap_or("")
|
|
897
|
+
)
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
849
901
|
#[async_trait]
|
|
850
902
|
#[typetag::serde(name = "gcs_object_store_provider")]
|
|
851
903
|
impl ObjectStoreBackend for GcsObjectStoreBackend {
|
|
@@ -969,6 +1021,8 @@ mod tests {
|
|
|
969
1021
|
|
|
970
1022
|
use tempfile::TempDir;
|
|
971
1023
|
|
|
1024
|
+
use crate::format::{ChunkId, ManifestId, SnapshotId};
|
|
1025
|
+
|
|
972
1026
|
use super::ObjectStorage;
|
|
973
1027
|
|
|
974
1028
|
#[tokio::test]
|
|
@@ -1018,4 +1072,34 @@ mod tests {
|
|
|
1018
1072
|
ObjectStorage::new_local_filesystem(PathBuf::from(&rel_path).as_path()).await;
|
|
1019
1073
|
assert!(store.is_ok());
|
|
1020
1074
|
}
|
|
1075
|
+
|
|
1076
|
+
#[tokio::test]
|
|
1077
|
+
async fn test_object_store_paths() {
|
|
1078
|
+
let store = ObjectStorage::new_local_filesystem(PathBuf::from(".").as_path())
|
|
1079
|
+
.await
|
|
1080
|
+
.unwrap();
|
|
1081
|
+
|
|
1082
|
+
let ref_key = "ref_key";
|
|
1083
|
+
let ref_path = store.ref_key(ref_key);
|
|
1084
|
+
assert_eq!(ref_path.to_string(), format!("refs/{ref_key}"));
|
|
1085
|
+
|
|
1086
|
+
let snapshot_id = SnapshotId::random();
|
|
1087
|
+
let snapshot_path = store.get_snapshot_path(&snapshot_id);
|
|
1088
|
+
assert_eq!(snapshot_path.to_string(), format!("snapshots/{snapshot_id}"));
|
|
1089
|
+
|
|
1090
|
+
let manifest_id = ManifestId::random();
|
|
1091
|
+
let manifest_path = store.get_manifest_path(&manifest_id);
|
|
1092
|
+
assert_eq!(manifest_path.to_string(), format!("manifests/{manifest_id}"));
|
|
1093
|
+
|
|
1094
|
+
let chunk_id = ChunkId::random();
|
|
1095
|
+
let chunk_path = store.get_chunk_path(&chunk_id);
|
|
1096
|
+
assert_eq!(chunk_path.to_string(), format!("chunks/{chunk_id}"));
|
|
1097
|
+
|
|
1098
|
+
let transaction_id = SnapshotId::random();
|
|
1099
|
+
let transaction_path = store.get_transaction_path(&transaction_id);
|
|
1100
|
+
assert_eq!(
|
|
1101
|
+
transaction_path.to_string(),
|
|
1102
|
+
format!("transactions/{transaction_id}")
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1021
1105
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use std::{
|
|
2
|
+
fmt,
|
|
2
3
|
future::ready,
|
|
3
4
|
ops::Range,
|
|
4
5
|
path::{Path, PathBuf},
|
|
@@ -29,7 +30,6 @@ use aws_sdk_s3::{
|
|
|
29
30
|
use aws_smithy_types_convert::{date_time::DateTimeExt, stream::PaginationStreamExt};
|
|
30
31
|
use bytes::{Buf, Bytes};
|
|
31
32
|
use chrono::{DateTime, Utc};
|
|
32
|
-
use err_into::ErrorInto as _;
|
|
33
33
|
use futures::{
|
|
34
34
|
stream::{self, BoxStream},
|
|
35
35
|
StreamExt, TryStreamExt,
|
|
@@ -59,6 +59,16 @@ pub struct S3Storage {
|
|
|
59
59
|
client: OnceCell<Arc<Client>>,
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
impl fmt::Display for S3Storage {
|
|
63
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
64
|
+
write!(
|
|
65
|
+
f,
|
|
66
|
+
"S3Storage(bucket={}, prefix={}, config={})",
|
|
67
|
+
self.bucket, self.prefix, self.config,
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
62
72
|
#[instrument(skip(credentials))]
|
|
63
73
|
pub async fn mk_client(config: &S3Options, credentials: S3Credentials) -> Client {
|
|
64
74
|
let region = config
|
|
@@ -139,10 +149,10 @@ impl S3Storage {
|
|
|
139
149
|
|
|
140
150
|
fn get_path_str(&self, file_prefix: &str, id: &str) -> StorageResult<String> {
|
|
141
151
|
let path = PathBuf::from_iter([self.prefix.as_str(), file_prefix, id]);
|
|
142
|
-
|
|
143
|
-
.into_string()
|
|
144
|
-
|
|
145
|
-
|
|
152
|
+
let path_str =
|
|
153
|
+
path.into_os_string().into_string().map_err(StorageErrorKind::BadPrefix)?;
|
|
154
|
+
|
|
155
|
+
Ok(path_str.replace("\\", "/"))
|
|
146
156
|
}
|
|
147
157
|
|
|
148
158
|
fn get_path<const SIZE: usize, T: FileTypeTag>(
|
|
@@ -176,10 +186,10 @@ impl S3Storage {
|
|
|
176
186
|
|
|
177
187
|
fn ref_key(&self, ref_key: &str) -> StorageResult<String> {
|
|
178
188
|
let path = PathBuf::from_iter([self.prefix.as_str(), REF_PREFIX, ref_key]);
|
|
179
|
-
|
|
180
|
-
.into_string()
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
let path_str =
|
|
190
|
+
path.into_os_string().into_string().map_err(StorageErrorKind::BadPrefix)?;
|
|
191
|
+
|
|
192
|
+
Ok(path_str.replace("\\", "/"))
|
|
183
193
|
}
|
|
184
194
|
|
|
185
195
|
async fn get_object_reader(
|
|
@@ -601,10 +611,7 @@ impl Storage for S3Storage {
|
|
|
601
611
|
_settings: &Settings,
|
|
602
612
|
prefix: &str,
|
|
603
613
|
) -> StorageResult<BoxStream<'a, StorageResult<ListInfo<String>>>> {
|
|
604
|
-
let prefix =
|
|
605
|
-
.into_os_string()
|
|
606
|
-
.into_string()
|
|
607
|
-
.map_err(StorageErrorKind::BadPrefix)?;
|
|
614
|
+
let prefix = format!("{}/{}", self.prefix, prefix).replace("//", "/");
|
|
608
615
|
let stream = self
|
|
609
616
|
.get_client()
|
|
610
617
|
.await
|
|
@@ -787,4 +794,39 @@ mod tests {
|
|
|
787
794
|
let deserialized: S3Storage = serde_json::from_str(&serialized).unwrap();
|
|
788
795
|
assert_eq!(storage.config, deserialized.config);
|
|
789
796
|
}
|
|
797
|
+
|
|
798
|
+
#[tokio::test]
|
|
799
|
+
async fn test_s3_paths() {
|
|
800
|
+
let storage = S3Storage::new(
|
|
801
|
+
S3Options {
|
|
802
|
+
region: Some("us-west-2".to_string()),
|
|
803
|
+
endpoint_url: None,
|
|
804
|
+
allow_http: true,
|
|
805
|
+
anonymous: false,
|
|
806
|
+
},
|
|
807
|
+
"bucket".to_string(),
|
|
808
|
+
Some("prefix".to_string()),
|
|
809
|
+
S3Credentials::FromEnv,
|
|
810
|
+
)
|
|
811
|
+
.unwrap();
|
|
812
|
+
|
|
813
|
+
let ref_path = storage.ref_key("ref_key").unwrap();
|
|
814
|
+
assert_eq!(ref_path, "prefix/refs/ref_key");
|
|
815
|
+
|
|
816
|
+
let snapshot_id = SnapshotId::random();
|
|
817
|
+
let snapshot_path = storage.get_snapshot_path(&snapshot_id).unwrap();
|
|
818
|
+
assert_eq!(snapshot_path, format!("prefix/snapshots/{snapshot_id}"));
|
|
819
|
+
|
|
820
|
+
let manifest_id = ManifestId::random();
|
|
821
|
+
let manifest_path = storage.get_manifest_path(&manifest_id).unwrap();
|
|
822
|
+
assert_eq!(manifest_path, format!("prefix/manifests/{manifest_id}"));
|
|
823
|
+
|
|
824
|
+
let chunk_id = ChunkId::random();
|
|
825
|
+
let chunk_path = storage.get_chunk_path(&chunk_id).unwrap();
|
|
826
|
+
assert_eq!(chunk_path, format!("prefix/chunks/{chunk_id}"));
|
|
827
|
+
|
|
828
|
+
let transaction_id = SnapshotId::random();
|
|
829
|
+
let transaction_path = storage.get_transaction_path(&transaction_id).unwrap();
|
|
830
|
+
assert_eq!(transaction_path, format!("prefix/transactions/{transaction_id}"));
|
|
831
|
+
}
|
|
790
832
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "icechunk-python"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4"
|
|
4
4
|
description = "Transactional storage engine for Zarr designed for use on cloud object storage"
|
|
5
5
|
readme = "../README.md"
|
|
6
6
|
repository = "https://github.com/earth-mover/icechunk"
|
|
@@ -21,7 +21,7 @@ crate-type = ["cdylib"]
|
|
|
21
21
|
bytes = "1.9.0"
|
|
22
22
|
chrono = { version = "0.4.39" }
|
|
23
23
|
futures = "0.3.31"
|
|
24
|
-
icechunk = { path = "../icechunk", version = "0.2.
|
|
24
|
+
icechunk = { path = "../icechunk", version = "0.2.4", features = ["logs"] }
|
|
25
25
|
itertools = "0.14.0"
|
|
26
26
|
pyo3 = { version = "0.23", features = [
|
|
27
27
|
"chrono",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# An example of using multiprocessing to write to an Icechunk dataset
|
|
2
|
+
|
|
3
|
+
import tempfile
|
|
4
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
5
|
+
|
|
6
|
+
import xarray as xr
|
|
7
|
+
from icechunk import Repository, Session, local_filesystem_storage
|
|
8
|
+
from icechunk.distributed import merge_sessions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def write_timestamp(*, itime: int, session: Session) -> Session:
|
|
12
|
+
# pass a list to isel to preserve the time dimension
|
|
13
|
+
ds = xr.tutorial.open_dataset("rasm").isel(time=[itime])
|
|
14
|
+
# region="auto" tells Xarray to infer which "region" of the output arrays to write to.
|
|
15
|
+
ds.to_zarr(session.store, region="auto", consolidated=False)
|
|
16
|
+
return session
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
if __name__ == "__main__":
|
|
20
|
+
ds = xr.tutorial.open_dataset("rasm").isel(time=slice(24))
|
|
21
|
+
repo = Repository.create(local_filesystem_storage(tempfile.mkdtemp()))
|
|
22
|
+
session = repo.writable_session("main")
|
|
23
|
+
|
|
24
|
+
chunks = {1 if dim == "time" else ds.sizes[dim] for dim in ds.Tair.dims}
|
|
25
|
+
ds.to_zarr(
|
|
26
|
+
session.store, compute=False, encoding={"Tair": {"chunks": chunks}}, mode="w"
|
|
27
|
+
)
|
|
28
|
+
# this commit is optional, but may be useful in your workflow
|
|
29
|
+
session.commit("initialize store")
|
|
30
|
+
|
|
31
|
+
session = repo.writable_session("main")
|
|
32
|
+
with ProcessPoolExecutor() as executor:
|
|
33
|
+
# opt-in to successful pickling of a writable session
|
|
34
|
+
with session.allow_pickling():
|
|
35
|
+
# submit the writes
|
|
36
|
+
futures = [
|
|
37
|
+
executor.submit(write_timestamp, itime=i, session=session)
|
|
38
|
+
for i in range(ds.sizes["time"])
|
|
39
|
+
]
|
|
40
|
+
# grab the Session objects from each individual write task
|
|
41
|
+
sessions = [f.result() for f in futures]
|
|
42
|
+
|
|
43
|
+
# manually merge the remote sessions in to the local session
|
|
44
|
+
session = merge_sessions(session, *sessions)
|
|
45
|
+
session.commit("finished writes")
|
|
46
|
+
|
|
47
|
+
ondisk = xr.open_zarr(repo.readonly_session("main").store, consolidated=False)
|
|
48
|
+
xr.testing.assert_identical(ds, ondisk)
|
|
@@ -52,6 +52,7 @@ from icechunk.credentials import (
|
|
|
52
52
|
containers_credentials,
|
|
53
53
|
gcs_credentials,
|
|
54
54
|
gcs_from_env_credentials,
|
|
55
|
+
gcs_refreshable_credentials,
|
|
55
56
|
gcs_static_credentials,
|
|
56
57
|
s3_anonymous_credentials,
|
|
57
58
|
s3_credentials,
|
|
@@ -128,11 +129,13 @@ __all__ = [
|
|
|
128
129
|
"containers_credentials",
|
|
129
130
|
"gcs_credentials",
|
|
130
131
|
"gcs_from_env_credentials",
|
|
132
|
+
"gcs_refreshable_credentials",
|
|
131
133
|
"gcs_static_credentials",
|
|
132
134
|
"gcs_storage",
|
|
133
135
|
"in_memory_storage",
|
|
134
136
|
"initialize_logs",
|
|
135
137
|
"local_filesystem_storage",
|
|
138
|
+
"print_debug_info",
|
|
136
139
|
"s3_anonymous_credentials",
|
|
137
140
|
"s3_credentials",
|
|
138
141
|
"s3_from_env_credentials",
|
|
@@ -144,4 +147,19 @@ __all__ = [
|
|
|
144
147
|
"tigris_storage",
|
|
145
148
|
]
|
|
146
149
|
|
|
150
|
+
|
|
151
|
+
def print_debug_info() -> None:
|
|
152
|
+
import platform
|
|
153
|
+
from importlib import import_module
|
|
154
|
+
|
|
155
|
+
print(f"platform: {platform.platform()}")
|
|
156
|
+
print(f"python: {platform.python_version()}")
|
|
157
|
+
print(f"icechunk: {__version__}")
|
|
158
|
+
for package in ["zarr", "numcodecs", "xarray", "virtualizarr"]:
|
|
159
|
+
try:
|
|
160
|
+
print(f"{package}: {import_module(package).__version__}")
|
|
161
|
+
except ModuleNotFoundError:
|
|
162
|
+
continue
|
|
163
|
+
|
|
164
|
+
|
|
147
165
|
initialize_logs()
|
|
@@ -947,6 +947,9 @@ class PyRepository:
|
|
|
947
947
|
) -> PyRepository: ...
|
|
948
948
|
@staticmethod
|
|
949
949
|
def exists(storage: Storage) -> bool: ...
|
|
950
|
+
@classmethod
|
|
951
|
+
def from_bytes(cls, data: bytes) -> PyRepository: ...
|
|
952
|
+
def as_bytes(self) -> bytes: ...
|
|
950
953
|
@staticmethod
|
|
951
954
|
def fetch_config(storage: Storage) -> RepositoryConfig | None: ...
|
|
952
955
|
def save_config(self) -> None: ...
|
|
@@ -1418,6 +1421,7 @@ class Storage:
|
|
|
1418
1421
|
*,
|
|
1419
1422
|
config: dict[str, str] | None = None,
|
|
1420
1423
|
) -> Storage: ...
|
|
1424
|
+
def __repr__(self) -> str: ...
|
|
1421
1425
|
def default_settings(self) -> StorageSettings: ...
|
|
1422
1426
|
|
|
1423
1427
|
class VersionSelection(Enum):
|
|
@@ -140,6 +140,16 @@ class Repository:
|
|
|
140
140
|
"""
|
|
141
141
|
return PyRepository.exists(storage)
|
|
142
142
|
|
|
143
|
+
def __getstate__(self) -> object:
|
|
144
|
+
return {
|
|
145
|
+
"_repository": self._repository.as_bytes(),
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
def __setstate__(self, state: object) -> None:
|
|
149
|
+
if not isinstance(state, dict):
|
|
150
|
+
raise ValueError("Invalid repository state")
|
|
151
|
+
self._repository = PyRepository.from_bytes(state["_repository"])
|
|
152
|
+
|
|
143
153
|
@staticmethod
|
|
144
154
|
def fetch_config(storage: Storage) -> RepositoryConfig | None:
|
|
145
155
|
"""
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use std::{
|
|
2
|
+
borrow::Cow,
|
|
2
3
|
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
|
3
4
|
sync::Arc,
|
|
4
5
|
};
|
|
@@ -463,6 +464,29 @@ impl PyRepository {
|
|
|
463
464
|
})
|
|
464
465
|
}
|
|
465
466
|
|
|
467
|
+
#[classmethod]
|
|
468
|
+
fn from_bytes(
|
|
469
|
+
_cls: Bound<'_, PyType>,
|
|
470
|
+
py: Python<'_>,
|
|
471
|
+
bytes: Vec<u8>,
|
|
472
|
+
) -> PyResult<Self> {
|
|
473
|
+
// This is a compute intensive task, we need to release the Gil
|
|
474
|
+
py.allow_threads(move || {
|
|
475
|
+
let repository = Repository::from_bytes(bytes)
|
|
476
|
+
.map_err(PyIcechunkStoreError::RepositoryError)?;
|
|
477
|
+
Ok(Self(Arc::new(repository)))
|
|
478
|
+
})
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
fn as_bytes(&self, py: Python<'_>) -> PyResult<Cow<[u8]>> {
|
|
482
|
+
// This is a compute intensive task, we need to release the Gil
|
|
483
|
+
py.allow_threads(move || {
|
|
484
|
+
let bytes =
|
|
485
|
+
self.0.as_bytes().map_err(PyIcechunkStoreError::RepositoryError)?;
|
|
486
|
+
Ok(Cow::Owned(bytes))
|
|
487
|
+
})
|
|
488
|
+
}
|
|
489
|
+
|
|
466
490
|
#[staticmethod]
|
|
467
491
|
fn fetch_config(
|
|
468
492
|
py: Python<'_>,
|
|
@@ -25,6 +25,18 @@ def tmp_repo(tmpdir: Path) -> Repository:
|
|
|
25
25
|
return repo
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
def test_pickle_repository(tmpdir: Path, tmp_repo: Repository) -> None:
|
|
29
|
+
pickled = pickle.dumps(tmp_repo)
|
|
30
|
+
roundtripped = pickle.loads(pickled)
|
|
31
|
+
assert tmp_repo.list_branches() == roundtripped.list_branches()
|
|
32
|
+
|
|
33
|
+
storage = tmp_repo.storage
|
|
34
|
+
assert (
|
|
35
|
+
repr(storage)
|
|
36
|
+
== f"ObjectStorage(backend=LocalFileSystemObjectStoreBackend(path={tmpdir}))"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
28
40
|
def test_pickle_read_only(tmp_repo: Repository) -> None:
|
|
29
41
|
tmp_session = tmp_repo.writable_session(branch="main")
|
|
30
42
|
tmp_store = tmp_session.store
|
|
@@ -52,6 +52,7 @@ from icechunk.credentials import (
|
|
|
52
52
|
containers_credentials,
|
|
53
53
|
gcs_credentials,
|
|
54
54
|
gcs_from_env_credentials,
|
|
55
|
+
gcs_refreshable_credentials,
|
|
55
56
|
gcs_static_credentials,
|
|
56
57
|
s3_anonymous_credentials,
|
|
57
58
|
s3_credentials,
|
|
@@ -128,11 +129,13 @@ __all__ = [
|
|
|
128
129
|
"containers_credentials",
|
|
129
130
|
"gcs_credentials",
|
|
130
131
|
"gcs_from_env_credentials",
|
|
132
|
+
"gcs_refreshable_credentials",
|
|
131
133
|
"gcs_static_credentials",
|
|
132
134
|
"gcs_storage",
|
|
133
135
|
"in_memory_storage",
|
|
134
136
|
"initialize_logs",
|
|
135
137
|
"local_filesystem_storage",
|
|
138
|
+
"print_debug_info",
|
|
136
139
|
"s3_anonymous_credentials",
|
|
137
140
|
"s3_credentials",
|
|
138
141
|
"s3_from_env_credentials",
|
|
@@ -144,4 +147,19 @@ __all__ = [
|
|
|
144
147
|
"tigris_storage",
|
|
145
148
|
]
|
|
146
149
|
|
|
150
|
+
|
|
151
|
+
def print_debug_info() -> None:
|
|
152
|
+
import platform
|
|
153
|
+
from importlib import import_module
|
|
154
|
+
|
|
155
|
+
print(f"platform: {platform.platform()}")
|
|
156
|
+
print(f"python: {platform.python_version()}")
|
|
157
|
+
print(f"icechunk: {__version__}")
|
|
158
|
+
for package in ["zarr", "numcodecs", "xarray", "virtualizarr"]:
|
|
159
|
+
try:
|
|
160
|
+
print(f"{package}: {import_module(package).__version__}")
|
|
161
|
+
except ModuleNotFoundError:
|
|
162
|
+
continue
|
|
163
|
+
|
|
164
|
+
|
|
147
165
|
initialize_logs()
|