diff --git a/.gitignore b/.gitignore index 3586d30..71834d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,13 @@ # Folder for generating test Zarr files -test_files/ +test_files/ + +# Coverage artifacts produced by tools/run_coverage.m +test/coverageReport/ +test/cobertura.xml +test/coverage_results.mat + +# Leaked by tZarrRead/tooBigArray (runs outside a WorkingFolderFixture) +test/bigData/ # Windows default autosave extension *.asv @@ -10,3 +18,8 @@ test_files/ # Bytecode-compiled version of python code PythonModule/__pycache__ *.pyc +.venv-zarr/ + +# Local Claude Code profile (per-developer, not shared) +.claude/ +.claude-profiles diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..21b3f7e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,63 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +MATLAB interface for reading and writing Zarr v2 arrays and metadata, from both local storage and Amazon S3. The MATLAB layer delegates the actual Zarr I/O to Google's [tensorstore](https://github.com/google/tensorstore) Python library, which it calls through MATLAB's `py.` Python bridge. + +## Architecture + +The codebase is a three-language stack. Data and type information flow across all three layers, so a change to the data path usually touches each: + +1. **User-facing MATLAB functions** (`zarrread.m`, `zarrwrite.m`, `zarrcreate.m`, `zarrinfo.m`, `zarrwriteatt.m`) — thin wrappers that do `arguments`-block input validation and construct a `Zarr` object. These are the documented public API. + +2. **`Zarr.m`** — the central gateway class (`classdef Zarr < handle`). It owns the connection between MATLAB and Python: bootstrapping the Python module path (`pySetup`/`ZarrPy`), building the tensorstore KVStore schema (local `file` driver vs. S3 `s3` driver), resolving/creating paths and Zarr groups, validating partial-read parameters, and converting between MATLAB and numpy arrays. Most non-trivial logic lives here as static helper methods. + +3. **`PythonModule/ZarrPy.py`** — a small wrapper over tensorstore. Exposes `createKVStore`, `createZarr`, `writeZarr`, `readZarr`. This is the only code that talks to tensorstore directly. `Zarr.m` imports it via `py.importlib.import_module('ZarrPy')` after inserting `PythonModule/` onto `py.sys.path`. + +### Key cross-cutting concerns + +- **Datatype mapping** (`ZarrDatatype.m`): a single class holds three parallel arrays mapping MATLAB types ↔ tensorstore types ↔ Zarr dtype strings (e.g. `"double"` ↔ `"float64"` ↔ `".m` in `test/`. They inherit shared fixtures from `SharedZarrTestSetup.m`, which adds the parent source folder to the path and copies `test/dataFiles/` into a `WorkingFolderFixture` so write tests don't pollute the repo. Read-test fixtures live in `test/dataFiles/grp_v2` (and `grp_v3`); expected results are stored in `expZarrArrData.mat` / `expZarrArrInfo.mat`. + +## Conventions + +- All error messages use `error("MATLAB::", ...)` identifiers — match the existing namespacing when adding new ones. +- Function help text is the block comment directly under the signature; keep it current since the README points users to `help `. +- Spelling is checked in CI by codespell (`.codespellrc`); add false positives to `ignore-words-list`. diff --git a/codecov.yml b/codecov.yml index 23a0e90..ed2418a 100644 --- a/codecov.yml +++ b/codecov.yml @@ -5,4 +5,5 @@ coverage: target: 85% threshold: 5% ignore: - - "test/*" \ No newline at end of file + - "test/*" + - "tools/*" \ No newline at end of file diff --git a/test/tZarr.m b/test/tZarr.m index 8bdad5c..37500cb 100644 --- a/test/tZarr.m +++ b/test/tZarr.m @@ -35,6 +35,104 @@ function verifyReload(testcase) end - + function verifyIsZarrArrayAndGroup(testcase) + % Verify that isZarrArray and isZarrGroup correctly identify a + % Zarr array (has .zarray) versus a Zarr group (has .zgroup). + % SharedZarrTestSetup copies the *contents* of dataFiles into + % the working folder, so fixtures live at grp_v2/... directly. + arrPath = "grp_v2/arr_v2"; + grpPath = "grp_v2"; + + testcase.verifyTrue(Zarr.isZarrArray(arrPath),... + "Expected an array path to be a Zarr array."); + testcase.verifyFalse(Zarr.isZarrArray(grpPath),... + "Did not expect a group path to be a Zarr array."); + + testcase.verifyTrue(Zarr.isZarrGroup(grpPath),... + "Expected a group path to be a Zarr group."); + testcase.verifyFalse(Zarr.isZarrGroup(arrPath),... + "Did not expect an array path to be a Zarr group."); + end + + function verifyDatatypeRoundTrip(testcase) + % Verify that ZarrDatatype maps consistently across MATLAB, + % Tensorstore, and Zarr type names, regardless of which static + % constructor is used to create it. + mlType = "double"; + tsType = "float64"; + zType = "