@@ -97,19 +97,23 @@ def __init__(self, store, path=None, read_only=False, chunk_store=None,
97
97
self ._is_view = False
98
98
99
99
# initialize metadata
100
- if self ._synchronizer is None :
101
- self ._load_metadata ()
102
- else :
103
- mkey = self ._key_prefix + array_meta_key
104
- with self ._synchronizer [mkey ]:
105
- self ._load_metadata ()
100
+ self ._load_metadata ()
106
101
107
102
# initialize attributes
108
103
akey = self ._key_prefix + attrs_key
109
104
self ._attrs = Attributes (store , key = akey , read_only = read_only ,
110
105
synchronizer = synchronizer )
111
106
112
107
def _load_metadata (self ):
108
+ """(Re)load metadata from store."""
109
+ if self ._synchronizer is None :
110
+ self ._load_metadata_nosync ()
111
+ else :
112
+ mkey = self ._key_prefix + array_meta_key
113
+ with self ._synchronizer [mkey ]:
114
+ self ._load_metadata_nosync ()
115
+
116
+ def _load_metadata_nosync (self ):
113
117
try :
114
118
mkey = self ._key_prefix + array_meta_key
115
119
meta_bytes = self ._store [mkey ]
@@ -136,10 +140,18 @@ def _load_metadata(self):
136
140
# setup filters
137
141
filters = meta ['filters' ]
138
142
if filters :
139
- filters = [get_codec (f ) for f in filters ]
143
+ filters = [get_codec (config ) for config in filters ]
140
144
self ._filters = filters
141
145
142
- def _flush_metadata (self ):
146
+ def _refresh_metadata (self ):
147
+ if not self ._cache_metadata :
148
+ self ._load_metadata ()
149
+
150
+ def _refresh_metadata_nosync (self ):
151
+ if not self ._cache_metadata :
152
+ self ._load_metadata_nosync ()
153
+
154
+ def _flush_metadata_nosync (self ):
143
155
if self ._is_view :
144
156
raise PermissionError ('not permitted for views' )
145
157
@@ -193,9 +205,7 @@ def chunk_store(self):
193
205
def shape (self ):
194
206
"""A tuple of integers describing the length of each dimension of
195
207
the array."""
196
- # refresh metadata because shape can change if array is resized
197
- if not self ._cache_metadata :
198
- self ._load_metadata ()
208
+ self ._refresh_metadata ()
199
209
return self ._shape
200
210
201
211
@shape .setter
@@ -206,38 +216,32 @@ def shape(self, value):
206
216
def chunks (self ):
207
217
"""A tuple of integers describing the length of each dimension of a
208
218
chunk of the array."""
209
- # should be immutable
210
219
return self ._chunks
211
220
212
221
@property
213
222
def dtype (self ):
214
223
"""The NumPy data type."""
215
- # should be immutable
216
224
return self ._dtype
217
225
218
226
@property
219
227
def compressor (self ):
220
228
"""Primary compression codec."""
221
- # should be immutable
222
229
return self ._compressor
223
230
224
231
@property
225
232
def fill_value (self ):
226
233
"""A value used for uninitialized portions of the array."""
227
- # should be immutable
228
234
return self ._fill_value
229
235
230
236
@property
231
237
def order (self ):
232
238
"""A string indicating the order in which bytes are arranged within
233
239
chunks of the array."""
234
- # should be immutable
235
240
return self ._order
236
241
237
242
@property
238
243
def filters (self ):
239
244
"""One or more codecs used to transform data prior to compression."""
240
- # should be immutable
241
245
return self ._filters
242
246
243
247
@property
@@ -256,21 +260,31 @@ def ndim(self):
256
260
"""Number of dimensions."""
257
261
return len (self .shape )
258
262
263
+ @property
264
+ def _size (self ):
265
+ return reduce (operator .mul , self ._shape )
266
+
259
267
@property
260
268
def size (self ):
261
269
"""The total number of elements in the array."""
262
- return reduce (operator .mul , self .shape )
270
+ self ._refresh_metadata ()
271
+ return self ._size
263
272
264
273
@property
265
274
def itemsize (self ):
266
275
"""The size in bytes of each item in the array."""
267
276
return self .dtype .itemsize
268
277
278
+ @property
279
+ def _nbytes (self ):
280
+ return self ._size * self .itemsize
281
+
269
282
@property
270
283
def nbytes (self ):
271
284
"""The total number of bytes that would be required to store the
272
285
array without compression."""
273
- return self .size * self .itemsize
286
+ self ._refresh_metadata ()
287
+ return self ._nbytes
274
288
275
289
@property
276
290
def nbytes_stored (self ):
@@ -287,18 +301,28 @@ def nbytes_stored(self):
287
301
else :
288
302
return m + n
289
303
304
+ @property
305
+ def _cdata_shape (self ):
306
+ return tuple (
307
+ int (np .ceil (s / c )) for s , c in zip (self ._shape , self ._chunks )
308
+ )
309
+
290
310
@property
291
311
def cdata_shape (self ):
292
312
"""A tuple of integers describing the number of chunks along each
293
313
dimension of the array."""
294
- return tuple (
295
- int (np .ceil (s / c )) for s , c in zip (self .shape , self .chunks )
296
- )
314
+ self ._refresh_metadata ()
315
+ return self ._cdata_shape
316
+
317
+ @property
318
+ def _nchunks (self ):
319
+ return reduce (operator .mul , self ._cdata_shape )
297
320
298
321
@property
299
322
def nchunks (self ):
300
323
"""Total number of chunks."""
301
- return reduce (operator .mul , self .cdata_shape )
324
+ self ._refresh_metadata ()
325
+ return self ._nchunks
302
326
303
327
@property
304
328
def nchunks_initialized (self ):
@@ -769,48 +793,45 @@ def _encode_chunk(self, chunk):
769
793
return cdata
770
794
771
795
def __repr__ (self ):
772
-
773
- # refresh metadata
774
- if not self ._cache_metadata :
775
- self ._load_metadata ()
796
+ self ._refresh_metadata ()
776
797
777
798
# main line
778
799
r = '%s(' % type (self ).__name__
779
800
if self .name :
780
801
r += '%s, ' % self .name
781
- r += '%s, ' % str (self .shape )
782
- r += '%s, ' % str (self .dtype )
783
- r += 'chunks=%s, ' % str (self .chunks )
784
- r += 'order=%s' % self .order
802
+ r += '%s, ' % str (self ._shape )
803
+ r += '%s, ' % str (self ._dtype )
804
+ r += 'chunks=%s, ' % str (self ._chunks )
805
+ r += 'order=%s' % self ._order
785
806
r += ')'
786
807
787
808
# storage size info
788
- r += '\n nbytes: %s' % human_readable_size (self .nbytes )
809
+ r += '\n nbytes: %s' % human_readable_size (self ._nbytes )
789
810
if self .nbytes_stored > 0 :
790
811
r += '; nbytes_stored: %s' % human_readable_size (
791
812
self .nbytes_stored )
792
- r += '; ratio: %.1f' % (self .nbytes / self .nbytes_stored )
813
+ r += '; ratio: %.1f' % (self ._nbytes / self .nbytes_stored )
793
814
r += '; initialized: %s/%s' % (self .nchunks_initialized ,
794
- self .nchunks )
815
+ self ._nchunks )
795
816
796
817
# filters
797
- if self .filters :
818
+ if self ._filters :
798
819
# first line
799
- r += '\n filters: %r' % self .filters [0 ]
820
+ r += '\n filters: %r' % self ._filters [0 ]
800
821
# subsequent lines
801
- for f in self .filters [1 :]:
822
+ for f in self ._filters [1 :]:
802
823
r += '\n %r' % f
803
824
804
825
# compressor
805
- if self .compressor :
806
- r += '\n compressor: %r' % self .compressor
826
+ if self ._compressor :
827
+ r += '\n compressor: %r' % self ._compressor
807
828
808
829
# storage and synchronizer classes
809
- r += '\n store: %s' % type (self .store ).__name__
810
- if self .store != self .chunk_store :
811
- r += '; chunk_store: %s' % type (self .chunk_store ).__name__
812
- if self .synchronizer is not None :
813
- r += '; synchronizer: %s' % type (self .synchronizer ).__name__
830
+ r += '\n store: %s' % type (self ._store ).__name__
831
+ if self ._store != self ._chunk_store :
832
+ r += '; chunk_store: %s' % type (self ._chunk_store ).__name__
833
+ if self ._synchronizer is not None :
834
+ r += '; synchronizer: %s' % type (self ._synchronizer ).__name__
814
835
815
836
return r
816
837
@@ -829,24 +850,14 @@ def _write_op(self, f, *args, **kwargs):
829
850
830
851
# synchronization
831
852
if self ._synchronizer is None :
832
-
833
- # refresh metadata
834
- if not self ._cache_metadata :
835
- self ._load_metadata ()
836
-
853
+ self ._refresh_metadata_nosync ()
837
854
return f (* args , ** kwargs )
838
855
839
856
else :
840
-
841
857
# synchronize on the array
842
858
mkey = self ._key_prefix + array_meta_key
843
-
844
859
with self ._synchronizer [mkey ]:
845
-
846
- # refresh metadata
847
- if not self ._cache_metadata :
848
- self ._load_metadata ()
849
-
860
+ self ._refresh_metadata_nosync ()
850
861
return f (* args , ** kwargs )
851
862
852
863
def resize (self , * args ):
@@ -894,7 +905,7 @@ def _resize_nosync(self, *args):
894
905
895
906
# update metadata
896
907
self ._shape = new_shape
897
- self ._flush_metadata ()
908
+ self ._flush_metadata_nosync ()
898
909
899
910
# determine the new number and arrangement of chunks
900
911
chunks = self ._chunks
@@ -920,6 +931,10 @@ def append(self, data, axis=0):
920
931
axis : int
921
932
Axis along which to append.
922
933
934
+ Returns
935
+ -------
936
+ new_shape : tuple
937
+
923
938
Notes
924
939
-----
925
940
The size of all dimensions other than `axis` must match between this
@@ -937,12 +952,14 @@ def append(self, data, axis=0):
937
952
compressor: Blosc(cname='lz4', clevel=5, shuffle=1)
938
953
store: dict
939
954
>>> z.append(a)
955
+ (20000, 1000)
940
956
>>> z
941
957
Array((20000, 1000), int32, chunks=(1000, 100), order=C)
942
958
nbytes: 76.3M; nbytes_stored: 3.8M; ratio: 20.3; initialized: 200/200
943
959
compressor: Blosc(cname='lz4', clevel=5, shuffle=1)
944
960
store: dict
945
961
>>> z.append(np.vstack([a, a]), axis=1)
962
+ (20000, 2000)
946
963
>>> z
947
964
Array((20000, 2000), int32, chunks=(1000, 100), order=C)
948
965
nbytes: 152.6M; nbytes_stored: 7.5M; ratio: 20.3; initialized: 400/400
0 commit comments