From cd276e2af884b2d7e7555d4bf299a513359757ef Mon Sep 17 00:00:00 2001
From: Davis Bennett <davis.v.bennett@gmail.com>
Date: Thu, 29 Aug 2024 16:00:24 +0200
Subject: [PATCH] Drop py39 (#38)

* drop python 3.9

* drop 3.9 from workflows
---
 .github/workflows/ci.yaml                 | 2 +-
 docs/index.md                             | 8 ++++----
 pyproject.toml                            | 5 ++++-
 src/pydantic_ome_ngff/latest/transform.py | 8 +++-----
 src/pydantic_ome_ngff/v04/multiscale.py   | 6 +++---
 src/pydantic_ome_ngff/v04/plate.py        | 4 +---
 src/pydantic_ome_ngff/v04/transform.py    | 8 ++++----
 src/pydantic_ome_ngff/v04/well.py         | 3 +--
 8 files changed, 21 insertions(+), 23 deletions(-)

diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index b5f22ac..7bd786b 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -9,7 +9,7 @@ jobs:
       runs-on: ubuntu-latest
       strategy:
         matrix:
-          python-version: ['3.9', '3.10', '3.11']
+          python-version: ['3.10', '3.11', '3.12']
       steps:
       - uses: actions/checkout@v4
       - name: Set up Python
diff --git a/docs/index.md b/docs/index.md
index bb396b0..8145494 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -466,8 +466,8 @@ except ValidationError as e:
     print(e)
     """
     1 validation error for Group
-      Value error, Dataset s0 was specified in multiscale metadata, but no array with that name was found in the hierarchy. All arrays referenced in multiscale metadata must be contained in the group. [type=value_error, input_value={'zarr_version': 2, 'attr...: 'zstd', 'level': 3}}}}, input_type=dict]
-        For further information visit https://errors.pydantic.dev/2.7/v/value_error
+      Value error, Dataset s0 was specified in multiscale metadata, but no array with that name was found in the hierarchy. All arrays referenced in multiscale metadata must be contained in the group. [type=value_error, input_value={'zarr_version': 2, 'attr...3, 'checksum': False}}}}, input_type=dict]
+        For further information visit https://errors.pydantic.dev/2.8/v/value_error
     """
 
 group_model_wrong_array = group_model.model_dump()
@@ -481,7 +481,7 @@ except ValidationError as e:
     print(e)
     """
     1 validation error for Group
-      Value error, Transform type='scale' scale=(1, 1) has dimensionality 2, which does not match the dimensionality of the array found in this group at s0 (1). Transform dimensionality must match array dimensionality. [type=value_error, input_value={'zarr_version': 2, 'attr...: 'zstd', 'level': 3}}}}, input_type=dict]
-        For further information visit https://errors.pydantic.dev/2.7/v/value_error
+      Value error, Transform type='scale' scale=(1, 1) has dimensionality 2, which does not match the dimensionality of the array found in this group at s0 (1). Transform dimensionality must match array dimensionality. [type=value_error, input_value={'zarr_version': 2, 'attr...3, 'checksum': False}}}}, input_type=dict]
+        For further information visit https://errors.pydantic.dev/2.8/v/value_error
     """
 ```
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index d94d7bb..ed1f4b2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -35,6 +35,9 @@ Source = "https://github.com/janeliascicomp/pydantic-ome-ngff"
 version.source = "vcs"
 build.hooks.vcs.version-file = "src/pydantic_ome_ngff/_version.py"
 
+[tool.hatch.envs.default]
+installer = "uv"
+
 [tool.hatch.envs.test]
 dependencies = [
   "pytest==8.0.0",
@@ -51,7 +54,7 @@ run = "run-coverage --no-cov"
 run-verbose = "run-coverage --verbose"
 
 [[tool.hatch.envs.test.matrix]]
-python = ["3.9", "3.10", "3.11"]
+python = ["3.10", "3.11", "3.12"]
 
 [tool.hatch.envs.types]
 extra-dependencies = [
diff --git a/src/pydantic_ome_ngff/latest/transform.py b/src/pydantic_ome_ngff/latest/transform.py
index ca1972a..c1eab44 100644
--- a/src/pydantic_ome_ngff/latest/transform.py
+++ b/src/pydantic_ome_ngff/latest/transform.py
@@ -1,7 +1,5 @@
 from __future__ import annotations
 
-from typing import Union
-
 import pydantic_ome_ngff.v04.transform as tx
 
 
@@ -40,9 +38,9 @@ class VectorScale(tx.VectorScale):
     """
 
 
-Scale = Union[VectorScale, PathScale]
-Translation = Union[VectorTranslation, PathTranslation]
-Transform = Union[Scale, Translation, Identity]
+Scale = VectorScale | PathScale
+Translation = VectorTranslation | PathTranslation
+Transform = Scale | Translation | Identity
 
 scale_translation = tx.scale_translation
 ensure_dimensionality = tx.ensure_dimensionality
diff --git a/src/pydantic_ome_ngff/v04/multiscale.py b/src/pydantic_ome_ngff/v04/multiscale.py
index dc0ad82..548fe43 100644
--- a/src/pydantic_ome_ngff/v04/multiscale.py
+++ b/src/pydantic_ome_ngff/v04/multiscale.py
@@ -10,7 +10,7 @@
     from numcodecs.abc import Codec
     from typing_extensions import Self
 
-from typing import Annotated, Any, Sequence, Union, cast
+from typing import Annotated, Any, Sequence, cast
 
 import zarr
 from numcodecs import Zstd
@@ -264,7 +264,7 @@ class GroupAttrs(BaseModel):
     multiscales: Annotated[tuple[MultiscaleMetadata, ...], Field(..., min_length=1)]
 
 
-class Group(GroupSpec[GroupAttrs, Union[ArraySpec, GroupSpec]]):
+class Group(GroupSpec[GroupAttrs, ArraySpec | GroupSpec]):
     """
     A model of a Zarr group that implements OME-NGFF Multiscales metadata.
 
@@ -479,7 +479,7 @@ def check_array_ndim(self) -> Group:
                 for tform in tforms:
                     if hasattr(tform, "scale") or hasattr(tform, "translation"):
                         tform = cast(
-                            Union[tx.VectorScale, tx.VectorTranslation],
+                            tx.VectorScale | tx.VectorTranslation,
                             tform,
                         )
                         if (tform_ndim := tx.ndim(tform)) != arr_ndim:
diff --git a/src/pydantic_ome_ngff/v04/plate.py b/src/pydantic_ome_ngff/v04/plate.py
index 7a1000f..6aada3c 100644
--- a/src/pydantic_ome_ngff/v04/plate.py
+++ b/src/pydantic_ome_ngff/v04/plate.py
@@ -1,7 +1,5 @@
 from __future__ import annotations
 
-from typing import Union
-
 from pydantic import (
     BaseModel,
     NonNegativeInt,
@@ -54,7 +52,7 @@ class GroupAttrs(BaseModel):
     plate: PlateMetadata
 
 
-class Group(GroupSpec[GroupAttrs, Union[well.Group, GroupSpec, ArraySpec]]):
+class Group(GroupSpec[GroupAttrs, well.Group | GroupSpec | ArraySpec]):
     @field_validator("members", mode="after")
     @classmethod
     def contains_well_group(
diff --git a/src/pydantic_ome_ngff/v04/transform.py b/src/pydantic_ome_ngff/v04/transform.py
index b457f5b..6f151e9 100644
--- a/src/pydantic_ome_ngff/v04/transform.py
+++ b/src/pydantic_ome_ngff/v04/transform.py
@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-from typing import Annotated, Literal, Sequence, Union
+from typing import Annotated, Literal, Sequence
 
 from pydantic_ome_ngff.base import StrictBase
 
@@ -166,9 +166,9 @@ def scale_translation(
     return (vec_scale, vec_trans)
 
 
-Scale = Union[VectorScale, PathScale]
-Translation = Union[VectorTranslation, PathTranslation]
-Transform = Union[Scale, Translation]
+Scale = VectorScale | PathScale
+Translation = VectorTranslation | PathTranslation
+Transform = Scale | Translation
 
 
 def ensure_dimensionality(
diff --git a/src/pydantic_ome_ngff/v04/well.py b/src/pydantic_ome_ngff/v04/well.py
index 168e5f7..4cffa4f 100644
--- a/src/pydantic_ome_ngff/v04/well.py
+++ b/src/pydantic_ome_ngff/v04/well.py
@@ -1,6 +1,5 @@
 from __future__ import annotations
 
-from typing import Union
 from pydantic import BaseModel, ValidationError, field_validator
 from pydantic_zarr.v2 import ArraySpec, GroupSpec
 
@@ -29,7 +28,7 @@ class GroupAttrs(BaseModel):
     well: WellMetadata
 
 
-class Group(GroupSpec[GroupAttrs, Union[multiscale.Group, GroupSpec, ArraySpec]]):
+class Group(GroupSpec[GroupAttrs, multiscale.Group | GroupSpec | ArraySpec]):
     @field_validator("members", mode="after")
     @classmethod
     def contains_multiscale_group(