rustytree-xarray 0.3.0__tar.gz → 0.5.0__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.
- rustytree_xarray-0.5.0/.github/dependabot.yml +73 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/.github/workflows/ci.yml +7 -7
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/.github/workflows/release.yml +8 -8
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/CHANGELOG.md +178 -1
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/Cargo.lock +294 -140
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/Cargo.toml +5 -5
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/PKG-INFO +2 -2
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/docs/architecture.md +13 -2
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/pyproject.toml +4 -2
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/python/rustytree/__init__.py +1 -1
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/python/rustytree/_array.py +30 -3
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/python/rustytree/backend.py +9 -6
- rustytree_xarray-0.5.0/src/array.rs +752 -0
- rustytree_xarray-0.5.0/src/dtype_dispatch.rs +82 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/lib.rs +6 -2
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/node.rs +8 -2
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/walk.rs +99 -33
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/conftest.py +61 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_backend_entrypoint.py +47 -12
- rustytree_xarray-0.5.0/tests/test_chunks.py +238 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_eager_fetch.py +10 -24
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_icechunk.py +9 -7
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_lazy.py +20 -15
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_phase1_scaffold.py +1 -1
- rustytree_xarray-0.5.0/tests/test_string_arrays.py +494 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_walk.py +25 -1
- rustytree_xarray-0.3.0/src/array.rs +0 -384
- rustytree_xarray-0.3.0/src/dtype_dispatch.rs +0 -82
- rustytree_xarray-0.3.0/tests/test_chunks.py +0 -98
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/.gitignore +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/LICENSE +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/README.md +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/assets/logo-banner-dark.png +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/assets/logo-banner-dark.svg +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/assets/logo-banner-light.png +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/assets/logo-banner-light.svg +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/assets/logo.png +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/docs/contributing.md +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/docs/release-process.md +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/docs/usage.md +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/notebooks/klot_demo.ipynb +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/error.rs +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/glob.rs +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/icechunk_store.rs +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/py_credentials.rs +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/runtime.rs +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/store.rs +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/src/url.rs +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_codecs.py +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_pickle.py +0 -0
- {rustytree_xarray-0.3.0 → rustytree_xarray-0.5.0}/tests/test_to_rust_source.py +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Dependabot version updates. Opens PRs on a schedule; nothing auto-merges —
|
|
2
|
+
# every PR is reviewed and merged by hand (including the grouped github-actions
|
|
3
|
+
# one). Security updates (CVE-triggered PRs) are enabled separately at the repo
|
|
4
|
+
# level, independent of this schedule.
|
|
5
|
+
#
|
|
6
|
+
# Deliberately NOT managed here (bumped by hand — coordinated, cross-manifest):
|
|
7
|
+
# - icechunk / typetag: FFI lockstep. The Python `icechunk` (pyproject) must
|
|
8
|
+
# share a minor with the Rust `icechunk` (`=2.1.0`) and `typetag`
|
|
9
|
+
# (`=0.2.22`) the crate links — the msgpack `Session` bytes format is
|
|
10
|
+
# coupled across the boundary, so a solo bump breaks `Session::from_bytes`
|
|
11
|
+
# (the 2.0.5→2.0.6 skew behind #46). Bump all three together manually.
|
|
12
|
+
# - ruff: pinned in pyproject AND hardcoded in ci.yml (`uvx ruff@0.15.8`),
|
|
13
|
+
# which Dependabot can't edit; a solo bump desyncs the lint gate and can
|
|
14
|
+
# churn formatting. Bump pyproject + both ci.yml literals together.
|
|
15
|
+
# - dtolnay/rust-toolchain@stable, pypa/gh-action-pypi-publish@release/v1:
|
|
16
|
+
# branch refs, not semver tags — Dependabot leaves them alone (no rule
|
|
17
|
+
# needed).
|
|
18
|
+
version: 2
|
|
19
|
+
|
|
20
|
+
updates:
|
|
21
|
+
# GitHub Actions — the `uses:` version pins in .github/workflows/* (exactly
|
|
22
|
+
# the manual toil of #54). One grouped PR per run.
|
|
23
|
+
- package-ecosystem: github-actions
|
|
24
|
+
directory: "/"
|
|
25
|
+
schedule:
|
|
26
|
+
interval: weekly
|
|
27
|
+
labels: ["dependencies"]
|
|
28
|
+
commit-message:
|
|
29
|
+
prefix: ci
|
|
30
|
+
groups:
|
|
31
|
+
actions:
|
|
32
|
+
patterns: ["*"]
|
|
33
|
+
|
|
34
|
+
# Rust crates (Cargo.toml / Cargo.lock).
|
|
35
|
+
- package-ecosystem: cargo
|
|
36
|
+
directory: "/"
|
|
37
|
+
schedule:
|
|
38
|
+
interval: weekly
|
|
39
|
+
labels: ["dependencies"]
|
|
40
|
+
commit-message:
|
|
41
|
+
prefix: deps
|
|
42
|
+
open-pull-requests-limit: 5
|
|
43
|
+
groups:
|
|
44
|
+
# Keep the zarrs family (zarrs, zarrs_storage, zarrs_object_store,
|
|
45
|
+
# zarrs_icechunk) moving together — they share a release cadence.
|
|
46
|
+
zarrs:
|
|
47
|
+
patterns: ["zarrs*"]
|
|
48
|
+
# pyo3 and numpy track matched 0.x minors (pyo3 0.28 ↔ numpy 0.28).
|
|
49
|
+
pyo3:
|
|
50
|
+
patterns: ["pyo3", "numpy"]
|
|
51
|
+
# Everything else: fold minor/patch into one PR; majors get their own.
|
|
52
|
+
cargo-minor:
|
|
53
|
+
update-types: ["minor", "patch"]
|
|
54
|
+
ignore:
|
|
55
|
+
- dependency-name: "icechunk" # FFI lockstep — bump by hand (see header)
|
|
56
|
+
- dependency-name: "typetag" # FFI lockstep — bump by hand (see header)
|
|
57
|
+
|
|
58
|
+
# Python deps (pyproject.toml: project deps + the `dev` extra).
|
|
59
|
+
- package-ecosystem: pip
|
|
60
|
+
directory: "/"
|
|
61
|
+
schedule:
|
|
62
|
+
interval: weekly
|
|
63
|
+
labels: ["dependencies"]
|
|
64
|
+
commit-message:
|
|
65
|
+
prefix: deps
|
|
66
|
+
open-pull-requests-limit: 5
|
|
67
|
+
groups:
|
|
68
|
+
# Fold minor/patch into one PR; majors get their own.
|
|
69
|
+
python:
|
|
70
|
+
update-types: ["minor", "patch"]
|
|
71
|
+
ignore:
|
|
72
|
+
- dependency-name: "icechunk" # FFI lockstep — bump by hand (see header)
|
|
73
|
+
- dependency-name: "ruff" # also hardcoded in ci.yml — bump by hand
|
|
@@ -24,8 +24,8 @@ jobs:
|
|
|
24
24
|
name: ruff (lint + format)
|
|
25
25
|
runs-on: ubuntu-latest
|
|
26
26
|
steps:
|
|
27
|
-
- uses: actions/checkout@
|
|
28
|
-
- uses: astral-sh/setup-uv@
|
|
27
|
+
- uses: actions/checkout@v7
|
|
28
|
+
- uses: astral-sh/setup-uv@v7
|
|
29
29
|
- run: uvx 'ruff@0.15.8' check .
|
|
30
30
|
- run: uvx 'ruff@0.15.8' format --check .
|
|
31
31
|
|
|
@@ -35,11 +35,11 @@ jobs:
|
|
|
35
35
|
name: cargo (fmt, clippy, test)
|
|
36
36
|
runs-on: ubuntu-latest
|
|
37
37
|
steps:
|
|
38
|
-
- uses: actions/checkout@
|
|
38
|
+
- uses: actions/checkout@v7
|
|
39
39
|
- uses: dtolnay/rust-toolchain@stable
|
|
40
40
|
with:
|
|
41
41
|
components: clippy, rustfmt
|
|
42
|
-
- uses: actions/setup-python@
|
|
42
|
+
- uses: actions/setup-python@v7
|
|
43
43
|
with:
|
|
44
44
|
python-version: "3.12"
|
|
45
45
|
- uses: Swatinem/rust-cache@v2
|
|
@@ -67,16 +67,16 @@ jobs:
|
|
|
67
67
|
matrix:
|
|
68
68
|
python-version: ["3.12"]
|
|
69
69
|
steps:
|
|
70
|
-
- uses: actions/checkout@
|
|
70
|
+
- uses: actions/checkout@v7
|
|
71
71
|
- uses: dtolnay/rust-toolchain@stable
|
|
72
72
|
- uses: Swatinem/rust-cache@v2
|
|
73
73
|
with:
|
|
74
74
|
# Keyed by Python version so each matrix cell gets its own cache.
|
|
75
75
|
key: py-${{ matrix.python-version }}
|
|
76
|
-
- uses: actions/setup-python@
|
|
76
|
+
- uses: actions/setup-python@v7
|
|
77
77
|
with:
|
|
78
78
|
python-version: ${{ matrix.python-version }}
|
|
79
|
-
- uses: astral-sh/setup-uv@
|
|
79
|
+
- uses: astral-sh/setup-uv@v7
|
|
80
80
|
- name: Set up venv and install maturin
|
|
81
81
|
run: |
|
|
82
82
|
uv venv --python "${{ matrix.python-version }}"
|
|
@@ -47,8 +47,8 @@ jobs:
|
|
|
47
47
|
python-version: ["3.12", "3.13"]
|
|
48
48
|
runs-on: ${{ matrix.platform.os }}
|
|
49
49
|
steps:
|
|
50
|
-
- uses: actions/checkout@
|
|
51
|
-
- uses: actions/setup-python@
|
|
50
|
+
- uses: actions/checkout@v7
|
|
51
|
+
- uses: actions/setup-python@v7
|
|
52
52
|
with:
|
|
53
53
|
python-version: ${{ matrix.python-version }}
|
|
54
54
|
- uses: dtolnay/rust-toolchain@stable
|
|
@@ -61,7 +61,7 @@ jobs:
|
|
|
61
61
|
target: ${{ matrix.platform.target }}
|
|
62
62
|
manylinux: ${{ matrix.platform.manylinux }}
|
|
63
63
|
args: --release --strip --out dist -i python${{ matrix.python-version }}
|
|
64
|
-
- uses: actions/upload-artifact@
|
|
64
|
+
- uses: actions/upload-artifact@v7
|
|
65
65
|
with:
|
|
66
66
|
name: wheel-${{ matrix.platform.target }}-py${{ matrix.python-version }}
|
|
67
67
|
path: dist/*.whl
|
|
@@ -71,12 +71,12 @@ jobs:
|
|
|
71
71
|
name: sdist
|
|
72
72
|
runs-on: ubuntu-latest
|
|
73
73
|
steps:
|
|
74
|
-
- uses: actions/checkout@
|
|
74
|
+
- uses: actions/checkout@v7
|
|
75
75
|
- uses: PyO3/maturin-action@v1
|
|
76
76
|
with:
|
|
77
77
|
command: sdist
|
|
78
78
|
args: --out dist
|
|
79
|
-
- uses: actions/upload-artifact@
|
|
79
|
+
- uses: actions/upload-artifact@v7
|
|
80
80
|
with:
|
|
81
81
|
name: sdist
|
|
82
82
|
path: dist/*.tar.gz
|
|
@@ -97,8 +97,8 @@ jobs:
|
|
|
97
97
|
group: release-${{ github.ref }}
|
|
98
98
|
cancel-in-progress: false
|
|
99
99
|
steps:
|
|
100
|
-
- uses: actions/checkout@
|
|
101
|
-
- uses: actions/download-artifact@
|
|
100
|
+
- uses: actions/checkout@v7
|
|
101
|
+
- uses: actions/download-artifact@v8
|
|
102
102
|
with:
|
|
103
103
|
path: dist
|
|
104
104
|
merge-multiple: true
|
|
@@ -128,7 +128,7 @@ jobs:
|
|
|
128
128
|
permissions:
|
|
129
129
|
id-token: write # mint short-lived OIDC tokens for trusted publishing
|
|
130
130
|
steps:
|
|
131
|
-
- uses: actions/download-artifact@
|
|
131
|
+
- uses: actions/download-artifact@v8
|
|
132
132
|
with:
|
|
133
133
|
path: dist
|
|
134
134
|
merge-multiple: true
|
|
@@ -11,6 +11,166 @@ release, that section is renamed to `[x.y.z] - YYYY-MM-DD` and a fresh
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.5.0] - 2026-07-26
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Eager-fetch small `object`-dtype (vlen `string`) scalars and self-named
|
|
19
|
+
1-D coords during the walk's Phase C ([#77]). `xr.open_datatree(engine=
|
|
20
|
+
"rustytree")` was paying one serial lazy read per `object`-dtype variable
|
|
21
|
+
at open time — xarray's `_contains_datetime_like_objects` samples every
|
|
22
|
+
such variable to rule out `cftime.datetime`, independent of the existing
|
|
23
|
+
CF-time-like/dim-coord triggers Phase C already covers. Extends the walk's
|
|
24
|
+
parallel pre-fetch to cover this case (bounded by a 4096-element count cap
|
|
25
|
+
and an 8 MiB total-byte-size cap, since per-element size is unbounded for
|
|
26
|
+
strings unlike the existing fixed-width numeric cap), and adds the
|
|
27
|
+
matching `object` → declared-read-dtype cast on the eager path in
|
|
28
|
+
`backend.py` (mirroring the lazy path's existing cast from #71). Scoped to
|
|
29
|
+
scalars and self-named 1-D coords only, so an ordinary small string data
|
|
30
|
+
variable doesn't lose its dask laziness just because it's small. Verified
|
|
31
|
+
on the live `s3://nexrad-arco/KLOT` store: ~48% faster `open_datatree`
|
|
32
|
+
(8.223s → 4.241s mean over 4 trials), 42 serial lazy reads eliminated.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Routine dependency and CI-action bumps via Dependabot ([#72], [#74],
|
|
37
|
+
[#75], [#76]). Cargo: `quinn-proto` 0.11.14 → 0.11.16 ([#72]); cargo-minor
|
|
38
|
+
group — `tokio` 1.53.0 → 1.53.1, `thiserror` 2.0.18 → 2.0.19, `async-trait`
|
|
39
|
+
0.1.89 → 0.1.91, `serde` 1.0.228 → 1.0.229, `zarrs_storage` 0.4.4 → 0.4.5,
|
|
40
|
+
`serde_json` 1.0.150 → 1.0.151 ([#75]); `zarrs_object_store` 0.6.2 → 0.7.0
|
|
41
|
+
([#76]). CI: `actions/setup-python` 6 → 7 ([#74]).
|
|
42
|
+
|
|
43
|
+
## [0.4.0] - 2026-07-24
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- Dependabot dependency automation ([#56]). A `.github/dependabot.yml` opens
|
|
48
|
+
weekly grouped version-update PRs for three ecosystems — `cargo`, `pip`
|
|
49
|
+
(pyproject), and `github-actions` — plus repo-level vulnerability alerts and
|
|
50
|
+
Dependabot security updates for CVE-triggered PRs. Nothing auto-merges; every
|
|
51
|
+
PR is reviewed by hand. `icechunk`/`typetag` (FFI lockstep) and `ruff` (also
|
|
52
|
+
pinned in `ci.yml`) are intentionally ignored and stay manual, coordinated
|
|
53
|
+
bumps.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- Bump `zarrs` 0.22 → 0.23 ([#60]). A breaking upstream release: `DataType`
|
|
58
|
+
became a newtype over `Arc<dyn DataTypeTraits>` rather than an enum, so the
|
|
59
|
+
shared `for_each_supported_dtype!` dispatch is now an
|
|
60
|
+
`is::<Float64DataType>()` chain against the marker types in
|
|
61
|
+
`zarrs::array::data_type`. `ArraySubset` moved from the removed
|
|
62
|
+
`zarrs::array_subset` module into `zarrs::array`, and
|
|
63
|
+
`async_retrieve_array_subset_elements::<T>` (deprecated in 0.23, already
|
|
64
|
+
deleted upstream for 0.24) became `async_retrieve_array_subset::<Vec<T>>`.
|
|
65
|
+
The supported-dtype set, the read path, and the storage stack are otherwise
|
|
66
|
+
unchanged — `zarrs_storage` still resolves to a single 0.4.x, so
|
|
67
|
+
`zarrs_object_store` and `zarrs_icechunk` needed no bump and the icechunk
|
|
68
|
+
FFI lockstep is untouched.
|
|
69
|
+
- Fixes a dtype string that 0.23 would have silently corrupted: the walk
|
|
70
|
+
built `VarMeta::dtype` via `format!("{}", array.data_type())`, and 0.23's
|
|
71
|
+
`Display` renders *both* Zarr spellings when they differ (`float64` →
|
|
72
|
+
`"float64 / <f8"`), which `numpy.dtype()` rejects. Both walk sites now
|
|
73
|
+
route through `zarrs_dtype_to_numpy_str`, the same canonical mapper the
|
|
74
|
+
array handle already used.
|
|
75
|
+
- `zarrs_dtype_to_numpy_str` now reads the dtype's Zarr V3 name (identical
|
|
76
|
+
to the NumPy name for all thirteen dtypes we can name; pinned by a new
|
|
77
|
+
unit test) instead of maintaining a parallel hand-written table. The one
|
|
78
|
+
exception is `bytes`, reported as `object` to match zarr-python —
|
|
79
|
+
`np.dtype("bytes")` is `|S0`, which would mislabel a variable-length
|
|
80
|
+
binary array rather than fail. Dtypes we can neither read nor safely
|
|
81
|
+
rename (`string`, `numpy.datetime64`, `r32`, …) still surface as a
|
|
82
|
+
`TypeError` from `np.dtype()` at open, as before.
|
|
83
|
+
|
|
84
|
+
- CI: bump GitHub Actions off the deprecated Node 20 runtime ([#55], fixes #54).
|
|
85
|
+
`actions/checkout` v4 → v5, `actions/setup-python` v5 → v6,
|
|
86
|
+
`actions/upload-artifact` v4 → v6, `actions/download-artifact` v4 → v7 — the
|
|
87
|
+
lowest major of each that runs on Node 24 (verified via each tag's
|
|
88
|
+
`runs.using`; the artifact actions only moved to Node 24 at v6/v7, so a naïve
|
|
89
|
+
bump to v5 would still have been Node 20). No workflow behaviour change.
|
|
90
|
+
|
|
91
|
+
- Raise the NumPy floor `numpy>=1.24` → `numpy>=2.0` ([#71]). Variable-length
|
|
92
|
+
`string` arrays are surfaced as numpy 2's variable-width `StringDType`
|
|
93
|
+
(`np.dtype("T")`), which did not exist before 2.0. rustytree's other pins
|
|
94
|
+
(`zarr>=3`, recent `xarray`) already track numpy 2, so this only makes an
|
|
95
|
+
existing expectation explicit.
|
|
96
|
+
|
|
97
|
+
- Routine dependency and CI-action bumps via Dependabot ([#57], [#58], [#59],
|
|
98
|
+
[#64]) — the first batch after the automation ([#56]) landed. Cargo: `tokio`
|
|
99
|
+
1.52.3 → 1.53.0, `futures` 0.3.32 → 0.3.33, `zarrs_storage` 0.4.3 → 0.4.4
|
|
100
|
+
([#64]); `chrono` 0.4.44 → 0.4.45, `zarrs_icechunk` 0.5.0 → 0.5.1 ([#59]);
|
|
101
|
+
`cmov` 0.5.3 → 0.5.4 ([#57]). CI actions ([#58]): `actions/checkout` 5 → 7,
|
|
102
|
+
`astral-sh/setup-uv` 4 → 7, `actions/upload-artifact` 6 → 7, and
|
|
103
|
+
`actions/download-artifact` 7 → 8 — superseding the v5/v6/v7 pins the [#55]
|
|
104
|
+
entry above describes.
|
|
105
|
+
|
|
106
|
+
### Fixed
|
|
107
|
+
|
|
108
|
+
- Zarr v3 string arrays now open and read instead of crashing ([#71], fixes
|
|
109
|
+
#70). Both v3 string flavours failed before: a variable-length `string` array
|
|
110
|
+
raised `TypeError: data type 'string' not understood` (its name reached
|
|
111
|
+
`np.dtype()` unmapped), and a `fixed_length_utf32` array (numpy `<U…`,
|
|
112
|
+
xarray's default `str` encoding) raised `NotImplementedError` at read. This
|
|
113
|
+
became a production regression when raw2zarr's FM301 retrofit added
|
|
114
|
+
`sweep_mode`/`prt_mode`/`follow_mode` as vlen-`string` scalars to the KLOT
|
|
115
|
+
eager store and the Serbian OSN stores, forcing consumers to fall back to the
|
|
116
|
+
slower `engine="zarr"`. rustytree now mirrors `engine="zarr"` for both
|
|
117
|
+
flavours — `xr.testing.assert_identical` holds against it for all
|
|
118
|
+
valid-Unicode content (2-D chunking, interior NULs, non-BMP code points,
|
|
119
|
+
empty strings, and unwritten-chunk fill values all included):
|
|
120
|
+
- **vlen `string`** is *declared* `object` but its values *materialise* as
|
|
121
|
+
numpy-2 `StringDType`. That declared/read split is exactly what
|
|
122
|
+
`engine="zarr"` produces: xarray's CF-decode flattens a
|
|
123
|
+
`StringDType`-declared variable's values back to `object`, so declaring
|
|
124
|
+
`object` up-front is the only way to keep `StringDType` values. The `numpy`
|
|
125
|
+
crate can only build `object` arrays across the FFI boundary, so the read
|
|
126
|
+
returns `object` and `RustyBackendArray` casts to the dtype the new
|
|
127
|
+
`ZarrsArrayHandle.read_dtype` reports.
|
|
128
|
+
- **`fixed_length_utf32`** → fixed-width `<U{n}` (`n` code points). zarrs 0.23
|
|
129
|
+
opens this dtype (0.22 could not); rustytree decodes the native-endian
|
|
130
|
+
UTF-32 to `str` and builds the `<U` array. One documented divergence: lone
|
|
131
|
+
surrogate code points (U+D800–U+DFFF, malformed Unicode) are dropped rather
|
|
132
|
+
than preserved, because the decode goes through Rust `char`.
|
|
133
|
+
- `slice_nd`'s bound relaxed from `T: Copy` to `T: Clone` so the same slicer
|
|
134
|
+
serves the `String` buffers; zero-cost for the numeric arms.
|
|
135
|
+
|
|
136
|
+
- An empty selection no longer returns a stray element or panics ([#68], fixes
|
|
137
|
+
#65). `isel(time=slice(1, 1))` and friends returned one bogus element whenever
|
|
138
|
+
the offset was not a multiple of the chunk size, and raised
|
|
139
|
+
`pyo3_runtime.PanicException` when the selection sat at the end of a ragged
|
|
140
|
+
final chunk (e.g. `slice(13, 13)` on a shape-13 array with chunks of 4).
|
|
141
|
+
Raggedness was needed only for the panic — the wrong length happened on any
|
|
142
|
+
non-chunk-aligned offset, including on arrays whose shape divides evenly.
|
|
143
|
+
`slice_nd`'s walk was a do-while that pushed an element before it could test
|
|
144
|
+
the bounds; it is now driven by the output element count, so an empty request
|
|
145
|
+
runs zero iterations and totality is structural rather than a guard. The panic
|
|
146
|
+
mattered beyond the wrong length: `PanicException` derives from
|
|
147
|
+
`BaseException`, so it passed straight through ordinary `except Exception:`
|
|
148
|
+
handlers. Empty selections also short-circuit before the chunk-alignment step
|
|
149
|
+
now, so they no longer pull a chunk off the network to return nothing.
|
|
150
|
+
|
|
151
|
+
- A reversed slice is empty rather than an error ([#68]). `v.isel(n=slice(5, 3))`
|
|
152
|
+
and `v[5:3]` raised `ValueError: start 5 > stop 3`, where numpy, pandas and
|
|
153
|
+
`engine="zarr"` all return an empty array. `slice.indices()` reports a reversed
|
|
154
|
+
slice faithfully as `(5, 3, 1)`, and that pair reached `read_subset` unchanged;
|
|
155
|
+
the Python adapter now normalises it. `read_subset` keeps its stricter
|
|
156
|
+
`start <= stop` contract, so a genuinely malformed range still raises.
|
|
157
|
+
|
|
158
|
+
- Tests: the two opt-in KTWX smoke tests now skip when the directory exists but
|
|
159
|
+
holds no icechunk repository ([#60]). The guard tested `KTWX_PATH.exists()`,
|
|
160
|
+
so an empty leftover directory failed the guard's purpose and the tests
|
|
161
|
+
errored with `KeyError: group / not found in store` instead of skipping. The
|
|
162
|
+
shared `ktwx_repo_available()` helper in `tests/conftest.py` now mirrors
|
|
163
|
+
rustytree's own detector (`looks_like_icechunk_repo`): a `repo` manifest file
|
|
164
|
+
plus a `snapshots/` directory.
|
|
165
|
+
|
|
166
|
+
### Security
|
|
167
|
+
|
|
168
|
+
- Bump `pyo3` and `numpy` 0.28 → 0.29 ([#61]) to fix a **high**-severity
|
|
169
|
+
out-of-bounds read in PyO3's `PyIterator` `nth`/`nth_back` (RUSTSEC/GHSA)
|
|
170
|
+
plus a medium-severity missing `Sync` bound on `PyCFunction::new_closure`.
|
|
171
|
+
A clean bump — no source changes; the pyo3/numpy majors move in lockstep.
|
|
172
|
+
(Surfaced by the newly-enabled Dependabot security alerts.)
|
|
173
|
+
|
|
14
174
|
## [0.3.0] - 2026-07-04
|
|
15
175
|
|
|
16
176
|
### Added
|
|
@@ -704,7 +864,9 @@ below.
|
|
|
704
864
|
intentionally not normalized — relative-vs-absolute glob
|
|
705
865
|
semantics differ in `PurePosixPath.match`.
|
|
706
866
|
|
|
707
|
-
[Unreleased]: https://github.com/aladinor/rustytree/compare/v0.
|
|
867
|
+
[Unreleased]: https://github.com/aladinor/rustytree/compare/v0.5.0...HEAD
|
|
868
|
+
[0.5.0]: https://github.com/aladinor/rustytree/compare/v0.4.0...v0.5.0
|
|
869
|
+
[0.4.0]: https://github.com/aladinor/rustytree/compare/v0.3.0...v0.4.0
|
|
708
870
|
[0.3.0]: https://github.com/aladinor/rustytree/compare/v0.2.1...v0.3.0
|
|
709
871
|
[0.2.1]: https://github.com/aladinor/rustytree/compare/v0.2.0...v0.2.1
|
|
710
872
|
[0.2.0]: https://github.com/aladinor/rustytree/compare/v0.1.0...v0.2.0
|
|
@@ -742,3 +904,18 @@ below.
|
|
|
742
904
|
[#49]: https://github.com/aladinor/rustytree/pull/49
|
|
743
905
|
[#50]: https://github.com/aladinor/rustytree/pull/50
|
|
744
906
|
[#52]: https://github.com/aladinor/rustytree/pull/52
|
|
907
|
+
[#55]: https://github.com/aladinor/rustytree/pull/55
|
|
908
|
+
[#56]: https://github.com/aladinor/rustytree/pull/56
|
|
909
|
+
[#57]: https://github.com/aladinor/rustytree/pull/57
|
|
910
|
+
[#58]: https://github.com/aladinor/rustytree/pull/58
|
|
911
|
+
[#59]: https://github.com/aladinor/rustytree/pull/59
|
|
912
|
+
[#60]: https://github.com/aladinor/rustytree/pull/60
|
|
913
|
+
[#61]: https://github.com/aladinor/rustytree/pull/61
|
|
914
|
+
[#64]: https://github.com/aladinor/rustytree/pull/64
|
|
915
|
+
[#68]: https://github.com/aladinor/rustytree/pull/68
|
|
916
|
+
[#71]: https://github.com/aladinor/rustytree/pull/71
|
|
917
|
+
[#72]: https://github.com/aladinor/rustytree/pull/72
|
|
918
|
+
[#74]: https://github.com/aladinor/rustytree/pull/74
|
|
919
|
+
[#75]: https://github.com/aladinor/rustytree/pull/75
|
|
920
|
+
[#76]: https://github.com/aladinor/rustytree/pull/76
|
|
921
|
+
[#77]: https://github.com/aladinor/rustytree/pull/77
|