Skip to content

Commit f3c123d

Browse files
committed
Add full copy of zarr-python v2.18.7 under src/zarr/v2
1 parent 80a09d7 commit f3c123d

41 files changed

Lines changed: 30195 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/zarr/v2/__init__.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# flake8: noqa
2+
from zarr.codecs import *
3+
from zarr.convenience import (
4+
consolidate_metadata,
5+
copy,
6+
copy_all,
7+
copy_store,
8+
load,
9+
open,
10+
open_consolidated,
11+
save,
12+
save_array,
13+
save_group,
14+
tree,
15+
)
16+
from zarr.core import Array
17+
from zarr.creation import (
18+
array,
19+
create,
20+
empty,
21+
empty_like,
22+
full,
23+
full_like,
24+
ones,
25+
ones_like,
26+
open_array,
27+
open_like,
28+
zeros,
29+
zeros_like,
30+
)
31+
from zarr.errors import CopyError, MetadataError
32+
from zarr.hierarchy import Group, group, open_group
33+
from zarr.n5 import N5Store, N5FSStore
34+
from zarr._storage.store import v3_api_available
35+
from zarr.storage import (
36+
ABSStore,
37+
DBMStore,
38+
DictStore,
39+
DirectoryStore,
40+
KVStore,
41+
LMDBStore,
42+
LRUStoreCache,
43+
MemoryStore,
44+
MongoDBStore,
45+
NestedDirectoryStore,
46+
RedisStore,
47+
SQLiteStore,
48+
TempStore,
49+
ZipStore,
50+
)
51+
from zarr.sync import ProcessSynchronizer, ThreadSynchronizer
52+
from zarr.version import version as __version__
53+
54+
# in case setuptools scm screw up and find version to be 0.0.0
55+
assert not __version__.startswith("0.0.0")
56+
57+
if v3_api_available:
58+
from zarr._storage.v3 import (
59+
ABSStoreV3,
60+
DBMStoreV3,
61+
KVStoreV3,
62+
DirectoryStoreV3,
63+
LMDBStoreV3,
64+
LRUStoreCacheV3,
65+
MemoryStoreV3,
66+
MongoDBStoreV3,
67+
RedisStoreV3,
68+
SQLiteStoreV3,
69+
ZipStoreV3,
70+
)

src/zarr/v2/_storage/__init__.py

Whitespace-only changes.

src/zarr/v2/_storage/absstore.py

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
"""This module contains storage classes related to Azure Blob Storage (ABS)"""
2+
3+
from typing import Optional
4+
import warnings
5+
6+
from numcodecs.compat import ensure_bytes
7+
from zarr.util import normalize_storage_path
8+
from zarr._storage.store import (
9+
_get_metadata_suffix,
10+
data_root,
11+
meta_root,
12+
Store,
13+
StoreV3,
14+
V3_DEPRECATION_MESSAGE,
15+
)
16+
from zarr.types import DIMENSION_SEPARATOR
17+
18+
__doctest_requires__ = {
19+
("ABSStore", "ABSStore.*"): ["azure.storage.blob"],
20+
}
21+
22+
23+
class ABSStore(Store):
24+
"""Storage class using Azure Blob Storage (ABS).
25+
26+
Parameters
27+
----------
28+
container : string
29+
The name of the ABS container to use.
30+
31+
.. deprecated::
32+
Use ``client`` instead.
33+
34+
prefix : string
35+
Location of the "directory" to use as the root of the storage hierarchy
36+
within the container.
37+
38+
account_name : string
39+
The Azure blob storage account name.
40+
41+
.. deprecated:: 2.8.3
42+
Use ``client`` instead.
43+
44+
account_key : string
45+
The Azure blob storage account access key.
46+
47+
.. deprecated:: 2.8.3
48+
Use ``client`` instead.
49+
50+
blob_service_kwargs : dictionary
51+
Extra arguments to be passed into the azure blob client, for e.g. when
52+
using the emulator, pass in blob_service_kwargs={'is_emulated': True}.
53+
54+
.. deprecated:: 2.8.3
55+
Use ``client`` instead.
56+
57+
dimension_separator : {'.', '/'}, optional
58+
Separator placed between the dimensions of a chunk.
59+
60+
client : azure.storage.blob.ContainerClient, optional
61+
And ``azure.storage.blob.ContainerClient`` to connect with. See
62+
`here <https://docs.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob.containerclient?view=azure-python>`_ # noqa
63+
for more.
64+
65+
.. versionadded:: 2.8.3
66+
67+
Notes
68+
-----
69+
In order to use this store, you must install the Microsoft Azure Storage SDK for Python,
70+
``azure-storage-blob>=12.5.0``.
71+
""" # noqa: E501
72+
73+
def __init__(
74+
self,
75+
container=None,
76+
prefix="",
77+
account_name=None,
78+
account_key=None,
79+
blob_service_kwargs=None,
80+
dimension_separator: Optional[DIMENSION_SEPARATOR] = None,
81+
client=None,
82+
):
83+
warnings.warn(
84+
V3_DEPRECATION_MESSAGE.format(store=self.__class__.__name__),
85+
FutureWarning,
86+
stacklevel=3,
87+
)
88+
89+
self._dimension_separator = dimension_separator
90+
self.prefix = normalize_storage_path(prefix)
91+
if client is None:
92+
# deprecated option, try to construct the client for them
93+
msg = (
94+
"Providing 'container', 'account_name', 'account_key', and 'blob_service_kwargs'"
95+
"is deprecated. Provide and instance of 'azure.storage.blob.ContainerClient' "
96+
"'client' instead."
97+
)
98+
warnings.warn(msg, FutureWarning, stacklevel=2)
99+
from azure.storage.blob import ContainerClient
100+
101+
blob_service_kwargs = blob_service_kwargs or {}
102+
client = ContainerClient(
103+
f"https://{account_name}.blob.core.windows.net/",
104+
container,
105+
credential=account_key,
106+
**blob_service_kwargs,
107+
)
108+
109+
self.client = client
110+
self._container = container
111+
self._account_name = account_name
112+
self._account_key = account_key
113+
114+
@staticmethod
115+
def _warn_deprecated(property_):
116+
msg = (
117+
"The {} property is deprecated and will be removed in a future "
118+
"version. Get the property from 'ABSStore.client' instead."
119+
)
120+
warnings.warn(msg.format(property_), FutureWarning, stacklevel=3)
121+
122+
@property
123+
def container(self):
124+
self._warn_deprecated("container")
125+
return self._container
126+
127+
@property
128+
def account_name(self):
129+
self._warn_deprecated("account_name")
130+
return self._account_name
131+
132+
@property
133+
def account_key(self):
134+
self._warn_deprecated("account_key")
135+
return self._account_key
136+
137+
def _append_path_to_prefix(self, path):
138+
if self.prefix == "":
139+
return normalize_storage_path(path)
140+
else:
141+
return "/".join([self.prefix, normalize_storage_path(path)])
142+
143+
@staticmethod
144+
def _strip_prefix_from_path(path, prefix):
145+
# normalized things will not have any leading or trailing slashes
146+
path_norm = normalize_storage_path(path)
147+
prefix_norm = normalize_storage_path(prefix)
148+
if prefix:
149+
return path_norm[(len(prefix_norm) + 1) :]
150+
else:
151+
return path_norm
152+
153+
def __getitem__(self, key):
154+
from azure.core.exceptions import ResourceNotFoundError
155+
156+
blob_name = self._append_path_to_prefix(key)
157+
try:
158+
return self.client.download_blob(blob_name).readall()
159+
except ResourceNotFoundError as e:
160+
raise KeyError(f"Blob {blob_name} not found") from e
161+
162+
def __setitem__(self, key, value):
163+
value = ensure_bytes(value)
164+
blob_name = self._append_path_to_prefix(key)
165+
self.client.upload_blob(blob_name, value, overwrite=True)
166+
167+
def __delitem__(self, key):
168+
from azure.core.exceptions import ResourceNotFoundError
169+
170+
try:
171+
self.client.delete_blob(self._append_path_to_prefix(key))
172+
except ResourceNotFoundError as e:
173+
raise KeyError(f"Blob {key} not found") from e
174+
175+
def __eq__(self, other):
176+
return (
177+
isinstance(other, ABSStore)
178+
and self.client == other.client
179+
and self.prefix == other.prefix
180+
)
181+
182+
def keys(self):
183+
return list(self.__iter__())
184+
185+
def __iter__(self):
186+
if self.prefix:
187+
list_blobs_prefix = self.prefix + "/"
188+
else:
189+
list_blobs_prefix = None
190+
for blob in self.client.list_blobs(list_blobs_prefix):
191+
yield self._strip_prefix_from_path(blob.name, self.prefix)
192+
193+
def __len__(self):
194+
return len(self.keys())
195+
196+
def __contains__(self, key):
197+
blob_name = self._append_path_to_prefix(key)
198+
return self.client.get_blob_client(blob_name).exists()
199+
200+
def listdir(self, path=None):
201+
dir_path = normalize_storage_path(self._append_path_to_prefix(path))
202+
if dir_path:
203+
dir_path += "/"
204+
items = [
205+
self._strip_prefix_from_path(blob.name, dir_path)
206+
for blob in self.client.walk_blobs(name_starts_with=dir_path, delimiter="/")
207+
]
208+
return items
209+
210+
def rmdir(self, path=None):
211+
dir_path = normalize_storage_path(self._append_path_to_prefix(path))
212+
if dir_path:
213+
dir_path += "/"
214+
for blob in self.client.list_blobs(name_starts_with=dir_path):
215+
self.client.delete_blob(blob)
216+
217+
def getsize(self, path=None):
218+
store_path = normalize_storage_path(path)
219+
fs_path = self._append_path_to_prefix(store_path)
220+
if fs_path:
221+
blob_client = self.client.get_blob_client(fs_path)
222+
else:
223+
blob_client = None
224+
225+
if blob_client and blob_client.exists():
226+
return blob_client.get_blob_properties().size
227+
else:
228+
size = 0
229+
if fs_path == "":
230+
fs_path = None
231+
elif not fs_path.endswith("/"):
232+
fs_path += "/"
233+
for blob in self.client.walk_blobs(name_starts_with=fs_path, delimiter="/"):
234+
blob_client = self.client.get_blob_client(blob.name)
235+
if blob_client.exists():
236+
size += blob_client.get_blob_properties().size
237+
return size
238+
239+
def clear(self):
240+
self.rmdir()
241+
242+
243+
class ABSStoreV3(ABSStore, StoreV3):
244+
def list(self):
245+
return list(self.keys())
246+
247+
def __eq__(self, other):
248+
return (
249+
isinstance(other, ABSStoreV3)
250+
and self.client == other.client
251+
and self.prefix == other.prefix
252+
)
253+
254+
def __setitem__(self, key, value):
255+
self._validate_key(key)
256+
super().__setitem__(key, value)
257+
258+
def rmdir(self, path=None):
259+
if not path:
260+
# Currently allowing clear to delete everything as in v2
261+
262+
# If we disallow an empty path then we will need to modify
263+
# TestABSStoreV3 to have the create_store method use a prefix.
264+
ABSStore.rmdir(self, "")
265+
return
266+
267+
meta_dir = meta_root + path
268+
meta_dir = meta_dir.rstrip("/")
269+
ABSStore.rmdir(self, meta_dir)
270+
271+
# remove data folder
272+
data_dir = data_root + path
273+
data_dir = data_dir.rstrip("/")
274+
ABSStore.rmdir(self, data_dir)
275+
276+
# remove metadata files
277+
sfx = _get_metadata_suffix(self)
278+
array_meta_file = meta_dir + ".array" + sfx
279+
if array_meta_file in self:
280+
del self[array_meta_file]
281+
group_meta_file = meta_dir + ".group" + sfx
282+
if group_meta_file in self:
283+
del self[group_meta_file]
284+
285+
# TODO: adapt the v2 getsize method to work for v3
286+
# For now, calling the generic keys-based _getsize
287+
def getsize(self, path=None):
288+
from zarr.storage import _getsize # avoid circular import
289+
290+
return _getsize(self, path)
291+
292+
293+
ABSStoreV3.__doc__ = ABSStore.__doc__

0 commit comments

Comments
 (0)