Skill Tracer
Skills › Scientific Agent Skills › zarr-python › v3_migration.md

v3_migration.md

91 lines · skills/zarr-python/references/v3_migration.md at 5f2bc03

Open on GitHub
1# Zarr-Python 3 migration
2
3Targets **3.4.0**. Separate upgrading the Python package, migrating application APIs,
4and changing an existing store's on-disk format. Choosing `zarr_format=2` when creating
5with Zarr-Python 3 does not make its Python API compatible with code written for v2.
6Some scientific consumers still require a separate environment pinned to Zarr-Python 2.
7
8| Older API | Current guidance |
9|---|---|
10| `DirectoryStore` / `FSStore` | `zarr.storage.LocalStore` / `FsspecStore` |
11| `TempStore` | `tempfile.TemporaryDirectory` plus LocalStore |
12| `group.create_dataset` / `require_dataset` | `create_array` / `require_array` |
13| `group.foo` | `group["foo"]` |
14| `resize(n, m)` | `resize((n, m))` |
15| `compressor=` legacy creation | `compressors=` with the codec family appropriate to the on-disk format |
16| `synchronizer`, separate `chunk_store` | Not implemented for the v3 API; coordinate ownership externally |
17| `copy`, `copy_all`, `copy_store`, `Group.move` | Not implemented; use explicit validated copying in a new destination |
19Python 3.12+ and NumPy 2+ are required for the current package. Upstream states the
20Zarr-Python 2 support window ended; choosing an exact legacy pin is a compatibility
21choice, not a claim of current maintenance. Do not invent a Python upper bound for all
22v2 releases. Generic object dtype is ambiguous; choose a supported explicit dtype and
23validate consumer support for variable-length/string/extension data.

Zarr-Python 3 migration

Targets 3.4.0. Separate upgrading the Python package, migrating application APIs, and changing an existing store's on-disk format. Choosing zarr_format=2 when creating with Zarr-Python 3 does not make its Python API compatible with code written for v2. Some scientific consumers still require a separate environment pinned to Zarr-Python 2.

Older APICurrent guidance
DirectoryStore / FSStorezarr.storage.LocalStore / FsspecStore
TempStoretempfile.TemporaryDirectory plus LocalStore
group.create_dataset / require_datasetcreate_array / require_array
group.foogroup["foo"]
resize(n, m)resize((n, m))
compressor= legacy creationcompressors= with the codec family appropriate to the on-disk format
synchronizer, separate chunk_storeNot implemented for the v3 API; coordinate ownership externally
copy, copy_all, copy_store, Group.moveNot implemented; use explicit validated copying in a new destination

Python 3.12+ and NumPy 2+ are required for the current package. Upstream states the Zarr-Python 2 support window ended; choosing an exact legacy pin is a compatibility choice, not a claim of current maintenance. Do not invent a Python upper bound for all v2 releases. Generic object dtype is ambiguous; choose a supported explicit dtype and validate consumer support for variable-length/string/extension data.

Raw lines 1 to 24
25## Format-2 creation with the current package
27```python
28import numpy as np
29import zarr
30from numcodecs import Blosc
32legacy = zarr.create_array(
33 "legacy.zarr", data=np.arange(24, dtype="i4").reshape(6, 4), chunks=(2, 2),
34 zarr_format=2, compressors=Blosc(cname="zstd"),
35 attributes={"units": "counts"},
37assert legacy.metadata.zarr_format == 2
38```

Format-2 creation with the current package

import numpy as np
import zarr
from numcodecs import Blosc

legacy = zarr.create_array(
    "legacy.zarr", data=np.arange(24, dtype="i4").reshape(6, 4), chunks=(2, 2),
    zarr_format=2, compressors=Blosc(cname="zstd"),
    attributes={"units": "counts"},
)
assert legacy.metadata.zarr_format == 2
Raw lines 25 to 39
40## The CLI migrates metadata, not chunk data
42Install `zarr[cli]==3.4.0`. `zarr migrate v3 input.zarr output.zarr` writes new
43`zarr.json` metadata at the destination **without copying chunk payloads**. That output
44can open successfully while reading fill values instead of original data. Do not report
45it as a converted dataset. Test a **complete copy** of the source, then migrate in place
46on that copy; preserve the original until all consumers pass.
48Continuing the synthetic example above, copy the small closed local store:
50```python
51from shutil import copytree
52copytree("legacy.zarr", "migration-copy.zarr")
53```
55```bash
56zarr migrate v3 migration-copy.zarr --dry-run
57zarr migrate v3 migration-copy.zarr
58```
60Then verify both formats against the original source, including non-fill data:
62```python
63import numpy as np
64import zarr
66original = zarr.open_array("legacy.zarr", mode="r", zarr_format=2)
67converted = zarr.open_array("migration-copy.zarr", mode="r", zarr_format=3)
68np.testing.assert_array_equal(converted[:], original[:])
69assert converted.dtype == original.dtype
70assert dict(converted.attrs) == dict(original.attrs)
71```
73Only after validation and consumer compatibility checks, retire v2 metadata on the copy:
75```bash
76zarr remove-metadata v2 migration-copy.zarr --dry-run
77zarr remove-metadata v2 migration-copy.zarr
78```
80This is a local homogeneous numeric example, not a guarantee for all codecs/dtypes or
81remote hierarchies. Back up complete objects; list/metadata operations aren't snapshots.
82When both v2/v3 metadata exist, specify the intended format on open. For full conversion
83with changed chunks/codecs, create a new store and copy bounded selections, preserving
84scientific metadata deliberately.
86Rectilinear chunks remain experimental (`array.rectilinear_chunks=True`), and format-3
87consolidation remains experimental. Don't make either an accidental migration default.
89Sources: [migration guide](https://zarr.readthedocs.io/en/stable/user-guide/v3_migration/),
90[CLI](https://zarr.readthedocs.io/en/stable/user-guide/cli/),
91[released migration code](https://github.com/zarr-developers/zarr-python/blob/v3.4.0/src/zarr/metadata/migrate_v3.py).

The CLI migrates metadata, not chunk data

Install zarr[cli]==3.4.0. zarr migrate v3 input.zarr output.zarr writes new zarr.json metadata at the destination without copying chunk payloads. That output can open successfully while reading fill values instead of original data. Do not report it as a converted dataset. Test a complete copy of the source, then migrate in place on that copy; preserve the original until all consumers pass.

Continuing the synthetic example above, copy the small closed local store:

from shutil import copytree
copytree("legacy.zarr", "migration-copy.zarr")
zarr migrate v3 migration-copy.zarr --dry-run
zarr migrate v3 migration-copy.zarr

Then verify both formats against the original source, including non-fill data:

import numpy as np
import zarr

original = zarr.open_array("legacy.zarr", mode="r", zarr_format=2)
converted = zarr.open_array("migration-copy.zarr", mode="r", zarr_format=3)
np.testing.assert_array_equal(converted[:], original[:])
assert converted.dtype == original.dtype
assert dict(converted.attrs) == dict(original.attrs)

Only after validation and consumer compatibility checks, retire v2 metadata on the copy:

zarr remove-metadata v2 migration-copy.zarr --dry-run
zarr remove-metadata v2 migration-copy.zarr

This is a local homogeneous numeric example, not a guarantee for all codecs/dtypes or remote hierarchies. Back up complete objects; list/metadata operations aren't snapshots. When both v2/v3 metadata exist, specify the intended format on open. For full conversion with changed chunks/codecs, create a new store and copy bounded selections, preserving scientific metadata deliberately.

Rectilinear chunks remain experimental (array.rectilinear_chunks=True), and format-3 consolidation remains experimental. Don't make either an accidental migration default.

Sources: migration guide, CLI, released migration code.

Raw lines 40 to 91