Skip to content

Commit b1aa5fe

Browse files
committed
open... functions accept any store; resolves #56
1 parent a00627e commit b1aa5fe

File tree

6 files changed

+110
-73
lines changed

6 files changed

+110
-73
lines changed

docs/release.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ Release notes
55
on the :class:`zarr.hierarchy.Group` class
66
(`#71 <https://github.com/alimanfoo/zarr/issues/71>`_).
77
* Added ``cache_metadata`` keyword argument to array creation methods.
8+
* The functions :func:`zarr.creation.open_array` and
9+
:func:`zarr.hierarchy.open_group` now accept any store as first argument
10+
(`#56 <https://github.com/alimanfoo/zarr/issues/56>`_).
811

912
.. _release_2.0.1:
1013

zarr/creation.py

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ def create(shape, chunks=None, dtype=None, compressor='default',
3232
Default value to use for uninitialized portions of the array.
3333
order : {'C', 'F'}, optional
3434
Memory layout to be used within each chunk.
35-
store : MutableMapping, optional
36-
Array storage. If not provided, a Python dict will be used, meaning
37-
array data will be stored in memory.
35+
store : MutableMapping or string
36+
Store or path to directory in file system.
3837
synchronizer : object, optional
3938
Array synchronizer.
4039
overwrite : bool, optional
@@ -72,9 +71,8 @@ def create(shape, chunks=None, dtype=None, compressor='default',
7271
7372
""" # flake8: noqa
7473

75-
# initialize store
76-
if store is None:
77-
store = dict()
74+
# handle polymorphic store arg
75+
store = _handle_store_arg(store)
7876

7977
# compatibility
8078
compressor, fill_value = _handle_kwargs(compressor, fill_value, kwargs)
@@ -92,6 +90,15 @@ def create(shape, chunks=None, dtype=None, compressor='default',
9290
return z
9391

9492

93+
def _handle_store_arg(store):
94+
if store is None:
95+
return dict()
96+
elif isinstance(store, str):
97+
return DirectoryStore(store)
98+
else:
99+
return store
100+
101+
95102
def _handle_kwargs(compressor, fill_value, kwargs):
96103

97104
# to be compatible with h5py, as well as backwards-compatible with Zarr
@@ -280,16 +287,16 @@ def array(data, **kwargs):
280287
return z
281288

282289

283-
def open_array(path, mode='a', shape=None, chunks=None, dtype=None,
290+
def open_array(store=None, mode='a', shape=None, chunks=None, dtype=None,
284291
compressor='default', fill_value=None, order='C',
285-
synchronizer=None, filters=None, cache_metadata=True, **kwargs):
286-
"""Convenience function to instantiate an array stored in a
287-
directory on the file system.
292+
synchronizer=None, filters=None, cache_metadata=True,
293+
path=None, **kwargs):
294+
"""Open array using mode-like semantics.
288295
289296
Parameters
290297
----------
291-
path : string
292-
Path to directory in file system in which to store the array.
298+
store : MutableMapping or string
299+
Store or path to directory in file system.
293300
mode : {'r', 'r+', 'a', 'w', 'w-'}
294301
Persistence mode: 'r' means read only (must exist); 'r+' means
295302
read/write (must exist); 'a' means read/write (create if doesn't
@@ -316,6 +323,8 @@ def open_array(path, mode='a', shape=None, chunks=None, dtype=None,
316323
lifetime of the object. If False, array metadata will be reloaded
317324
prior to all data access and modification operations (may incur
318325
overhead depending on storage and data access pattern).
326+
path : string, optional
327+
Array path.
319328
320329
Returns
321330
-------
@@ -349,57 +358,56 @@ def open_array(path, mode='a', shape=None, chunks=None, dtype=None,
349358
350359
""" # flake8: noqa
351360

352-
# use same mode semantics as h5py, although N.B., here `path` is a
353-
# directory:
361+
# use same mode semantics as h5py
354362
# r : read only, must exist
355363
# r+ : read/write, must exist
356364
# w : create, delete if exists
357365
# w- or x : create, fail if exists
358366
# a : read/write if exists, create otherwise (default)
359367

360-
# setup store
361-
store = DirectoryStore(path)
368+
# handle polymorphic store arg
369+
store = _handle_store_arg(store)
362370

363371
# compatibility
364372
compressor, fill_value = _handle_kwargs(compressor, fill_value, kwargs)
365373

366374
# ensure store is initialized
367375

368376
if mode in ['r', 'r+']:
369-
if contains_group(store):
377+
if contains_group(store, path=path):
370378
raise ValueError('store contains group')
371-
elif not contains_array(store):
379+
elif not contains_array(store, path=path):
372380
raise ValueError('array does not exist')
373381

374382
elif mode == 'w':
375383
init_array(store, shape=shape, chunks=chunks, dtype=dtype,
376384
compressor=compressor, fill_value=fill_value,
377-
order=order, filters=filters, overwrite=True)
385+
order=order, filters=filters, overwrite=True, path=path)
378386

379387
elif mode == 'a':
380-
if contains_group(store):
388+
if contains_group(store, path=path):
381389
raise ValueError('store contains group')
382-
elif not contains_array(store):
390+
elif not contains_array(store, path=path):
383391
init_array(store, shape=shape, chunks=chunks, dtype=dtype,
384392
compressor=compressor, fill_value=fill_value,
385-
order=order, filters=filters)
393+
order=order, filters=filters, path=path)
386394

387395
elif mode in ['w-', 'x']:
388-
if contains_group(store):
396+
if contains_group(store, path=path):
389397
raise ValueError('store contains group')
390-
elif contains_array(store):
398+
elif contains_array(store, path=path):
391399
raise ValueError('store contains array')
392400
else:
393401
init_array(store, shape=shape, chunks=chunks, dtype=dtype,
394402
compressor=compressor, fill_value=fill_value,
395-
order=order, filters=filters)
403+
order=order, filters=filters, path=path)
396404

397405
# determine read only status
398406
read_only = mode == 'r'
399407

400408
# instantiate array
401409
z = Array(store, read_only=read_only, synchronizer=synchronizer,
402-
cache_metadata=cache_metadata)
410+
cache_metadata=cache_metadata, path=path)
403411

404412
return z
405413

zarr/hierarchy.py

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ class Group(Mapping):
2222
2323
Parameters
2424
----------
25-
store : HierarchicalStore
25+
store : MutableMapping
2626
Group store, already initialized.
2727
path : string, optional
28-
Storage path.
28+
Group path.
2929
read_only : bool, optional
3030
True if group should be protected against modification.
3131
chunk_store : MutableMapping, optional
@@ -749,14 +749,23 @@ def _full_like_nosync(self, name, data, **kwargs):
749749
chunk_store=self._chunk_store, **kwargs)
750750

751751

752-
def group(store=None, overwrite=False, chunk_store=None, synchronizer=None):
752+
def _handle_store_arg(store):
753+
if store is None:
754+
return DictStore()
755+
elif isinstance(store, str):
756+
return DirectoryStore(store)
757+
else:
758+
return store
759+
760+
761+
def group(store=None, overwrite=False, chunk_store=None, synchronizer=None,
762+
path=None):
753763
"""Create a group.
754764
755765
Parameters
756766
----------
757-
store : MutableMapping, optional
758-
Group storage. If not provided, a DictStore will be used, meaning
759-
that data will be stored in memory.
767+
store : MutableMapping or string
768+
Store or path to directory in file system.
760769
overwrite : bool, optional
761770
If True, delete any pre-existing data in `store` at `path` before
762771
creating the group.
@@ -765,6 +774,8 @@ def group(store=None, overwrite=False, chunk_store=None, synchronizer=None):
765774
for storage of both chunks and metadata.
766775
synchronizer : object, optional
767776
Array synchronizer.
777+
path : string, optional
778+
Group path.
768779
769780
Returns
770781
-------
@@ -791,33 +802,34 @@ def group(store=None, overwrite=False, chunk_store=None, synchronizer=None):
791802
792803
"""
793804

794-
# ensure store
795-
if store is None:
796-
store = DictStore()
805+
# handle polymorphic store arg
806+
store = _handle_store_arg(store)
797807

798808
# require group
799809
if overwrite or not contains_group(store):
800-
init_group(store, overwrite=overwrite, chunk_store=chunk_store)
810+
init_group(store, overwrite=overwrite, chunk_store=chunk_store,
811+
path=path)
801812

802813
return Group(store, read_only=False, chunk_store=chunk_store,
803-
synchronizer=synchronizer)
814+
synchronizer=synchronizer, path=path)
804815

805816

806-
def open_group(path, mode='a', synchronizer=None):
807-
"""Convenience function to instantiate a group stored in a directory on
808-
the file system.
817+
def open_group(store=None, mode='a', synchronizer=None, path=None):
818+
"""Open a group using mode-like semantics.
809819
810820
Parameters
811821
----------
812-
path : string
813-
Path to directory in file system in which to store the group.
822+
store : MutableMapping or string
823+
Store or path to directory in file system.
814824
mode : {'r', 'r+', 'a', 'w', 'w-'}
815825
Persistence mode: 'r' means read only (must exist); 'r+' means
816826
read/write (must exist); 'a' means read/write (create if doesn't
817827
exist); 'w' means create (overwrite if exists); 'w-' means create
818828
(fail if exists).
819829
synchronizer : object, optional
820830
Array synchronizer.
831+
path : string, optional
832+
Group path.
821833
822834
Returns
823835
-------
@@ -843,35 +855,36 @@ def open_group(path, mode='a', synchronizer=None):
843855
844856
"""
845857

846-
# setup store
847-
store = DirectoryStore(path)
858+
# handle polymorphic store arg
859+
store = _handle_store_arg(store)
848860

849861
# ensure store is initialized
850862

851863
if mode in ['r', 'r+']:
852-
if contains_array(store):
864+
if contains_array(store, path=path):
853865
raise ValueError('store contains array')
854-
elif not contains_group(store):
866+
elif not contains_group(store, path=path):
855867
raise ValueError('group does not exist')
856868

857869
elif mode == 'w':
858-
init_group(store, overwrite=True)
870+
init_group(store, overwrite=True, path=path)
859871

860872
elif mode == 'a':
861-
if contains_array(store):
873+
if contains_array(store, path=path):
862874
raise ValueError('store contains array')
863-
if not contains_group(store):
864-
init_group(store)
875+
if not contains_group(store, path=path):
876+
init_group(store, path=path)
865877

866878
elif mode in ['w-', 'x']:
867-
if contains_array(store):
879+
if contains_array(store, path=path):
868880
raise ValueError('store contains array')
869-
elif contains_group(store):
881+
elif contains_group(store, path=path):
870882
raise ValueError('store contains group')
871883
else:
872-
init_group(store)
884+
init_group(store, path=path)
873885

874886
# determine read only status
875887
read_only = mode == 'r'
876888

877-
return Group(store, read_only=read_only, synchronizer=synchronizer)
889+
return Group(store, read_only=read_only, synchronizer=synchronizer,
890+
path=path)

zarr/tests/test_creation.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ def test_full():
101101

102102
def test_open_array():
103103

104-
path = 'example'
104+
store = 'example'
105105

106106
# mode == 'w'
107-
z = open_array(path, mode='w', shape=100, chunks=10)
107+
z = open_array(store, mode='w', shape=100, chunks=10)
108108
z[:] = 42
109109
assert_is_instance(z, Array)
110110
assert_is_instance(z.store, DirectoryStore)
@@ -119,15 +119,15 @@ def test_open_array():
119119
open_array('doesnotexist', mode=mode)
120120
with assert_raises(ValueError):
121121
open_array('example_group', mode=mode)
122-
z = open_array(path, mode='r')
122+
z = open_array(store, mode='r')
123123
assert_is_instance(z, Array)
124124
assert_is_instance(z.store, DirectoryStore)
125125
eq((100,), z.shape)
126126
eq((10,), z.chunks)
127127
assert_array_equal(np.full(100, fill_value=42), z[:])
128128
with assert_raises(PermissionError):
129129
z[:] = 43
130-
z = open_array(path, mode='r+')
130+
z = open_array(store, mode='r+')
131131
assert_is_instance(z, Array)
132132
assert_is_instance(z.store, DirectoryStore)
133133
eq((100,), z.shape)
@@ -137,8 +137,8 @@ def test_open_array():
137137
assert_array_equal(np.full(100, fill_value=43), z[:])
138138

139139
# mode == 'a'
140-
shutil.rmtree(path)
141-
z = open_array(path, mode='a', shape=100, chunks=10)
140+
shutil.rmtree(store)
141+
z = open_array(store, mode='a', shape=100, chunks=10)
142142
z[:] = 42
143143
assert_is_instance(z, Array)
144144
assert_is_instance(z.store, DirectoryStore)
@@ -150,23 +150,28 @@ def test_open_array():
150150

151151
# mode in 'w-', 'x'
152152
for mode in 'w-', 'x':
153-
shutil.rmtree(path)
154-
z = open_array(path, mode=mode, shape=100, chunks=10)
153+
shutil.rmtree(store)
154+
z = open_array(store, mode=mode, shape=100, chunks=10)
155155
z[:] = 42
156156
assert_is_instance(z, Array)
157157
assert_is_instance(z.store, DirectoryStore)
158158
eq((100,), z.shape)
159159
eq((10,), z.chunks)
160160
assert_array_equal(np.full(100, fill_value=42), z[:])
161161
with assert_raises(ValueError):
162-
open_array(path, mode=mode)
162+
open_array(store, mode=mode)
163163
with assert_raises(ValueError):
164164
open_array('example_group', mode=mode)
165165

166166
# with synchronizer
167-
z = open_array(path, synchronizer=ThreadSynchronizer())
167+
z = open_array(store, synchronizer=ThreadSynchronizer())
168168
assert_is_instance(z, Array)
169169

170+
# with path
171+
z = open_array(store, shape=100, path='foo/bar', mode='w')
172+
assert_is_instance(z, Array)
173+
eq('foo/bar', z.path)
174+
170175

171176
def test_empty_like():
172177
# zarr array

0 commit comments

Comments
 (0)