icechunk 0.2.3__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.
Files changed (169) hide show
  1. {icechunk-0.2.3 → icechunk-0.2.4}/PKG-INFO +1 -1
  2. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/Cargo.toml +1 -1
  3. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/storage/mod.rs +18 -1
  4. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/storage/object_store.rs +32 -1
  5. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/storage/s3.rs +44 -13
  6. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/Cargo.toml +2 -2
  7. icechunk-0.2.4/icechunk-python/examples/mpwrite.py +48 -0
  8. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/examples/low_level_dataset.rs +0 -0
  9. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/examples/multithreaded_get_chunk_refs.rs +0 -0
  10. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/examples/multithreaded_store.rs +0 -0
  11. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/flatbuffers/all.fbs +0 -0
  12. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/flatbuffers/manifest.fbs +0 -0
  13. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/flatbuffers/object_ids.fbs +0 -0
  14. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/flatbuffers/snapshot.fbs +0 -0
  15. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/flatbuffers/transaction_log.fbs +0 -0
  16. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/proptest-regressions/dataset.txt +0 -0
  17. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/proptest-regressions/format/manifest.txt +0 -0
  18. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/proptest-regressions/manifest.txt +0 -0
  19. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/proptest-regressions/session.txt +0 -0
  20. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/proptest-regressions/storage/mod.txt +0 -0
  21. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/proptest-regressions/storage/s3.txt +0 -0
  22. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/proptest-regressions/storage/virtual_ref.txt +0 -0
  23. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/asset_manager.rs +0 -0
  24. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/change_set.rs +0 -0
  25. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/config.rs +0 -0
  26. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/conflicts/basic_solver.rs +0 -0
  27. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/conflicts/detector.rs +0 -0
  28. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/conflicts/mod.rs +0 -0
  29. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/error.rs +0 -0
  30. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/format/attributes.rs +0 -0
  31. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/format/flatbuffers/all_generated.rs +0 -0
  32. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/format/manifest.rs +0 -0
  33. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/format/mod.rs +0 -0
  34. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/format/serializers/mod.rs +0 -0
  35. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/format/snapshot.rs +0 -0
  36. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/format/transaction_log.rs +0 -0
  37. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/lib.rs +0 -0
  38. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/ops/gc.rs +0 -0
  39. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/ops/mod.rs +0 -0
  40. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/refs.rs +0 -0
  41. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/repository.rs +0 -0
  42. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/session.rs +0 -0
  43. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/storage/logging.rs +0 -0
  44. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/store.rs +0 -0
  45. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/strategies.rs +0 -0
  46. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/src/virtual_chunks.rs +0 -0
  47. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/tests/test_concurrency.rs +0 -0
  48. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/tests/test_distributed_writes.rs +0 -0
  49. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/tests/test_gc.rs +0 -0
  50. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/tests/test_storage.rs +0 -0
  51. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk/tests/test_virtual_refs.rs +0 -0
  52. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/.gitignore +0 -0
  53. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/Cargo.lock +0 -0
  54. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/__init__.py +0 -0
  55. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/coiled_runner.py +0 -0
  56. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/conftest.py +0 -0
  57. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/create_era5.py +0 -0
  58. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/datasets.py +0 -0
  59. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/envs/icechunk-alpha-12.txt +0 -0
  60. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/envs/icechunk-alpha-release.txt +0 -0
  61. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/helpers.py +0 -0
  62. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/lib.py +0 -0
  63. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/most_recent.sh +0 -0
  64. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/runner.py +0 -0
  65. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/tasks.py +0 -0
  66. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/test_benchmark_reads.py +0 -0
  67. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/benchmarks/test_benchmark_writes.py +0 -0
  68. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/examples/dask_write.py +0 -0
  69. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/conflict.ipynb +0 -0
  70. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/demo-azure-blob.ipynb +0 -0
  71. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/demo-dummy-data.ipynb +0 -0
  72. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/demo-gcs.ipynb +0 -0
  73. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/demo-s3.ipynb +0 -0
  74. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/environment.yml +0 -0
  75. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/memorystore.ipynb +0 -0
  76. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/performance/era5_xarray-Icechunk.ipynb +0 -0
  77. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/performance/era5_xarray-zarr2.ipynb +0 -0
  78. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/performance/era5_xarray-zarr3.ipynb +0 -0
  79. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/notebooks/version-control.ipynb +0 -0
  80. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/__init__.py +0 -0
  81. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/_icechunk_python.pyi +0 -0
  82. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/credentials.py +0 -0
  83. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/dask.py +0 -0
  84. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/distributed.py +0 -0
  85. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/py.typed +0 -0
  86. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/repository.py +0 -0
  87. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/session.py +0 -0
  88. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/storage.py +0 -0
  89. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/store.py +0 -0
  90. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/vendor/__init__.py +0 -0
  91. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/vendor/xarray.py +0 -0
  92. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/python/icechunk/xarray.py +0 -0
  93. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/src/config.rs +0 -0
  94. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/src/conflicts.rs +0 -0
  95. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/src/errors.rs +0 -0
  96. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/src/lib.rs +0 -0
  97. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/src/repository.rs +0 -0
  98. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/src/session.rs +0 -0
  99. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/src/store.rs +0 -0
  100. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/src/streams.rs +0 -0
  101. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/__init__.py +0 -0
  102. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/conftest.py +0 -0
  103. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/chunks/09HEW2P03CSMHFAZY7DG +0 -0
  104. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/chunks/52H0E4NSPN8SVRK9EVGG +0 -0
  105. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/chunks/DWQ75SDC624XF9H326RG +0 -0
  106. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/chunks/RW938N1KP2R4BHMW62QG +0 -0
  107. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/config.yaml +0 -0
  108. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/manifests/CMYVHDWMSTG9R25780YG +0 -0
  109. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/manifests/G3W2W8V6ZG09J6C21WE0 +0 -0
  110. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/manifests/Q04J7QW5RQ8D17TPA10G +0 -0
  111. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/manifests/SHTEAP8C784YMZSJKBM0 +0 -0
  112. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/branch.main/ref.json +0 -0
  113. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/branch.my-branch/ref.json +0 -0
  114. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/tag.deleted/ref.json +0 -0
  115. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/tag.deleted/ref.json.deleted +0 -0
  116. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/tag.it also works!/ref.json +0 -0
  117. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/refs/tag.it works!/ref.json +0 -0
  118. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/4QF8JA0YPDN51MHSSYVG +0 -0
  119. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/7XAF0Q905SH4938DN9CG +0 -0
  120. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/GC4YVH5SKBPEZCENYQE0 +0 -0
  121. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/NXH3M0HJ7EEJ0699DPP0 +0 -0
  122. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/P874YS3J196959RDHX7G +0 -0
  123. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/snapshots/XDZ162T1TYBEJMK99NPG +0 -0
  124. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/4QF8JA0YPDN51MHSSYVG +0 -0
  125. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/7XAF0Q905SH4938DN9CG +0 -0
  126. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/GC4YVH5SKBPEZCENYQE0 +0 -0
  127. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/NXH3M0HJ7EEJ0699DPP0 +0 -0
  128. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/data/test-repo/transactions/XDZ162T1TYBEJMK99NPG +0 -0
  129. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/run_xarray_backends_tests.py +0 -0
  130. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_can_read_old.py +0 -0
  131. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_commit_properties.py +0 -0
  132. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_concurrency.py +0 -0
  133. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_config.py +0 -0
  134. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_conflicts.py +0 -0
  135. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_credentials.py +0 -0
  136. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_dask.py +0 -0
  137. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_debuginfo.py +0 -0
  138. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_distributed_writers.py +0 -0
  139. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_error.py +0 -0
  140. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_gc.py +0 -0
  141. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_pickle.py +0 -0
  142. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_regressions.py +0 -0
  143. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_stateful_repo_ops.py +0 -0
  144. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_store.py +0 -0
  145. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_timetravel.py +0 -0
  146. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_virtual_ref.py +0 -0
  147. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_xarray.py +0 -0
  148. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/__init__.py +0 -0
  149. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_array.py +0 -0
  150. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_group.py +0 -0
  151. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_properties.py +0 -0
  152. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_stateful.py +0 -0
  153. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_store/__init__.py +0 -0
  154. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_store/test_core.py +0 -0
  155. {icechunk-0.2.3 → icechunk-0.2.4}/icechunk-python/tests/test_zarr/test_store/test_icechunk_store.py +0 -0
  156. {icechunk-0.2.3 → icechunk-0.2.4}/pyproject.toml +0 -0
  157. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/__init__.py +0 -0
  158. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/_icechunk_python.pyi +0 -0
  159. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/credentials.py +0 -0
  160. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/dask.py +0 -0
  161. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/distributed.py +0 -0
  162. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/py.typed +0 -0
  163. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/repository.py +0 -0
  164. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/session.py +0 -0
  165. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/storage.py +0 -0
  166. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/store.py +0 -0
  167. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/vendor/__init__.py +0 -0
  168. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/vendor/xarray.py +0 -0
  169. {icechunk-0.2.3 → icechunk-0.2.4}/python/icechunk/xarray.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: icechunk
3
- Version: 0.2.3
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
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "icechunk"
3
- version = "0.2.3"
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"
@@ -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 {
@@ -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
 
@@ -1022,6 +1021,8 @@ mod tests {
1022
1021
 
1023
1022
  use tempfile::TempDir;
1024
1023
 
1024
+ use crate::format::{ChunkId, ManifestId, SnapshotId};
1025
+
1025
1026
  use super::ObjectStorage;
1026
1027
 
1027
1028
  #[tokio::test]
@@ -1071,4 +1072,34 @@ mod tests {
1071
1072
  ObjectStorage::new_local_filesystem(PathBuf::from(&rel_path).as_path()).await;
1072
1073
  assert!(store.is_ok());
1073
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
+ }
1074
1105
  }
@@ -30,7 +30,6 @@ use aws_sdk_s3::{
30
30
  use aws_smithy_types_convert::{date_time::DateTimeExt, stream::PaginationStreamExt};
31
31
  use bytes::{Buf, Bytes};
32
32
  use chrono::{DateTime, Utc};
33
- use err_into::ErrorInto as _;
34
33
  use futures::{
35
34
  stream::{self, BoxStream},
36
35
  StreamExt, TryStreamExt,
@@ -150,10 +149,10 @@ impl S3Storage {
150
149
 
151
150
  fn get_path_str(&self, file_prefix: &str, id: &str) -> StorageResult<String> {
152
151
  let path = PathBuf::from_iter([self.prefix.as_str(), file_prefix, id]);
153
- path.into_os_string()
154
- .into_string()
155
- .map_err(StorageErrorKind::BadPrefix)
156
- .err_into()
152
+ let path_str =
153
+ path.into_os_string().into_string().map_err(StorageErrorKind::BadPrefix)?;
154
+
155
+ Ok(path_str.replace("\\", "/"))
157
156
  }
158
157
 
159
158
  fn get_path<const SIZE: usize, T: FileTypeTag>(
@@ -187,10 +186,10 @@ impl S3Storage {
187
186
 
188
187
  fn ref_key(&self, ref_key: &str) -> StorageResult<String> {
189
188
  let path = PathBuf::from_iter([self.prefix.as_str(), REF_PREFIX, ref_key]);
190
- path.into_os_string()
191
- .into_string()
192
- .map_err(StorageErrorKind::BadPrefix)
193
- .err_into()
189
+ let path_str =
190
+ path.into_os_string().into_string().map_err(StorageErrorKind::BadPrefix)?;
191
+
192
+ Ok(path_str.replace("\\", "/"))
194
193
  }
195
194
 
196
195
  async fn get_object_reader(
@@ -612,10 +611,7 @@ impl Storage for S3Storage {
612
611
  _settings: &Settings,
613
612
  prefix: &str,
614
613
  ) -> StorageResult<BoxStream<'a, StorageResult<ListInfo<String>>>> {
615
- let prefix = PathBuf::from_iter([self.prefix.as_str(), prefix])
616
- .into_os_string()
617
- .into_string()
618
- .map_err(StorageErrorKind::BadPrefix)?;
614
+ let prefix = format!("{}/{}", self.prefix, prefix).replace("//", "/");
619
615
  let stream = self
620
616
  .get_client()
621
617
  .await
@@ -798,4 +794,39 @@ mod tests {
798
794
  let deserialized: S3Storage = serde_json::from_str(&serialized).unwrap();
799
795
  assert_eq!(storage.config, deserialized.config);
800
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
+ }
801
832
  }
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "icechunk-python"
3
- version = "0.2.3"
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.3", features = ["logs"] }
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)
File without changes
File without changes
File without changes
File without changes
File without changes