10
10
11
11
from zarr .compressors import get_compressor_cls
12
12
from zarr .util import is_total_slice , normalize_array_selection , \
13
- get_chunk_range , human_readable_size , normalize_resize_args
14
- from zarr .storage import normalize_prefix , normalize_key , array_meta_key , \
15
- array_attrs_key , listdir
16
- from zarr .meta import decode_metadata , encode_metadata
13
+ get_chunk_range , human_readable_size , normalize_resize_args , \
14
+ normalize_storage_path
15
+ from zarr .storage import array_meta_key , attrs_key , listdir , contains_group , \
16
+ buffersize
17
+ from zarr .meta import decode_array_metadata , encode_array_metadata
17
18
from zarr .attrs import Attributes
18
- from zarr .compat import itervalues
19
19
from zarr .errors import ReadOnlyError
20
20
21
21
@@ -70,22 +70,30 @@ class Array(object):
70
70
71
71
""" # flake8: noqa
72
72
73
- def __init__ (self , store , name = None , readonly = False ):
73
+ def __init__ (self , store , path = None , readonly = False ):
74
74
# N.B., expect at this point store is fully initialised with all
75
75
# configuration metadata fully specified and normalised
76
76
77
77
self ._store = store
78
- self ._prefix = normalize_prefix (name )
78
+ self ._path = normalize_storage_path (path )
79
+ if self ._path :
80
+ self ._key_prefix = self ._path + '/'
81
+ else :
82
+ self ._key_prefix = ''
79
83
self ._readonly = readonly
80
84
85
+ # guard conditions
86
+ if contains_group (store , path = self ._path ):
87
+ raise ValueError ('store contains a group' )
88
+
81
89
# initialise metadata
82
- meta_key = array_meta_key (self ._prefix )
83
90
try :
84
- meta_bytes = store [meta_key ]
91
+ mkey = self ._key_prefix + array_meta_key
92
+ meta_bytes = store [mkey ]
85
93
except KeyError :
86
94
raise ValueError ('store has no metadata' )
87
95
else :
88
- meta = decode_metadata (meta_bytes )
96
+ meta = decode_array_metadata (meta_bytes )
89
97
self ._meta = meta
90
98
self ._shape = meta ['shape' ]
91
99
self ._chunks = meta ['chunks' ]
@@ -98,28 +106,36 @@ def __init__(self, store, name=None, readonly=False):
98
106
self ._compressor = compressor_cls (self ._compression_opts )
99
107
100
108
# initialise attributes
101
- attrs_key = array_attrs_key ( self ._prefix )
102
- self ._attrs = Attributes (store , key = attrs_key , readonly = readonly )
109
+ akey = self ._key_prefix + attrs_key
110
+ self ._attrs = Attributes (store , key = akey , readonly = readonly )
103
111
104
112
def flush_metadata (self ):
105
113
meta = dict (shape = self ._shape , chunks = self ._chunks , dtype = self ._dtype ,
106
114
compression = self ._compression ,
107
115
compression_opts = self ._compression_opts ,
108
116
fill_value = self ._fill_value , order = self ._order )
109
- meta_key = array_meta_key ( self ._prefix )
110
- self ._store [meta_key ] = encode_metadata (meta )
117
+ mkey = self ._key_prefix + array_meta_key
118
+ self ._store [mkey ] = encode_array_metadata (meta )
111
119
112
120
@property
113
121
def store (self ):
114
122
"""A MutableMapping providing the underlying storage for the array."""
115
123
return self ._store
116
124
125
+ @property
126
+ def path (self ):
127
+ """TODO doc me"""
128
+ return self ._path
129
+
117
130
@property
118
131
def name (self ):
119
- """TODO"""
120
- if self ._prefix :
121
- # follow h5py convention: add leading slash, remove trailing slash
122
- return '/' + self ._prefix [:- 1 ]
132
+ """TODO doc me"""
133
+ if self .path :
134
+ # follow h5py convention: add leading slash
135
+ name = self .path
136
+ if name [0 ] != '/' :
137
+ name = '/' + name
138
+ return name
123
139
return None
124
140
125
141
@property
@@ -196,29 +212,25 @@ def nbytes_stored(self):
196
212
attributes encoded as JSON."""
197
213
if hasattr (self ._store , 'getsize' ):
198
214
# pass through
199
- return self ._store .getsize (self ._prefix )
215
+ return self ._store .getsize (self ._path )
200
216
elif isinstance (self ._store , dict ):
201
- # cheap to compute by summing length of values
217
+ # compute from size of values
202
218
size = 0
203
- for child in ls (self ._store , self ._prefix ):
204
- key = self ._prefix + child
219
+ for k in listdir (self ._store , self ._path ):
220
+ v = self ._store [ self . _key_prefix + k ]
205
221
try :
206
- size += len ( self . _store [ key ] )
207
- except KeyError :
208
- pass
222
+ size += buffersize ( v )
223
+ except TypeError :
224
+ return - 1
209
225
return size
210
226
else :
211
227
return - 1
212
228
213
229
@property
214
230
def initialized (self ):
215
231
"""The number of chunks that have been initialized with some data."""
216
- n = 0
217
- for child in listdir (self ._store , self ._prefix ):
218
- key = self ._prefix + child
219
- if key in self ._store :
220
- n += 1
221
- # N.B., expect 'meta' and 'attrs' keys in store also, so subtract 2
232
+ n = sum (1 for _ in listdir (self ._store , self ._path ))
233
+ # N.B., expect meta and attrs keys in store also, so subtract 2
222
234
return n - 2
223
235
224
236
@property
@@ -234,7 +246,7 @@ def __eq__(self, other):
234
246
isinstance (other , Array ) and
235
247
self .store == other .store and
236
248
self .readonly == other .readonly and
237
- self .name == other .name
249
+ self .path == other .path
238
250
# N.B., no need to compare other properties, should be covered by
239
251
# store comparison
240
252
)
@@ -509,7 +521,7 @@ def _chunk_getitem(self, cidx, item, dest):
509
521
try :
510
522
511
523
# obtain compressed data for chunk
512
- ckey = self ._prefix + '.' . join ( map ( str , cidx ) )
524
+ ckey = self ._ckey ( cidx )
513
525
cdata = self ._store [ckey ]
514
526
515
527
except KeyError :
@@ -584,7 +596,7 @@ def _chunk_setitem(self, cidx, key, value):
584
596
try :
585
597
586
598
# obtain compressed data for chunk
587
- ckey = self ._prefix + '.' . join ( map ( str , cidx ) )
599
+ ckey = self ._ckey ( cidx )
588
600
cdata = self ._store [ckey ]
589
601
590
602
except KeyError :
@@ -609,9 +621,12 @@ def _chunk_setitem(self, cidx, key, value):
609
621
cdata = self ._compressor .compress (chunk )
610
622
611
623
# store
612
- ckey = '.' . join ( map ( str , cidx ) )
624
+ ckey = self . _ckey ( cidx )
613
625
self ._store [ckey ] = cdata
614
626
627
+ def _ckey (self , cidx ):
628
+ return self ._key_prefix + '.' .join (map (str , cidx ))
629
+
615
630
def __repr__ (self ):
616
631
r = '%s.%s(' % (type (self ).__module__ , type (self ).__name__ )
617
632
if self .name :
@@ -635,7 +650,7 @@ def __repr__(self):
635
650
return r
636
651
637
652
def __getstate__ (self ):
638
- return self ._store , self ._prefix , self ._readonly
653
+ return self ._store , self ._path , self ._readonly
639
654
640
655
def __setstate__ (self , state ):
641
656
self .__init__ (* state )
@@ -690,7 +705,7 @@ def resize(self, *args):
690
705
691
706
# remove any chunks not within range
692
707
for key in list (self ._store ):
693
- if key not in ['meta' , 'attrs' ]:
708
+ if key not in [array_meta_key , attrs_key ]:
694
709
cidx = map (int , key .split ('.' ))
695
710
if all (i < c for i , c in zip (cidx , new_cdata_shape )):
696
711
pass # keep the chunk
0 commit comments