forked from zarr-developers/zarr-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathio.py
More file actions
92 lines (72 loc) · 3.12 KB
/
io.py
File metadata and controls
92 lines (72 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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)