Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/168.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Corrected docstring examples in `v2.py` and `v3.py` (and experimental equivalents): fixed copy-pasted v2 output in a v3 example, missing commas, wrong import aliases, a `zarr_format=2` in a v3 example, "codices" → "codecs", "Compare am" → "Compare an", and a truncated sentence in the `to_zarr` docstring. Also fixed `V2ChunkKeyEncoding` to reference the correct config TypedDict, and modernized lint: `for` loops instead of list-comprehension side effects, `dict(data)` instead of `dict(data).copy()`, single-item `in` tests to equality, and raw strings in `pytest.raises(match=…)` calls.
3 changes: 2 additions & 1 deletion src/pydantic_zarr/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ def ensure_member_name(data: Any) -> str:

def ensure_key_no_path(data: Any) -> Any:
if isinstance(data, Mapping):
[ensure_member_name(key) for key in data]
for key in data:
ensure_member_name(key)
return data


Expand Down
3 changes: 2 additions & 1 deletion src/pydantic_zarr/experimental/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def ensure_member_name(data: Any) -> str:

def ensure_key_no_path(data: Any) -> Any:
if isinstance(data, Mapping):
[ensure_member_name(key) for key in data]
for key in data:
ensure_member_name(key)
return data


Expand Down
4 changes: 2 additions & 2 deletions src/pydantic_zarr/experimental/v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def like(
exclude: IncEx = None,
) -> bool:
"""
Compare am `ArraySpec` to another `ArraySpec` or a `zarr.Array`, parameterized over the
Compare an `ArraySpec` to another `ArraySpec` or a `zarr.Array`, parameterized over the
fields to exclude or include in the comparison. Models are first converted to `dict` via the
`model_dump` method of `pydantic.BaseModel`, then compared with the `==` operator.

Expand Down Expand Up @@ -1152,7 +1152,7 @@ def from_flat_group(data: Mapping[str, ArraySpec | BaseGroupSpec]) -> GroupSpec:
# populates member_groups
submember_by_parent_name: dict[str, dict[str, ArraySpec | BaseGroupSpec]] = {}
# copy the input to ensure that mutations are contained inside this function
data_copy = dict(data).copy()
data_copy = dict(data)
# Get the root node
try:
# The root node is a GroupSpec with the key ""
Expand Down
10 changes: 5 additions & 5 deletions src/pydantic_zarr/experimental/v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ class ArraySpec(NodeSpec):
fill_value: FillValue
The fill value for this array.
codecs: Sequence[NamedConfig]
The sequence of codices for this array.
The sequence of codecs for this array.
storage_transformers: Optional[Sequence[NamedConfig]]
An optional sequence of `NamedConfig` objects that define the storage
transformers for this array.
Expand Down Expand Up @@ -457,7 +457,7 @@ def like(
exclude: IncEx = None,
) -> bool:
"""
Compare am `ArraySpec` to another `ArraySpec` or a `zarr.Array`, parameterized over the
Compare an `ArraySpec` to another `ArraySpec` or a `zarr.Array`, parameterized over the
fields to exclude or include in the comparison. Models are first converted to `dict` via the
`model_dump` method of `pydantic.BaseModel`, then compared with the `==` operator.

Expand Down Expand Up @@ -1186,7 +1186,7 @@ def from_flat_group(
# populates member_groups
submember_by_parent_name: dict[str, dict[str, ArraySpec | BaseGroupSpec]] = {}
# copy the input to ensure that mutations are contained inside this function
data_copy = dict(data).copy()
data_copy = dict(data)
# Get the root node
try:
# The root node is a GroupSpec with the key ""
Expand Down Expand Up @@ -1262,9 +1262,9 @@ def auto_fill_value(data: object) -> FillValue:
return False
elif kind in ["i", "u"]:
return 0
elif kind in ["f"]:
elif kind == "f":
return "NaN"
elif kind in ["c"]:
elif kind == "c":
return ("NaN", "NaN")
else:
raise ValueError(f"Cannot determine default fill value for data type {kind}")
Expand Down
22 changes: 11 additions & 11 deletions src/pydantic_zarr/v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ def like(
exclude: IncEx = None,
) -> bool:
"""
Compare am `ArraySpec` to another `ArraySpec` or a `zarr.Array`, parameterized over the
Compare an `ArraySpec` to another `ArraySpec` or a `zarr.Array`, parameterized over the
fields to exclude or include in the comparison. Models are first converted to `dict` via the
`model_dump` method of `pydantic.BaseModel`, then compared with the `==` operator.

Expand Down Expand Up @@ -713,14 +713,14 @@ def to_flat(self, root_path: str = "") -> dict[str, AnyArraySpec | AnyGroupSpec]
Examples
--------

>>> from pydantic_zarr.v2 import to_flat, GroupSpec
>>> from pydantic_zarr.v2 import GroupSpec
>>> g1 = GroupSpec(members=None, attributes={'foo': 'bar'})
>>> to_flat(g1)
>>> g1.to_flat()
{'': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
>>> to_flat(g1 root_path='baz')
>>> g1.to_flat(root_path='baz')
{'baz': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
>>> to_flat(GroupSpec(members={'g1': g1}, attributes={'foo': 'bar'}))
{'/g1': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None), '': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
>>> GroupSpec(members={'g1': g1}, attributes={'foo': 'bar'}).to_flat()
{'': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None), '/g1': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
"""
return to_flat(self, root_path=root_path)

Expand Down Expand Up @@ -838,7 +838,7 @@ def to_zarr(
overwrite : bool, default = False
Whether to overwrite existing objects in storage to create the Zarr group or array.
**kwargs
Additional keyword arguments will be
Additional keyword arguments will be passed to member `to_zarr` calls and `zarr.create`.

Returns
-------
Expand Down Expand Up @@ -883,14 +883,14 @@ def to_flat(
Examples
--------

>>> from pydantic_zarr.v2 import flatten, GroupSpec
>>> from pydantic_zarr.v2 import to_flat, GroupSpec
>>> g1 = GroupSpec(members=None, attributes={'foo': 'bar'})
>>> to_flat(g1)
{'': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
>>> to_flat(g1 root_path='baz')
>>> to_flat(g1, root_path='baz')
{'baz': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
>>> to_flat(GroupSpec(members={'g1': g1}, attributes={'foo': 'bar'}))
{'/g1': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None), '': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
{'': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None), '/g1': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
"""
result = {}
model_copy: AnyArraySpec | AnyGroupSpec
Expand Down Expand Up @@ -983,7 +983,7 @@ def from_flat_group(data: Mapping[str, AnyArraySpec | AnyGroupSpec]) -> AnyGroup
# populates member_groups
submember_by_parent_name: dict[str, dict[str, AnyArraySpec | AnyGroupSpec]] = {}
# copy the input to ensure that mutations are contained inside this function
data_copy = dict(data).copy()
data_copy = dict(data)
# Get the root node
try:
# The root node is a GroupSpec with the key ""
Expand Down
42 changes: 22 additions & 20 deletions src/pydantic_zarr/v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class V2ChunkKeyEncodingConfig(TypedDict):
separator: Literal[".", "/"]


V2ChunkKeyEncoding = NamedConfig[Literal["v2"], DefaultChunkKeyEncodingConfig]
V2ChunkKeyEncoding = NamedConfig[Literal["v2"], V2ChunkKeyEncodingConfig]


class NodeSpec(StrictBase):
Expand Down Expand Up @@ -207,7 +207,7 @@ class ArraySpec(NodeSpec, Generic[TAttr]):
fill_value: FillValue
The fill value for this array.
codecs: Sequence[NamedConfig]
The sequence of codices for this array.
The sequence of codecs for this array.
storage_transformers: Optional[Sequence[NamedConfig]]
An optional sequence of `NamedConfig` objects that define the storage
transformers for this array.
Expand Down Expand Up @@ -350,10 +350,12 @@ def from_zarr(cls, array: zarr.Array) -> Self:
Examples
--------
>>> import zarr
>>> import zarr.storage
>>> from pydantic_zarr.v3 import ArraySpec
>>> x = zarr.create((10,10))
>>> store = zarr.storage.MemoryStore()
>>> x = zarr.create(store=store, shape=(10, 10), zarr_format=3)
>>> ArraySpec.from_zarr(x)
ArraySpec(zarr_format=2, attributes={}, shape=(10, 10), chunks=(10, 10), dtype='<f8', fill_value=0.0, order='C', filters=None, dimension_separator='.', compressor={'id': 'blosc', 'cname': 'lz4', 'clevel': 5, 'shuffle': 1, 'blocksize': 0})
ArraySpec(zarr_format=3, node_type='array', attributes={}, shape=(10, 10), data_type='float64', chunk_grid={'name': 'regular', 'configuration': {'chunk_shape': (10, 10)}}, chunk_key_encoding={'name': 'default', 'configuration': {'separator': '/'}}, fill_value=0.0, codecs=({'name': 'bytes', 'configuration': {'endian': 'little'}}, {'name': 'zstd', 'configuration': {'level': 0, 'checksum': False}}), storage_transformers=(), dimension_names=None)

"""
try:
Expand Down Expand Up @@ -451,7 +453,7 @@ def like(
exclude: IncEx = None,
) -> bool:
"""
Compare am `ArraySpec` to another `ArraySpec` or a `zarr.Array`, parameterized over the
Compare an `ArraySpec` to another `ArraySpec` or a `zarr.Array`, parameterized over the
fields to exclude or include in the comparison. Models are first converted to `dict` via the
`model_dump` method of `pydantic.BaseModel`, then compared with the `==` operator.

Expand Down Expand Up @@ -601,14 +603,14 @@ def to_flat(self, root_path: str = "") -> dict[str, AnyArraySpec | AnyGroupSpec]
Examples
--------

>>> from pydantic_zarr.v3 import to_flat, GroupSpec
>>> from pydantic_zarr.v3 import GroupSpec
>>> g1 = GroupSpec(members=None, attributes={'foo': 'bar'})
>>> to_flat(g1)
{'': GroupSpec(zarr_format=3, attributes={'foo': 'bar'}, members=None)}
>>> to_flat(g1 root_path='baz')
{'baz': GroupSpec(zarr_format=3, attributes={'foo': 'bar'}, members=None)}
>>> to_flat(GroupSpec(members={'g1': g1}, attributes={'foo': 'bar'}))
{'/g1': GroupSpec(zarr_format=3, attributes={'foo': 'bar'}, members=None), '': GroupSpec(zarr_format=3, attributes={'foo': 'bar'}, members=None)}
>>> g1.to_flat()
{'': GroupSpec(zarr_format=3, node_type='group', attributes={'foo': 'bar'}, members=None)}
>>> g1.to_flat(root_path='baz')
{'baz': GroupSpec(zarr_format=3, node_type='group', attributes={'foo': 'bar'}, members=None)}
>>> GroupSpec(members={'g1': g1}, attributes={'foo': 'bar'}).to_flat()
{'': GroupSpec(zarr_format=3, node_type='group', attributes={'foo': 'bar'}, members=None), '/g1': GroupSpec(zarr_format=3, node_type='group', attributes={'foo': 'bar'}, members=None)}
"""
return to_flat(self, root_path=root_path)

Expand Down Expand Up @@ -968,7 +970,7 @@ def from_flat_group(
# populates member_groups
submember_by_parent_name: dict[str, dict[str, ArraySpec[Any] | GroupSpec[Any, Any]]] = {}
# copy the input to ensure that mutations are contained inside this function
data_copy = dict(data).copy()
data_copy = dict(data)
# Get the root node
try:
# The root node is a GroupSpec with the key ""
Expand Down Expand Up @@ -1041,9 +1043,9 @@ def auto_fill_value(data: object) -> FillValue:
return False
elif kind in ["i", "u"]:
return 0
elif kind in ["f"]:
elif kind == "f":
return "NaN"
elif kind in ["c"]:
elif kind == "c":
return ("NaN", "NaN")
else:
raise ValueError(f"Cannot determine default fill value for data type {kind}")
Expand Down Expand Up @@ -1105,14 +1107,14 @@ def to_flat(node: ArraySpec | GroupSpec, root_path: str = "") -> dict[str, Array
Examples
--------

>>> from pydantic_zarr.v3 import flatten, GroupSpec
>>> from pydantic_zarr.v3 import to_flat, GroupSpec
>>> g1 = GroupSpec(members=None, attributes={'foo': 'bar'})
>>> to_flat(g1)
{'': GroupSpec(zarr_format=3, attributes={'foo': 'bar'}, members=None)}
>>> to_flat(g1 root_path='baz')
{'baz': GroupSpec(zarr_format=3, attributes={'foo': 'bar'}, members=None)}
{'': GroupSpec(zarr_format=3, node_type='group', attributes={'foo': 'bar'}, members=None)}
>>> to_flat(g1, root_path='baz')
{'baz': GroupSpec(zarr_format=3, node_type='group', attributes={'foo': 'bar'}, members=None)}
>>> to_flat(GroupSpec(members={'g1': g1}, attributes={'foo': 'bar'}))
{'/g1': GroupSpec(zarr_format=3, attributes={'foo': 'bar'}, members=None), '': GroupSpec(zarr_format=2, attributes={'foo': 'bar'}, members=None)}
{'': GroupSpec(zarr_format=3, node_type='group', attributes={'foo': 'bar'}, members=None), '/g1': GroupSpec(zarr_format=3, node_type='group', attributes={'foo': 'bar'}, members=None)}
"""
result = {}
model_copy: AnyArraySpec | AnyGroupSpec
Expand Down
2 changes: 1 addition & 1 deletion tests/test_pydantic_zarr/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

@pytest.mark.parametrize("data", ["/", "///", "a/b/", "a/b/vc"])
def test_parse_str_no_path(data: str) -> None:
with pytest.raises(ValueError, match='Strings containing "/" are invalid.'):
with pytest.raises(ValueError, match=r'Strings containing "/" are invalid\.'):
ensure_member_name(data)


Expand Down
2 changes: 1 addition & 1 deletion tests/test_pydantic_zarr/test_experimental/test_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ class GroupB(GroupSpec):

@pytest.mark.parametrize("data", ["/", "a/b/c"])
def test_member_name(data: str) -> None:
with pytest.raises(ValidationError, match='Strings containing "/" are invalid.'):
with pytest.raises(ValidationError, match=r'Strings containing "/" are invalid\.'):
GroupSpec(attributes={}, members={data: GroupSpec(attributes={}, members={})})


Expand Down
4 changes: 2 additions & 2 deletions tests/test_pydantic_zarr/test_experimental/test_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def test_arrayspec_no_empty_codecs(arrayspec: ArraySpec) -> None:
"""

with pytest.raises(
ValidationError, match="Value error, Invalid length. Expected 1 or more, got 0."
ValidationError, match=r"Value error, Invalid length\. Expected 1 or more, got 0\."
):
ArraySpec(**(arrayspec.model_dump() | {"codecs": ()})) # type: ignore[arg-type]

Expand Down Expand Up @@ -396,7 +396,7 @@ def test_arrayspec_with_methods_validation(arrayspec) -> None:
arrayspec.with_dimension_names(("x", "y")) # 2 names for 1D array

# Test that validation fails with empty codecs
with pytest.raises(ValidationError, match="Invalid length. Expected 1 or more, got 0"):
with pytest.raises(ValidationError, match=r"Invalid length\. Expected 1 or more, got 0"):
arrayspec.with_codecs(())


Expand Down
2 changes: 1 addition & 1 deletion tests/test_pydantic_zarr/test_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ def test_from_array(shape: tuple[int, ...], dtype: str | None) -> None:

@pytest.mark.parametrize("data", ["/", "a/b/c"])
def test_member_name(data: str) -> None:
with pytest.raises(ValidationError, match='Strings containing "/" are invalid.'):
with pytest.raises(ValidationError, match=r'Strings containing "/" are invalid\.'):
GroupSpec(attributes={}, members={data: GroupSpec(attributes={}, members={})})


Expand Down
2 changes: 1 addition & 1 deletion tests/test_pydantic_zarr/test_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def test_arrayspec_no_empty_codecs() -> None:
"""

with pytest.raises(
ValidationError, match="Value error, Invalid length. Expected 1 or more, got 0."
ValidationError, match=r"Value error, Invalid length\. Expected 1 or more, got 0\."
):
ArraySpec(
shape=(1,),
Expand Down
Loading