-
-
Notifications
You must be signed in to change notification settings - Fork 358
Prevent creation of arrays/groups under a parent array #3407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
382362d
restrict arrays as parents of other arrays
K-Meech bfba0e5
use common save_metadata function for groups and arrays
K-Meech 62b198e
add test for creation under a parent array
K-Meech e62775d
fix failing tests
K-Meech f6e44a9
Merge branch 'main' of github.com:K-Meech/zarr-python into km/child-o…
K-Meech 8541cc8
fix failing doctest
K-Meech f59aaf4
merge upstream changes
K-Meech 5d72564
Merge branch 'main' into km/child-of-array
d-v-b 9b23137
remove dependency on AsyncGroup
K-Meech ac3bb0a
merge upstream changes
K-Meech 8b38670
Merge branch 'km/child-of-array' of github.com:K-Meech/zarr-python in…
K-Meech c8157fd
document changes
K-Meech File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Prevents creation of groups (.create_group) or arrays (.create_array) as children | ||
of an existing array. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
from __future__ import annotations | ||
|
||
import asyncio | ||
from typing import TYPE_CHECKING | ||
|
||
from zarr.abc.store import set_or_delete | ||
from zarr.core.buffer.core import default_buffer_prototype | ||
from zarr.errors import ContainsArrayError | ||
from zarr.storage._common import StorePath, ensure_no_existing_node | ||
|
||
if TYPE_CHECKING: | ||
from zarr.core.common import ZarrFormat | ||
from zarr.core.group import GroupMetadata | ||
from zarr.core.metadata import ArrayMetadata | ||
|
||
|
||
def _build_parents(store_path: StorePath, zarr_format: ZarrFormat) -> dict[str, GroupMetadata]: | ||
from zarr.core.group import GroupMetadata | ||
|
||
path = store_path.path | ||
if not path: | ||
return {} | ||
|
||
required_parts = path.split("/")[:-1] | ||
|
||
# the root group | ||
parents = {"": GroupMetadata(zarr_format=zarr_format)} | ||
|
||
for i, part in enumerate(required_parts): | ||
parent_path = "/".join(required_parts[:i] + [part]) | ||
parents[parent_path] = GroupMetadata(zarr_format=zarr_format) | ||
|
||
return parents | ||
|
||
|
||
async def save_metadata( | ||
store_path: StorePath, metadata: ArrayMetadata | GroupMetadata, ensure_parents: bool = False | ||
) -> None: | ||
"""Asynchronously save the array or group metadata. | ||
|
||
Parameters | ||
---------- | ||
store_path : StorePath | ||
Location to save metadata. | ||
metadata : ArrayMetadata | GroupMetadata | ||
Metadata to save. | ||
ensure_parents : bool, optional | ||
Create any missing parent groups, and check no existing parents are arrays. | ||
|
||
Raises | ||
------ | ||
ValueError | ||
""" | ||
to_save = metadata.to_buffer_dict(default_buffer_prototype()) | ||
set_awaitables = [set_or_delete(store_path / key, value) for key, value in to_save.items()] | ||
|
||
if ensure_parents: | ||
# To enable zarr.create(store, path="a/b/c"), we need to create all the intermediate groups. | ||
parents = _build_parents(store_path, metadata.zarr_format) | ||
ensure_array_awaitables = [] | ||
|
||
for parent_path, parent_metadata in parents.items(): | ||
parent_store_path = StorePath(store_path.store, parent_path) | ||
|
||
# Error if an array already exists at any parent location. Only groups can have child nodes. | ||
ensure_array_awaitables.append( | ||
ensure_no_existing_node( | ||
parent_store_path, parent_metadata.zarr_format, node_type="array" | ||
) | ||
) | ||
set_awaitables.extend( | ||
[ | ||
(parent_store_path / key).set_if_not_exists(value) | ||
for key, value in parent_metadata.to_buffer_dict( | ||
default_buffer_prototype() | ||
).items() | ||
] | ||
) | ||
|
||
# Checks for parent arrays must happen first, before any metadata is modified | ||
try: | ||
await asyncio.gather(*ensure_array_awaitables) | ||
except ContainsArrayError as e: | ||
# clear awaitables to avoid RuntimeWarning: coroutine was never awaited | ||
for awaitable in set_awaitables: | ||
awaitable.close() | ||
|
||
raise ValueError( | ||
f"A parent of {store_path} is an array - only groups may have child nodes." | ||
) from e | ||
|
||
await asyncio.gather(*set_awaitables) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why did we need to change this test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test creates an array as a child of another array, so would throw an error (I changed it to create a group then put both arrays inside instead).
E.g. running the equivalent for a local store, shows an array inside an array: