zarrsmith 0.6.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.
Files changed (145) hide show
  1. zarrsmith-0.6.0/.github/scripts/next_version.py +69 -0
  2. zarrsmith-0.6.0/.github/workflows/docker-publish.yml +75 -0
  3. zarrsmith-0.6.0/.github/workflows/documentation.yml +38 -0
  4. zarrsmith-0.6.0/.github/workflows/release.yml +116 -0
  5. zarrsmith-0.6.0/.github/workflows/tests.yml +34 -0
  6. zarrsmith-0.6.0/.gitignore +15 -0
  7. zarrsmith-0.6.0/Dockerfile +39 -0
  8. zarrsmith-0.6.0/LICENSE +21 -0
  9. zarrsmith-0.6.0/MANIFEST.in +2 -0
  10. zarrsmith-0.6.0/PKG-INFO +177 -0
  11. zarrsmith-0.6.0/README.md +108 -0
  12. zarrsmith-0.6.0/documentation/Makefile +20 -0
  13. zarrsmith-0.6.0/documentation/advanced.md +75 -0
  14. zarrsmith-0.6.0/documentation/api_reference.rst +16 -0
  15. zarrsmith-0.6.0/documentation/chromatic-shift-after.png +0 -0
  16. zarrsmith-0.6.0/documentation/chromatic-shift-before.png +0 -0
  17. zarrsmith-0.6.0/documentation/chromatic-shift.md +141 -0
  18. zarrsmith-0.6.0/documentation/cli.md +143 -0
  19. zarrsmith-0.6.0/documentation/conf.py +91 -0
  20. zarrsmith-0.6.0/documentation/contributing.md +186 -0
  21. zarrsmith-0.6.0/documentation/index.md +50 -0
  22. zarrsmith-0.6.0/documentation/installation.md +56 -0
  23. zarrsmith-0.6.0/documentation/instructions_for_gif.txt +3 -0
  24. zarrsmith-0.6.0/documentation/make.bat +35 -0
  25. zarrsmith-0.6.0/documentation/mosaic-demo.png +0 -0
  26. zarrsmith-0.6.0/documentation/mosaic.md +198 -0
  27. zarrsmith-0.6.0/documentation/napari-demo.png +0 -0
  28. zarrsmith-0.6.0/documentation/napari-plugin.md +71 -0
  29. zarrsmith-0.6.0/documentation/objects-explorer.gif +0 -0
  30. zarrsmith-0.6.0/documentation/palette.png +0 -0
  31. zarrsmith-0.6.0/documentation/python-api.md +121 -0
  32. zarrsmith-0.6.0/documentation/readers.md +36 -0
  33. zarrsmith-0.6.0/examples/00_installation_and_mental_model.ipynb +245 -0
  34. zarrsmith-0.6.0/examples/01_read_microscope_datasets_templates.ipynb +302 -0
  35. zarrsmith-0.6.0/examples/02_array_manager_from_numpy_dask.ipynb +239 -0
  36. zarrsmith-0.6.0/examples/03_create_ome_zarr_with_metadata.ipynb +245 -0
  37. zarrsmith-0.6.0/examples/04_read_zarr_inspect_groups_labels.ipynb +271 -0
  38. zarrsmith-0.6.0/examples/05_add_groups_and_write_image_regions.ipynb +253 -0
  39. zarrsmith-0.6.0/examples/06_labels_append_inside_existing_zarr.ipynb +324 -0
  40. zarrsmith-0.6.0/examples/07_create_new_zarr_dataset_with_labels.ipynb +605 -0
  41. zarrsmith-0.6.0/examples/08_metadata_subset_pyramid_and_channels.ipynb +302 -0
  42. zarrsmith-0.6.0/examples/09_legacy_options_v04_and_troubleshooting.ipynb +342 -0
  43. zarrsmith-0.6.0/examples/10_mosaic_fusion.ipynb +371 -0
  44. zarrsmith-0.6.0/examples/README.md +36 -0
  45. zarrsmith-0.6.0/examples/label_features_explorer.py +49 -0
  46. zarrsmith-0.6.0/examples/manifest.json +17 -0
  47. zarrsmith-0.6.0/examples/test_batch.csv +2 -0
  48. zarrsmith-0.6.0/pyproject.toml +109 -0
  49. zarrsmith-0.6.0/setup.cfg +4 -0
  50. zarrsmith-0.6.0/tests/__init__.py +0 -0
  51. zarrsmith-0.6.0/tests/conftest.py +65 -0
  52. zarrsmith-0.6.0/tests/test_anisotropic_downsampling.py +101 -0
  53. zarrsmith-0.6.0/tests/test_channel_colors.py +38 -0
  54. zarrsmith-0.6.0/tests/test_chromatic_shift.py +319 -0
  55. zarrsmith-0.6.0/tests/test_cli_chromatic_shift.py +117 -0
  56. zarrsmith-0.6.0/tests/test_cli_mosaic.py +242 -0
  57. zarrsmith-0.6.0/tests/test_cli_shards.py +226 -0
  58. zarrsmith-0.6.0/tests/test_drop_singleton.py +135 -0
  59. zarrsmith-0.6.0/tests/test_evident_manager.py +249 -0
  60. zarrsmith-0.6.0/tests/test_fusion_regions.py +110 -0
  61. zarrsmith-0.6.0/tests/test_luxendo_mosaic.py +116 -0
  62. zarrsmith-0.6.0/tests/test_manager_refactor.py +512 -0
  63. zarrsmith-0.6.0/tests/test_mosaic_fields.py +106 -0
  64. zarrsmith-0.6.0/tests/test_mosaic_fusion.py +294 -0
  65. zarrsmith-0.6.0/tests/test_napari_compact_layout.py +121 -0
  66. zarrsmith-0.6.0/tests/test_napari_explorer_widget.py +423 -0
  67. zarrsmith-0.6.0/tests/test_napari_layout.py +259 -0
  68. zarrsmith-0.6.0/tests/test_napari_log.py +106 -0
  69. zarrsmith-0.6.0/tests/test_napari_mosaic_widget.py +535 -0
  70. zarrsmith-0.6.0/tests/test_next_version.py +43 -0
  71. zarrsmith-0.6.0/tests/test_opera_mosaic.py +331 -0
  72. zarrsmith-0.6.0/tests/test_parallel_write.py +147 -0
  73. zarrsmith-0.6.0/tests/test_shared_defaults.py +85 -0
  74. zarrsmith-0.6.0/tests/test_zarr_axis_aware.py +167 -0
  75. zarrsmith-0.6.0/tests/test_zarr_discovery.py +56 -0
  76. zarrsmith-0.6.0/tests/test_zarr_empty_creation.py +124 -0
  77. zarrsmith-0.6.0/tests/test_zarr_read_write.py +105 -0
  78. zarrsmith-0.6.0/tests/test_zarr_region_write.py +67 -0
  79. zarrsmith-0.6.0/tests/test_zarr_sharding.py +372 -0
  80. zarrsmith-0.6.0/zarrsmith/__init__.py +9 -0
  81. zarrsmith-0.6.0/zarrsmith/_version.py +24 -0
  82. zarrsmith-0.6.0/zarrsmith/cli/__arguments.py +729 -0
  83. zarrsmith-0.6.0/zarrsmith/cli/__init__.py +0 -0
  84. zarrsmith-0.6.0/zarrsmith/cli/zarrsmith.py +912 -0
  85. zarrsmith-0.6.0/zarrsmith/microscope_manager/__init__.py +11 -0
  86. zarrsmith-0.6.0/zarrsmith/microscope_manager/array_manager.py +133 -0
  87. zarrsmith-0.6.0/zarrsmith/microscope_manager/evident_manager.py +373 -0
  88. zarrsmith-0.6.0/zarrsmith/microscope_manager/luxendo_manager.py +197 -0
  89. zarrsmith-0.6.0/zarrsmith/microscope_manager/microscope_manager.py +262 -0
  90. zarrsmith-0.6.0/zarrsmith/microscope_manager/opera_manager.py +98 -0
  91. zarrsmith-0.6.0/zarrsmith/microscope_manager/readers.py +57 -0
  92. zarrsmith-0.6.0/zarrsmith/microscope_manager/scape_manager.py +201 -0
  93. zarrsmith-0.6.0/zarrsmith/microscope_manager/viventis_manager.py +104 -0
  94. zarrsmith-0.6.0/zarrsmith/microscope_manager/zarr_manager.py +995 -0
  95. zarrsmith-0.6.0/zarrsmith/microscope_manager/zarr_v04_manager.py +30 -0
  96. zarrsmith-0.6.0/zarrsmith/microscope_manager/zeiss_manager.py +135 -0
  97. zarrsmith-0.6.0/zarrsmith/mosaic_manager/__init__.py +10 -0
  98. zarrsmith-0.6.0/zarrsmith/mosaic_manager/fields.py +104 -0
  99. zarrsmith-0.6.0/zarrsmith/mosaic_manager/fusion.py +1018 -0
  100. zarrsmith-0.6.0/zarrsmith/mosaic_manager/h5_array.py +45 -0
  101. zarrsmith-0.6.0/zarrsmith/mosaic_manager/luxendo_mosaic_manager.py +160 -0
  102. zarrsmith-0.6.0/zarrsmith/mosaic_manager/mosaic.py +454 -0
  103. zarrsmith-0.6.0/zarrsmith/mosaic_manager/opera_mosaic_manager.py +530 -0
  104. zarrsmith-0.6.0/zarrsmith/mosaic_manager/readers.py +57 -0
  105. zarrsmith-0.6.0/zarrsmith/mosaic_manager/tiff_array.py +106 -0
  106. zarrsmith-0.6.0/zarrsmith/mosaic_manager/tile.py +80 -0
  107. zarrsmith-0.6.0/zarrsmith/mosaic_manager/zeiss_mosaic_manager.py +22 -0
  108. zarrsmith-0.6.0/zarrsmith/napari/__init__.py +0 -0
  109. zarrsmith-0.6.0/zarrsmith/napari/_batch_csv.py +28 -0
  110. zarrsmith-0.6.0/zarrsmith/napari/_convert_widget.py +1139 -0
  111. zarrsmith-0.6.0/zarrsmith/napari/_dataset_helpers.py +57 -0
  112. zarrsmith-0.6.0/zarrsmith/napari/_explorer_widget.py +1320 -0
  113. zarrsmith-0.6.0/zarrsmith/napari/_export_widget.py +173 -0
  114. zarrsmith-0.6.0/zarrsmith/napari/_layout.py +208 -0
  115. zarrsmith-0.6.0/zarrsmith/napari/_log.py +79 -0
  116. zarrsmith-0.6.0/zarrsmith/napari/_mosaic_widget.py +818 -0
  117. zarrsmith-0.6.0/zarrsmith/napari/napari.yaml +34 -0
  118. zarrsmith-0.6.0/zarrsmith/napari/resources/zarrsmith-icon.svg +96 -0
  119. zarrsmith-0.6.0/zarrsmith/utils/__init__.py +0 -0
  120. zarrsmith-0.6.0/zarrsmith/utils/axes.py +254 -0
  121. zarrsmith-0.6.0/zarrsmith/utils/chromatic_shift.py +836 -0
  122. zarrsmith-0.6.0/zarrsmith/utils/chunks.py +77 -0
  123. zarrsmith-0.6.0/zarrsmith/utils/colors.py +89 -0
  124. zarrsmith-0.6.0/zarrsmith/utils/create_empty_dataset.py +110 -0
  125. zarrsmith-0.6.0/zarrsmith/utils/create_empty_group.py +116 -0
  126. zarrsmith-0.6.0/zarrsmith/utils/dataset_ops.py +270 -0
  127. zarrsmith-0.6.0/zarrsmith/utils/downsampling.py +182 -0
  128. zarrsmith-0.6.0/zarrsmith/utils/metadata.py +89 -0
  129. zarrsmith-0.6.0/zarrsmith/utils/ngff.py +939 -0
  130. zarrsmith-0.6.0/zarrsmith/utils/ome.py +115 -0
  131. zarrsmith-0.6.0/zarrsmith/utils/pyramid.py +115 -0
  132. zarrsmith-0.6.0/zarrsmith/utils/subset.py +105 -0
  133. zarrsmith-0.6.0/zarrsmith/utils/to_zarr.py +253 -0
  134. zarrsmith-0.6.0/zarrsmith/utils/units.py +81 -0
  135. zarrsmith-0.6.0/zarrsmith/utils/visualize.py +185 -0
  136. zarrsmith-0.6.0/zarrsmith/utils/write_image_region.py +281 -0
  137. zarrsmith-0.6.0/zarrsmith/utils/write_label_region.py +60 -0
  138. zarrsmith-0.6.0/zarrsmith/utils/zoom.py +71 -0
  139. zarrsmith-0.6.0/zarrsmith.egg-info/PKG-INFO +177 -0
  140. zarrsmith-0.6.0/zarrsmith.egg-info/SOURCES.txt +143 -0
  141. zarrsmith-0.6.0/zarrsmith.egg-info/dependency_links.txt +1 -0
  142. zarrsmith-0.6.0/zarrsmith.egg-info/entry_points.txt +5 -0
  143. zarrsmith-0.6.0/zarrsmith.egg-info/requires.txt +55 -0
  144. zarrsmith-0.6.0/zarrsmith.egg-info/scm_file_list.json +139 -0
  145. zarrsmith-0.6.0/zarrsmith.egg-info/top_level.txt +1 -0
@@ -0,0 +1,69 @@
1
+ """Compute the next zarrsmith release version for a merged pull request.
2
+
3
+ Usage: python next_version.py <pr.json>
4
+
5
+ ``pr.json`` is the output of ``gh pr view <n> --json labels``. Existing tags are
6
+ read from the local git repository. Prints the next version (``X.Y.Z``,
7
+ without the leading ``v``), or nothing when the PR should not be released.
8
+
9
+ Releases are opt-in: a PR is released only if it carries one of the labels
10
+ ``release:major``, ``release:minor`` or ``release:patch``. Without such a label
11
+ nothing is tagged. If several are present the largest bump wins.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import re
18
+ import subprocess
19
+ import sys
20
+
21
+ # Tags with a major at or above this are legacy calendar versions and are ignored.
22
+ CALVER_MAJOR = 2000
23
+
24
+ TAG_RE = re.compile(r"^v(\d+)\.(\d+)\.(\d+)$")
25
+ KINDS = ("major", "minor", "patch") # ordered by priority
26
+
27
+
28
+ def latest_version(tags: list[str]) -> tuple[int, int, int] | None:
29
+ versions = []
30
+ for tag in tags:
31
+ m = TAG_RE.match(tag.strip())
32
+ if m:
33
+ v = tuple(int(x) for x in m.groups())
34
+ if v[0] < CALVER_MAJOR:
35
+ versions.append(v)
36
+ return max(versions) if versions else None
37
+
38
+
39
+ def bump_kind(pr: dict) -> str | None:
40
+ labels = {label["name"].lower() for label in pr.get("labels") or []}
41
+ for kind in KINDS:
42
+ if f"release:{kind}" in labels:
43
+ return kind
44
+ return None
45
+
46
+
47
+ def next_version(tags: list[str], pr: dict) -> str | None:
48
+ kind = bump_kind(pr)
49
+ if kind is None:
50
+ return None
51
+ major, minor, patch = latest_version(tags) or (0, 0, 0)
52
+ if kind == "major":
53
+ return f"{major + 1}.0.0"
54
+ if kind == "minor":
55
+ return f"{major}.{minor + 1}.0"
56
+ return f"{major}.{minor}.{patch + 1}"
57
+
58
+
59
+ def main() -> None:
60
+ with open(sys.argv[1], encoding="utf-8") as fh:
61
+ pr = json.load(fh)
62
+ tags = subprocess.run(
63
+ ["git", "tag", "--list", "v*"], capture_output=True, text=True, check=True
64
+ ).stdout.splitlines()
65
+ print(next_version(tags, pr) or "")
66
+
67
+
68
+ if __name__ == "__main__":
69
+ main()
@@ -0,0 +1,75 @@
1
+ name: Build and Publish Docker Image
2
+
3
+ on:
4
+ # Normal path: called by release.yml after a merged PR creates a new version tag.
5
+ workflow_call:
6
+ inputs:
7
+ version:
8
+ description: "Release version without the leading v (e.g. 0.10.1)"
9
+ required: true
10
+ type: string
11
+ # Tags pushed by hand (not by release.yml's GITHUB_TOKEN) still build an image.
12
+ push:
13
+ tags:
14
+ - 'v*'
15
+ workflow_dispatch: # Allows manual triggering
16
+
17
+ env:
18
+ REGISTRY: ghcr.io
19
+ # Explicit, not github.repository: the images up to 0.5.5 stay at ghcr.io/embl-mif/pymif.
20
+ IMAGE_NAME: ${{ github.repository_owner }}/zarrsmith
21
+
22
+ jobs:
23
+ build-and-push-image:
24
+ runs-on: ubuntu-latest
25
+
26
+ # Grants permissions to the GITHUB_TOKEN to upload packages to GHCR
27
+ permissions:
28
+ contents: read
29
+ packages: write
30
+
31
+ steps:
32
+ - name: Resolve version
33
+ id: ver
34
+ env:
35
+ INPUT_VERSION: ${{ inputs.version }}
36
+ run: |
37
+ version="$INPUT_VERSION"
38
+ if [ -z "$version" ] && [ "$GITHUB_REF_TYPE" = "tag" ]; then
39
+ version="${GITHUB_REF_NAME#v}"
40
+ fi
41
+ echo "version=$version" >> "$GITHUB_OUTPUT"
42
+
43
+ - name: Checkout repository
44
+ uses: actions/checkout@v5
45
+ with:
46
+ ref: ${{ steps.ver.outputs.version && format('v{0}', steps.ver.outputs.version) || '' }}
47
+
48
+ - name: Log in to the Container registry
49
+ uses: docker/login-action@v3
50
+ with:
51
+ registry: ${{ env.REGISTRY }}
52
+ username: ${{ github.actor }}
53
+ password: ${{ secrets.GITHUB_TOKEN }}
54
+
55
+ - name: Extract metadata (tags, labels) for Docker
56
+ id: meta
57
+ uses: docker/metadata-action@v5
58
+ with:
59
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
60
+ tags: |
61
+ # Release version, e.g. 0.10.1, plus 'latest'
62
+ type=raw,value=${{ steps.ver.outputs.version }},enable=${{ steps.ver.outputs.version != '' }}
63
+ type=raw,value=latest,enable=${{ steps.ver.outputs.version != '' }}
64
+ # Manual runs on a branch are tagged with the branch name
65
+ type=ref,event=branch,enable=${{ steps.ver.outputs.version == '' }}
66
+
67
+ - name: Build and push Docker image
68
+ uses: docker/build-push-action@v5
69
+ with:
70
+ context: .
71
+ push: true
72
+ tags: ${{ steps.meta.outputs.tags }}
73
+ labels: ${{ steps.meta.outputs.labels }}
74
+ build-args: |
75
+ ZARRSMITH_VERSION=${{ steps.ver.outputs.version }}
@@ -0,0 +1,38 @@
1
+ name: documentation
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: write
11
+
12
+ jobs:
13
+ docs:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Checkout repository
17
+ uses: actions/checkout@v5
18
+ with:
19
+ fetch-depth: 0 # tags are needed to derive the version shown in the docs
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v6
22
+ with:
23
+ python-version: '3.12'
24
+ - name: Install package and docs dependencies
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install -e ".[docs]"
28
+ - name: Sphinx build
29
+ run: |
30
+ sphinx-build documentation _build
31
+ - name: Deploy to GitHub Pages
32
+ uses: peaceiris/actions-gh-pages@v3
33
+ if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
34
+ with:
35
+ publish_branch: gh-pages
36
+ github_token: ${{ secrets.GITHUB_TOKEN }}
37
+ publish_dir: _build
38
+ force_orphan: true
@@ -0,0 +1,116 @@
1
+ name: release
2
+
3
+ # Releases are opt-in: only a merged PR into main labelled release:major, release:minor or
4
+ # release:patch creates a vX.Y.Z tag, a GitHub Release, a PyPI release and a Docker image. All other merged
5
+ # PRs skip this workflow (the job-level `if` means no runner is started).
6
+ # The version is computed by .github/scripts/next_version.py.
7
+ # pull_request_target is used so merges of PRs from forks also get a write token; the
8
+ # job only checks out the merge commit, i.e. code that is already on main.
9
+ on:
10
+ pull_request_target:
11
+ types: [closed]
12
+ branches: [main]
13
+
14
+ jobs:
15
+ tag:
16
+ if: >-
17
+ github.event.pull_request.merged == true && (
18
+ contains(github.event.pull_request.labels.*.name, 'release:major') ||
19
+ contains(github.event.pull_request.labels.*.name, 'release:minor') ||
20
+ contains(github.event.pull_request.labels.*.name, 'release:patch'))
21
+ runs-on: ubuntu-latest
22
+ permissions:
23
+ contents: write
24
+ pull-requests: read
25
+ # Serialize releases so two quick merges never compute the same version.
26
+ concurrency:
27
+ group: release
28
+ cancel-in-progress: false
29
+ outputs:
30
+ version: ${{ steps.version.outputs.version }}
31
+
32
+ steps:
33
+ - name: Check out merge commit
34
+ uses: actions/checkout@v5
35
+ with:
36
+ ref: ${{ github.event.pull_request.merge_commit_sha }}
37
+ fetch-depth: 0
38
+
39
+ - name: Set up Python
40
+ uses: actions/setup-python@v6
41
+ with:
42
+ python-version: '3.12'
43
+
44
+ - name: Compute next version
45
+ id: version
46
+ env:
47
+ GH_TOKEN: ${{ github.token }}
48
+ PR_NUMBER: ${{ github.event.pull_request.number }}
49
+ run: |
50
+ gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" \
51
+ --json labels > "$RUNNER_TEMP/pr.json"
52
+ version=$(python .github/scripts/next_version.py "$RUNNER_TEMP/pr.json")
53
+ echo "version=$version" >> "$GITHUB_OUTPUT"
54
+ if [ -z "$version" ]; then
55
+ echo "No release for this PR."
56
+ else
57
+ echo "Next version: $version"
58
+ fi
59
+
60
+ - name: Create tag and GitHub Release
61
+ if: steps.version.outputs.version != ''
62
+ env:
63
+ GH_TOKEN: ${{ github.token }}
64
+ VERSION: ${{ steps.version.outputs.version }}
65
+ SHA: ${{ github.event.pull_request.merge_commit_sha }}
66
+ run: |
67
+ git config user.name "github-actions[bot]"
68
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
69
+ git tag -a "v$VERSION" -m "zarrsmith $VERSION" "$SHA"
70
+ git push origin "v$VERSION"
71
+ gh release create "v$VERSION" --repo "$GITHUB_REPOSITORY" \
72
+ --title "v$VERSION" --generate-notes --verify-tag
73
+
74
+ # Trusted publishing: PyPI accepts this repository's release.yml in the `pypi` environment,
75
+ # so no token is stored. It must run in this top-level workflow (PyPI rejects reusable ones).
76
+ pypi:
77
+ needs: tag
78
+ if: needs.tag.outputs.version != ''
79
+ runs-on: ubuntu-latest
80
+ environment:
81
+ name: pypi
82
+ url: https://pypi.org/p/zarrsmith
83
+ permissions:
84
+ id-token: write
85
+
86
+ steps:
87
+ - name: Check out release tag
88
+ uses: actions/checkout@v5
89
+ with:
90
+ ref: v${{ needs.tag.outputs.version }}
91
+
92
+ - name: Set up Python
93
+ uses: actions/setup-python@v6
94
+ with:
95
+ python-version: '3.12'
96
+
97
+ - name: Build sdist and wheel
98
+ env:
99
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ needs.tag.outputs.version }}
100
+ run: |
101
+ python -m pip install --upgrade build
102
+ python -m build
103
+
104
+ - name: Publish to PyPI
105
+ uses: pypa/gh-action-pypi-publish@release/v1
106
+
107
+ # Tags pushed with GITHUB_TOKEN do not trigger other workflows, so call the image build directly.
108
+ docker:
109
+ needs: tag
110
+ if: needs.tag.outputs.version != ''
111
+ uses: ./.github/workflows/docker-publish.yml
112
+ with:
113
+ version: ${{ needs.tag.outputs.version }}
114
+ permissions:
115
+ contents: read
116
+ packages: write
@@ -0,0 +1,34 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ pytest:
10
+ runs-on: ubuntu-latest
11
+
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.12"]
16
+
17
+ steps:
18
+ - name: Check out repository
19
+ uses: actions/checkout@v5
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v6
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+ cache: pip
26
+
27
+ - name: Install package
28
+ run: |
29
+ python -m pip install --upgrade pip
30
+ pip install -e ".[dev]"
31
+
32
+ - name: Run tests
33
+ run: |
34
+ pytest -q
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ _build/
3
+ *.py[cod]
4
+ *.zarr
5
+ *.egg-info/
6
+ .env
7
+ .ipynb_checkpoints
8
+ .vscode*
9
+ pymif_old/
10
+ documentation/demonstration_open_zarr.avi
11
+ documentation/demonstration_open_zarr.mp4
12
+ documentation/demonstration_open_zarr.gif
13
+ documentation/Thumbs.db
14
+ *build/
15
+ zarrsmith/_version.py
@@ -0,0 +1,39 @@
1
+ # Base image
2
+ FROM python:3.12-slim
3
+
4
+ # Avoid interactive prompts
5
+ ENV DEBIAN_FRONTEND=noninteractive
6
+
7
+ # Install system dependencies (same as your original)
8
+ RUN apt-get update && apt-get install -y \
9
+ libfontconfig1 \
10
+ libgl1 \
11
+ libglx0 \
12
+ libglib2.0-0 \
13
+ procps \
14
+ && rm -rf /var/lib/apt/lists/*
15
+
16
+ # Set workdir
17
+ WORKDIR /app
18
+
19
+ # Copy project files
20
+ COPY . /app
21
+
22
+ # Optional: choose extras at build time (default = base)
23
+ ARG ZARRSMITH_EXTRAS=""
24
+ # Package version (set by CI); the image has no git, so setuptools-scm cannot read tags
25
+ ARG ZARRSMITH_VERSION=""
26
+
27
+ # Upgrade pip and install package
28
+ RUN pip install --upgrade pip && \
29
+ if [ -n "$ZARRSMITH_VERSION" ]; then \
30
+ export SETUPTOOLS_SCM_PRETEND_VERSION="$ZARRSMITH_VERSION"; \
31
+ fi && \
32
+ if [ -z "$ZARRSMITH_EXTRAS" ]; then \
33
+ pip install .; \
34
+ else \
35
+ pip install ".[${ZARRSMITH_EXTRAS}]"; \
36
+ fi
37
+
38
+ # Default shell
39
+ CMD ["/bin/bash"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 European Molecular Biology Laboratory (EMBL)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ recursive-include zarrsmith/napari *.yaml
2
+ recursive-include zarrsmith/napari/resources *.svg
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.4
2
+ Name: zarrsmith
3
+ Version: 0.6.0
4
+ Summary: Microscopy I/O, OME-Zarr forging and NGFF utilities: read vendor datasets, write multiscale OME-Zarr, fuse mosaics, from Python, the command line and napari.
5
+ Author-email: Nicola Gritti <nicola.gritti@embl.es>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/embl-mif/zarrsmith
8
+ Project-URL: Documentation, https://embl-mif.github.io/zarrsmith/
9
+ Project-URL: Issues, https://github.com/embl-mif/zarrsmith/issues
10
+ Project-URL: Changelog, https://github.com/embl-mif/zarrsmith/releases
11
+ Keywords: microscopy,zarr,ome-zarr,ngff,napari
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Operating System :: OS Independent
15
+ Requires-Python: >=3.12
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: async-lru>=2.3.0
19
+ Requires-Dist: bioio>=3.3.0
20
+ Requires-Dist: bioio-czi>=2.6.0
21
+ Requires-Dist: dask>=2026.3.0
22
+ Requires-Dist: dask-image>=2025.11.0
23
+ Requires-Dist: h5py>=3.16.0
24
+ Requires-Dist: imagecodecs>=2026.10.10
25
+ Requires-Dist: matplotlib>=3.10.8
26
+ Requires-Dist: natsort
27
+ Requires-Dist: numba>=0.64.0
28
+ Requires-Dist: numcodecs>=0.16.5
29
+ Requires-Dist: numpy>=2.4.3
30
+ Requires-Dist: ome-zarr>=0.16.0
31
+ Requires-Dist: pandas>=3.0.1
32
+ Requires-Dist: readlif>=0.6.6
33
+ Requires-Dist: scikit-image>=0.26.0
34
+ Requires-Dist: scikit-learn>=1.8.0
35
+ Requires-Dist: scipy>=1.17.1
36
+ Requires-Dist: slideio>=2.10.0
37
+ Requires-Dist: tifffile>=2026.3.3
38
+ Requires-Dist: tqdm>=4.67.3
39
+ Requires-Dist: typer>=0.24.1
40
+ Requires-Dist: xlsxwriter>=3.2.9
41
+ Requires-Dist: xyzservices>=2025.11.0
42
+ Requires-Dist: zarr>=3.1.6
43
+ Requires-Dist: zict>=3.0.0
44
+ Provides-Extra: napari
45
+ Requires-Dist: magicgui>=0.10.1; extra == "napari"
46
+ Requires-Dist: napari; extra == "napari"
47
+ Requires-Dist: napari-animation; extra == "napari"
48
+ Requires-Dist: napari-clusters-plotter>=0.11; extra == "napari"
49
+ Requires-Dist: napari-metadata; extra == "napari"
50
+ Requires-Dist: napari-ome-zarr>=0.8.2; extra == "napari"
51
+ Requires-Dist: pyconify>=0.2.1; extra == "napari"
52
+ Requires-Dist: PyQt6; extra == "napari"
53
+ Requires-Dist: QtPy>=2.4.3; extra == "napari"
54
+ Provides-Extra: notebooks
55
+ Requires-Dist: notebook>=7.5.5; extra == "notebooks"
56
+ Provides-Extra: dev
57
+ Requires-Dist: pytest>=9.0.2; extra == "dev"
58
+ Requires-Dist: build>=1.4.1; extra == "dev"
59
+ Requires-Dist: wheel>=0.46.3; extra == "dev"
60
+ Provides-Extra: docs
61
+ Requires-Dist: Sphinx>=9.1.0; extra == "docs"
62
+ Requires-Dist: sphinx-autoapi>=3.8.0; extra == "docs"
63
+ Requires-Dist: sphinx-autodoc-typehints>=3.9.11; extra == "docs"
64
+ Requires-Dist: sphinx_rtd_theme>=3.1.0; extra == "docs"
65
+ Requires-Dist: myst-parser>=5.0.0; extra == "docs"
66
+ Provides-Extra: all
67
+ Requires-Dist: zarrsmith[dev,docs,napari,notebooks]; extra == "all"
68
+ Dynamic: license-file
69
+
70
+ <h1>
71
+ <img src="https://raw.githubusercontent.com/embl-mif/zarrsmith/main/zarrsmith/napari/resources/zarrsmith-icon.svg" alt="ZarrSmith logo" width="120" align="left">
72
+ ZarrSmith — microscopy I/O, OME-Zarr forging, and NGFF utilities
73
+ <br clear="left">
74
+ </h1>
75
+ <!-- The logo has an absolute URL so that it also shows on PyPI.
76
+ documentation/index.md repeats this header in Markdown (Sphinx needs a Markdown title and does not
77
+ rewrite HTML paths) and includes this README from here. -->
78
+
79
+ ![Python](https://img.shields.io/badge/python-3.12-green)
80
+ [![License](https://img.shields.io/github/license/embl-mif/zarrsmith.svg)](https://github.com/embl-mif/zarrsmith/blob/main/LICENSE)
81
+ [![Tests](https://github.com/embl-mif/zarrsmith/actions/workflows/tests.yml/badge.svg)](https://github.com/embl-mif/zarrsmith/actions/workflows/tests.yml)
82
+ [![codecov](https://codecov.io/gh/embl-mif/zarrsmith/graph/badge.svg)](https://codecov.io/gh/embl-mif/zarrsmith)
83
+ [![Documentation](https://github.com/embl-mif/zarrsmith/actions/workflows/documentation.yml/badge.svg)](https://github.com/embl-mif/zarrsmith/actions/workflows/documentation.yml)
84
+ [![Docker](https://github.com/embl-mif/zarrsmith/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/embl-mif/zarrsmith/actions/workflows/docker-publish.yml)
85
+ [![GitHub release](https://img.shields.io/github/v/release/embl-mif/zarrsmith.svg)](https://github.com/embl-mif/zarrsmith/releases)
86
+ [![GitHub stars](https://img.shields.io/github/stars/embl-mif/zarrsmith.svg?style=social)](https://github.com/embl-mif/zarrsmith/stargazers)
87
+
88
+ **ZarrSmith** is a Python package for reading microscopy datasets from multiple acquisition systems, building multiscale pyramids, writing **OME-NGFF / OME-Zarr**, and working with those datasets from Python, the command line and napari.
89
+
90
+ The rendered documentation is at **[embl-mif.github.io/zarrsmith](https://embl-mif.github.io/zarrsmith/)**.
91
+
92
+ > [!NOTE]
93
+ > ZarrSmith was called **PyMIF** up to version 0.5.5. From 0.6.0, import `zarrsmith` and run the `zarrsmith` command instead of `pymif`. The Docker images of PyMIF stay available at `ghcr.io/embl-mif/pymif:<version>`; newer images are at `ghcr.io/embl-mif/zarrsmith`.
94
+
95
+ ---
96
+
97
+ ## What ZarrSmith does
98
+
99
+ - **Microscope managers** read Luxendo, Opera, SCAPE, Viventis, Zeiss, Evident (Olympus VSI) and OME-Zarr datasets into one lazy (Dask) API with a shared metadata schema. → [Readers and conventions](documentation/readers.md)
100
+ - **OME-Zarr writing**: full export, empty datasets and groups, image and label region updates, any subset of the `tczyx` axes. → [Python API](documentation/python-api.md)
101
+ - **Pyramids and subsetting**: multiscale generation, cropping, channel reordering, metadata updates. → [Python API](documentation/python-api.md)
102
+ - **Mosaics**: raw tiles shown at their stage position and fused into one OME-Zarr image (3D or projection). → [Mosaics](documentation/mosaic.md)
103
+ - **Chromatic shift correction**: the Z offset between channels measured on the sample itself, and a corrected copy with the same layout as the input. → [Chromatic shift correction](documentation/chromatic-shift.md)
104
+ - **Command line**: one-off and CSV-batch conversion, mosaic fusion and chromatic shift correction. → [Command line](documentation/cli.md)
105
+ - **Napari widgets**: conversion with ROI selection, mosaic fusion, exploration of segmented objects (features plot linked with the viewer). → [Napari plugin](documentation/napari-plugin.md)
106
+ - **Output tuning**: sharding, singleton axes, parallel writing, progress bars. → [Advanced writing options](documentation/advanced.md)
107
+
108
+ ## Installation
109
+
110
+ ```console
111
+ conda create -n zarrsmith python=3.12
112
+ conda activate zarrsmith
113
+ git clone https://github.com/embl-mif/zarrsmith.git
114
+ cd zarrsmith
115
+ pip install . # or: pip install -e .[napari] for development with the napari widgets
116
+ ```
117
+
118
+ Versioning, releases and development installs: [Installation and versioning](documentation/installation.md).
119
+
120
+ ## Quick start
121
+
122
+ ```python
123
+ import zarrsmith.microscope_manager as mm
124
+
125
+ source = mm.ViventisManager("path/to/Position_1") # any microscope manager
126
+ source.build_pyramid(num_levels=3)
127
+ source.to_zarr("output.zarr") # NGFF v0.5 / Zarr v3
128
+
129
+ z = mm.ZarrManager("output.zarr")
130
+ z.visualize() # open in napari
131
+ ```
132
+
133
+ ```console
134
+ zarrsmith convert -i INPUT_PATH -m MICROSCOPE -z OUTPUT_ZARR
135
+ zarrsmith fuse -i ACQUISITION_FOLDER -z OUTPUT_ZARR -rds 4 8 8 # fuse raw tiles
136
+ zarrsmith chromatic-shift -i INPUT_ZARR -z OUTPUT_ZARR -r shift.json # align channels in Z
137
+ ```
138
+
139
+ ## Documentation
140
+
141
+ **Getting started**
142
+
143
+ | Page | Contents |
144
+ |---|---|
145
+ | [Installation and versioning](documentation/installation.md) | environments, extras, release labels |
146
+ | [Readers and conventions](documentation/readers.md) | supported microscopes, shared reader behaviour, logging |
147
+
148
+ **Working with data**
149
+
150
+ | Page | Contents |
151
+ |---|---|
152
+ | [Python API](documentation/python-api.md) | export, empty datasets, axis-aware metadata, labels, region writes |
153
+ | [Mosaics](documentation/mosaic.md) | raw tiles, placement check, fusion options |
154
+ | [Chromatic shift correction](documentation/chromatic-shift.md) | measuring the Z offset between channels, the corrected dataset, checking the result, `zarrsmith chromatic-shift` |
155
+ | [Advanced writing options](documentation/advanced.md) | sharding, singleton axes, parallel writing, progress bar |
156
+
157
+ **Interfaces**
158
+
159
+ | Page | Contents |
160
+ |---|---|
161
+ | [Command line](documentation/cli.md) | `zarrsmith convert`, `zarrsmith fuse`, `zarrsmith chromatic-shift` (one dataset or a CSV batch) |
162
+ | [Napari plugin](documentation/napari-plugin.md) | converter, mosaic fusion and objects explorer widgets |
163
+
164
+ **Reference**
165
+
166
+ | Page | Contents |
167
+ |---|---|
168
+ | [API reference](https://embl-mif.github.io/zarrsmith/autoapi/zarrsmith/index.html) | generated from the docstrings |
169
+ | [Contributing](documentation/contributing.md) | package layout, adding a microscope manager or a mosaic manager, `zarrsmith.utils`, documentation |
170
+
171
+ ## Help
172
+
173
+ For questions or bug reports, open an
174
+ [issue](https://github.com/embl-mif/zarrsmith/issues) on GitHub, or contact the current maintainers.
175
+
176
+ > [!IMPORTANT]
177
+ > If ZarrSmith contributes to your work, please acknowledge ZarrSmith and the EMBL Mesoscopic Imaging Facility in your publications.