Skip to content

Commit d4c5940

Browse files
committed
fix: handle dropped dims
1 parent 34bd6af commit d4c5940

5 files changed

Lines changed: 24 additions & 29 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ crate-type = ["cdylib", "rlib"]
1010

1111
[dependencies]
1212
pyo3 = { version = "0.27.1", features = ["abi3-py311"] }
13-
zarrs = { version = "0.23.0", features = ["async", "zlib", "pcodec", "bz2"] }
13+
zarrs = { version = "0.23.6", features = ["async", "zlib", "pcodec", "bz2"] }
1414
rayon_iter_concurrent_limit = "0.2.0"
1515
rayon = "1.10.0"
1616
# fix for https://stackoverflow.com/questions/76593417/package-openssl-was-not-found-in-the-pkg-config-search-path

python/zarrs/utils.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def make_chunk_info_for_rust_with_indices(
6060
drop_axes: tuple[int, ...],
6161
shape: tuple[int, ...],
6262
) -> RustChunkInfo:
63-
shape = shape if shape else (1,) # constant array
63+
is_shape_constant = shape == ()
6464
chunk_info_with_indices: list[ChunkItem] = []
6565
write_empty_chunks: bool = True
6666
for (
@@ -71,15 +71,28 @@ def make_chunk_info_for_rust_with_indices(
7171
_,
7272
) in batch_info:
7373
write_empty_chunks = chunk_spec.config.write_empty_chunks
74-
out_selection_as_slices = selector_tuple_to_slice_selection(out_selection)
7574
chunk_selection_as_slices = selector_tuple_to_slice_selection(chunk_selection)
75+
out_selection_as_slices_iter = iter(selector_tuple_to_slice_selection(out_selection))
76+
out_selection_as_slices_expanded = list(next(out_selection_as_slices_iter) if not isinstance(c, int) else slice(0, 1) for c in chunk_selection)
77+
if is_shape_constant:
78+
io_array_shape = (1,)
79+
else:
80+
shape_iter = iter(shape)
81+
try:
82+
io_array_shape = list(next(shape_iter) if not isinstance(c, int) else 1 for c in chunk_selection)
83+
except RuntimeError as e:
84+
if isinstance(e.__cause__, StopIteration):
85+
raise IndexError(
86+
f"the size of the chunk subset {chunk_selection} and input/output subset {shape} are incompatible"
87+
) from None
88+
raise
7689
chunk_info_with_indices.append(
7790
ChunkItem(
7891
key=byte_getter.path,
7992
chunk_subset=chunk_selection_as_slices,
8093
chunk_shape=chunk_spec.shape,
81-
subset=out_selection_as_slices,
82-
shape=shape,
94+
subset=out_selection_as_slices_expanded,
95+
shape=io_array_shape,
8396
)
8497
)
8598
return RustChunkInfo(chunk_info_with_indices, write_empty_chunks)

src/chunk_item.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub(crate) struct ChunkItem {
3131
pub chunk_subset: ArraySubset,
3232
pub subset: ArraySubset,
3333
pub shape: Vec<NonZeroU64>,
34+
pub output_shape: Vec<NonZeroU64>,
3435
pub num_elements: u64,
3536
}
3637

@@ -65,6 +66,7 @@ impl ChunkItem {
6566
subset,
6667
shape: chunk_shape_nonzero_u64,
6768
num_elements,
69+
output_shape: shape_nonzero_u64
6870
})
6971
}
7072
}

src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ mod utils;
3838

3939
use crate::concurrency::ChunkConcurrentLimitAndCodecOptions;
4040
use crate::store::StoreConfig;
41-
use crate::utils::{PyCodecErrExt, PyErrExt as _, PyUntypedArrayExt as _};
41+
use crate::utils::{PyCodecErrExt, PyErrExt as _};
4242

4343
// TODO: Use a OnceLock for store with get_or_try_init when stabilised?
4444
#[gen_stub_pyclass]
@@ -288,7 +288,6 @@ impl CodecPipelineImpl {
288288
) -> PyResult<()> {
289289
// Get input array
290290
let output = Self::nparray_to_unsafe_cell_slice(value)?;
291-
let output_shape: Vec<u64> = value.shape_zarr()?;
292291

293292
// Adjust the concurrency based on the codec chain and the first chunk description
294293
let Some((chunk_concurrent_limit, codec_options)) =
@@ -343,7 +342,7 @@ impl CodecPipelineImpl {
343342
.fixed_size()
344343
.ok_or("variable length data type not supported")
345344
.map_py_err::<PyTypeError>()?,
346-
&output_shape,
345+
bytemuck::must_cast_slice::<_, u64>(&item.output_shape),
347346
item.subset.clone(),
348347
)
349348
.map_py_err::<PyRuntimeError>()?
@@ -410,7 +409,6 @@ impl CodecPipelineImpl {
410409
} else {
411410
InputValue::Constant(FillValue::new(input_slice.to_vec()))
412411
};
413-
let input_shape: Vec<u64> = value.shape_zarr()?;
414412

415413
// Adjust the concurrency based on the codec chain and the first chunk description
416414
let Some((chunk_concurrent_limit, mut codec_options)) =
@@ -424,7 +422,7 @@ impl CodecPipelineImpl {
424422
let store_chunk = |item: ChunkItem| match &input {
425423
InputValue::Array(input) => {
426424
let chunk_subset_bytes = input
427-
.extract_array_subset(&item.subset, &input_shape, &self.data_type)
425+
.extract_array_subset(&item.subset, bytemuck::must_cast_slice::<_, u64>(&item.output_shape), &self.data_type)
428426
.map_codec_err()?;
429427
self.store_chunk_subset_bytes(
430428
&item,

src/utils.rs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::fmt::Display;
22

3-
use numpy::{PyUntypedArray, PyUntypedArrayMethods};
4-
use pyo3::{Bound, PyErr, PyResult, PyTypeInfo};
3+
use pyo3::{PyErr, PyResult, PyTypeInfo};
54
use zarrs::array::CodecError;
65

76
use crate::ChunkItem;
@@ -38,23 +37,6 @@ impl<T> PyCodecErrExt<T> for Result<T, CodecError> {
3837
}
3938
}
4039

41-
pub(crate) trait PyUntypedArrayExt {
42-
fn shape_zarr(&self) -> PyResult<Vec<u64>>;
43-
}
44-
45-
impl PyUntypedArrayExt for Bound<'_, PyUntypedArray> {
46-
fn shape_zarr(&self) -> PyResult<Vec<u64>> {
47-
Ok(if self.shape().is_empty() {
48-
vec![1] // scalar value
49-
} else {
50-
self.shape()
51-
.iter()
52-
.map(|&i| u64::try_from(i))
53-
.collect::<Result<_, _>>()?
54-
})
55-
}
56-
}
57-
5840
pub fn is_whole_chunk(item: &ChunkItem) -> bool {
5941
item.chunk_subset.start().iter().all(|&o| o == 0)
6042
&& item.chunk_subset.shape() == bytemuck::must_cast_slice::<_, u64>(&item.shape)

0 commit comments

Comments
 (0)