Skip to content

Commit c3f7327

Browse files
author
Martin Durant
committed
Remove consolidated functionality, add tests
1 parent b5d8c9f commit c3f7327

File tree

4 files changed

+51
-62
lines changed

4 files changed

+51
-62
lines changed

zarr/creation.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ def array(data, **kwargs):
357357
def open_array(store=None, mode='a', shape=None, chunks=True, dtype=None,
358358
compressor='default', fill_value=0, order='C', synchronizer=None,
359359
filters=None, cache_metadata=True, cache_attrs=True, path=None,
360-
object_codec=None, chunk_store=None, **kwargs):
360+
object_codec=None, chunk_store=None, storage_options=None,
361+
**kwargs):
361362
"""Open an array using file-mode-like semantics.
362363
363364
Parameters
@@ -403,6 +404,9 @@ def open_array(store=None, mode='a', shape=None, chunks=True, dtype=None,
403404
A codec to encode object arrays, only needed if dtype=object.
404405
chunk_store : MutableMapping or string, optional
405406
Store or path to directory in file system or name of zip file.
407+
storage_options : dict
408+
If using an fsspec URL to create the store, these will be passed to
409+
the backend implementation. Ignored otherwise.
406410
407411
Returns
408412
-------
@@ -439,7 +443,6 @@ def open_array(store=None, mode='a', shape=None, chunks=True, dtype=None,
439443

440444
# handle polymorphic store arg
441445
clobber = mode == 'w'
442-
storage_options = kwargs.pop("storage_options", None)
443446
store = normalize_store_arg(store, clobber=clobber, storage_options=storage_options)
444447
if chunk_store is not None:
445448
chunk_store = normalize_store_arg(chunk_store, clobber=clobber,

zarr/hierarchy.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,9 @@ def open_group(store=None, mode='a', cache_attrs=True, synchronizer=None, path=N
11181118
Group path within store.
11191119
chunk_store : MutableMapping or string, optional
11201120
Store or path to directory in file system or name of zip file.
1121+
storage_options : dict
1122+
If using an fsspec URL to create the store, these will be passed to
1123+
the backend implementation. Ignored otherwise.
11211124
11221125
Returns
11231126
-------
@@ -1140,9 +1143,10 @@ def open_group(store=None, mode='a', cache_attrs=True, synchronizer=None, path=N
11401143
"""
11411144

11421145
# handle polymorphic store arg
1143-
store = _normalize_store_arg(store, storage_options=storage_options)
1146+
clobber = mode != 'r'
1147+
store = _normalize_store_arg(store, clobber=clobber, storage_options=storage_options)
11441148
if chunk_store is not None:
1145-
chunk_store = _normalize_store_arg(chunk_store, storage_options=storage_options)
1149+
chunk_store = _normalize_store_arg(chunk_store, clobber=clobber, storage_options=storage_options)
11461150
path = normalize_storage_path(path)
11471151

11481152
# ensure store is initialized

zarr/storage.py

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -948,9 +948,30 @@ def atexit_rmglob(path,
948948

949949

950950
class FSStore(MutableMapping):
951+
"""Wraps an fsspec.FSMap to give access to arbitrary filesystems
952+
953+
Requires that ``fsspec`` is installed, as well as any additional
954+
requirements for the protocol chosen.
955+
956+
Parameters
957+
----------
958+
url : str
959+
The destination to map. Should include protocol and path,
960+
like "s3://bucket/root"
961+
normalize_keys : bool
962+
key_separator : str
963+
Character to use when constructing the target path strings
964+
for data keys
965+
mode : str
966+
"w" for writable, "r" for read-only
967+
exceptions : list of Exception subclasses
968+
When accessing data, any of these exceptions will be treated
969+
as a missing key
970+
storage_options : passed to the fsspec implementation
971+
"""
951972

952973
def __init__(self, url, normalize_keys=True, key_separator='.',
953-
mode='w', consolidated=False, metadata_key='.zmetadata',
974+
mode='w',
954975
exceptions=(KeyError, PermissionError, IOError),
955976
**storage_options):
956977
import fsspec
@@ -961,24 +982,8 @@ def __init__(self, url, normalize_keys=True, key_separator='.',
961982
self.fs = self.map.fs # for direct operations
962983
self.mode = mode
963984
self.exceptions = exceptions
964-
# TODO: should warn if consolidated and write mode?
965985
if self.fs.exists(url) and not self.fs.isdir(url):
966986
err_fspath_exists_notdir(url)
967-
self.consolidated = consolidated
968-
self.metadata_key = metadata_key
969-
if consolidated:
970-
self.meta = json.loads(self.map.get(metadata_key, b"{}").decode())
971-
if mode == 'r' or 'zarr_consolidated_format' in self.meta:
972-
consolidated_format = self.meta.get('zarr_consolidated_format', None)
973-
if consolidated_format != 1: # pragma: no cover
974-
raise MetadataError('unsupported zarr consolidated metadata format: %s' %
975-
consolidated_format)
976-
else:
977-
self.meta['zarr_consolidated_format'] = 1
978-
979-
@staticmethod
980-
def _is_meta(key):
981-
return key.split('/')[-1] in [attrs_key, group_meta_key, array_meta_key]
982987

983988
def _normalize_key(self, key):
984989
key = normalize_storage_path(key).lstrip('/')
@@ -988,8 +993,6 @@ def _normalize_key(self, key):
988993
return key.lower() if self.normalize_keys else key
989994

990995
def __getitem__(self, key):
991-
if self.consolidated and self._is_meta(key):
992-
return self.meta[key].encode() # expect bytes out
993996
key = self._normalize_key(key)
994997
try:
995998
return self.map[key]
@@ -999,9 +1002,6 @@ def __getitem__(self, key):
9991002
def __setitem__(self, key, value):
10001003
if self.mode == 'r':
10011004
err_read_only()
1002-
if self.consolidated and self._is_meta(key):
1003-
self.meta[key] = value.decode()
1004-
self.map[self.metadata_key] = json.dumps(self.meta).encode()
10051005
key = self._normalize_key(key)
10061006
path = self.dir_path(key)
10071007
value = ensure_contiguous_ndarray(value)
@@ -1015,9 +1015,6 @@ def __setitem__(self, key, value):
10151015
def __delitem__(self, key):
10161016
if self.mode == 'r':
10171017
err_read_only()
1018-
if self.consolidated and self._is_meta(key):
1019-
del self.meta[key]
1020-
self.map[self.metadata_key] = json.dumps(self.meta).encode()
10211018
key = self._normalize_key(key)
10221019
path = self.dir_path(key)
10231020
if self.fs.isdir(path):
@@ -1026,8 +1023,6 @@ def __delitem__(self, key):
10261023
del self.map[key]
10271024

10281025
def __contains__(self, key):
1029-
if self.consolidated and self._is_meta(key):
1030-
return key in self.meta
10311026
key = self._normalize_key(key)
10321027
return key in self.map
10331028

@@ -1071,8 +1066,6 @@ def getsize(self, path=None):
10711066
def clear(self):
10721067
if self.mode == 'r':
10731068
err_read_only()
1074-
if self.consolidated:
1075-
self.meta = {}
10761069
self.map.clear()
10771070

10781071

zarr/tests/test_storage.py

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -852,35 +852,6 @@ def test_complex(self):
852852
assert store["foo"] == b"hello"
853853
assert 'foo' in os.listdir(path2)
854854

855-
def test_consolidated(self):
856-
path = tempfile.mkdtemp()
857-
store = FSStore(path, consolidated=True)
858-
store[".zarray"] = b"{}"
859-
assert ".zmetadata" in os.listdir(path)
860-
del store[".zarray"]
861-
with pytest.raises(KeyError):
862-
store[".zarray"]
863-
store[".zarray"] = b"{}"
864-
865-
os.remove(os.path.join(path, ".zarray"))
866-
store2 = FSStore(path, mode='r', consolidated=True)
867-
assert store != store2
868-
assert ".zarray" in store2
869-
assert store2[".zarray"] == b"{}"
870-
with pytest.raises(PermissionError):
871-
store2[".zarray"] = b"{{}}"
872-
with pytest.raises(PermissionError):
873-
del store2[".zarray"]
874-
with pytest.raises(PermissionError):
875-
store2.clear()
876-
with pytest.raises(PermissionError):
877-
store2.rmdir("any")
878-
with pytest.raises(ValueError):
879-
FSStore(os.path.join(path, ".zmetadata"))
880-
881-
store.clear()
882-
assert ".zmetadata" not in store
883-
884855
def test_not_fsspec(self):
885856
import zarr
886857
path = tempfile.mkdtemp()
@@ -890,6 +861,24 @@ def test_not_fsspec(self):
890861
zarr.open_group(path, mode='w', storage_options={"some": "kwargs"})
891862
zarr.open_array("file://" + path, mode='w', shape=(1,), dtype="f8")
892863

864+
def test_create(self):
865+
import zarr
866+
path1 = tempfile.mkdtemp()
867+
path2 = tempfile.mkdtemp()
868+
g = zarr.open_group("file://" + path1, mode='w',
869+
storage_options={"auto_mkdir": True})
870+
a = g.create_dataset("data", shape=(8,))
871+
a[:4] = [0, 1, 2, 3]
872+
assert "data" in os.listdir(path1)
873+
assert ".zgroup" in os.listdir(path1)
874+
875+
g = zarr.open_group("simplecache::file://" + path1, mode='r',
876+
storage_options={"cache_storage": path2,
877+
"same_names": True})
878+
assert g.data[:].tolist() == [0, 1, 2, 3, 0, 0, 0, 0]
879+
with pytest.raises(PermissionError):
880+
g.data[:] = 1
881+
893882

894883
class TestNestedDirectoryStore(TestDirectoryStore, unittest.TestCase):
895884

0 commit comments

Comments
 (0)