diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e61de0..78a3628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,6 +91,9 @@ API: `File::dataset_at(address)` opens a dataset without resolving a path. libhdf5's `h5stat_newgrat.h5` (35001 members in the root): listing takes 0.03 s and 2000 opens 1 ms (h5py: 0.022 s). +- **`ds[np.array(1)]` is an integer index**, as in h5py; a 0-d integer + array went down the index-list path and raised a confusing `TypeError`. + The h5py comparison keys now include 0-d arrays on every axis. - **CI builds and tests the Python package.** It was excluded from CI. `scripts/ci-test.sh` now lints `clawhdf5-py`, builds the wheel with maturin, unpacks it under `target/` and runs the pytest suite; skipped diff --git a/crates/clawhdf5-py/src/select.rs b/crates/clawhdf5-py/src/select.rs index 6b358b9..7c52442 100644 --- a/crates/clawhdf5-py/src/select.rs +++ b/crates/clawhdf5-py/src/select.rs @@ -361,6 +361,14 @@ fn parse_axis(py: Python<'_>, a: &Bound<'_, PyAny>, n: u64) -> PyResult { let is_array_like = a.is_instance(&np.getattr("ndarray")?)? || a.is_instance_of::() || a.is_instance_of::(); + // A 0-d integer array (`ds[np.array(1)]`) is an integer index, as in h5py. + if a.is_instance(&np.getattr("ndarray")?)? && a.getattr("ndim")?.extract::()? == 0 { + let kind: String = a.getattr("dtype")?.getattr("kind")?.extract()?; + if kind == "i" || kind == "u" { + let i: i128 = a.call_method0("item")?.extract()?; + return Ok(Axis::Index(normalize(i, n)?)); + } + } if !is_bool && !is_array_like && a.hasattr("__index__")? { let i: i128 = a.call_method0("__index__")?.extract()?; return Ok(Axis::Index(normalize(i, n)?)); diff --git a/crates/clawhdf5-py/tests/test_read_vs_h5py.py b/crates/clawhdf5-py/tests/test_read_vs_h5py.py index a02484c..cbac1e4 100644 --- a/crates/clawhdf5-py/tests/test_read_vs_h5py.py +++ b/crates/clawhdf5-py/tests/test_read_vs_h5py.py @@ -234,7 +234,8 @@ def assert_same(ours, theirs, what=""): def keys_for(shape): if shape == (): return [(), Ellipsis] - keys = [(), Ellipsis, 0, -1, slice(None), slice(None, None, 2), slice(1, None, 3), slice(0, 0), np.int64(0)] + keys = [(), Ellipsis, 0, -1, slice(None), slice(None, None, 2), slice(1, None, 3), slice(0, 0), np.int64(0), + np.array(0), np.array(-1, dtype="i1")] n0 = shape[0] if n0 == 0: return [(), Ellipsis, slice(None), slice(None, None, 2), slice(0, 0)] @@ -252,6 +253,8 @@ def keys_for(shape): (slice(None), [0, n1 - 1] if n1 > 1 else [0]), (slice(None, None, 2), 1), (slice(0, 2), slice(3, 1)), + (np.array(1) if n0 > 1 else np.array(0), slice(None)), + (slice(None), np.array(n1 - 1, dtype="u2")), ] if len(shape) >= 3: keys += [(0, slice(None), -1), (slice(1, None, 2), 2, slice(None, None, 3)), (Ellipsis, 0, 0), (0, Ellipsis, 1)]