6
6
import time
7
7
import traceback
8
8
import contextlib
9
- from collections import Mapping
9
+ from collections import Mapping , OrderedDict
10
10
import warnings
11
11
12
12
from ..conventions import cf_encoder
@@ -96,6 +96,9 @@ def __getitem__(self, key):
96
96
def __len__ (self ):
97
97
return len (self .variables )
98
98
99
+ def get_dimensions (self ): # pragma: no cover
100
+ raise NotImplementedError
101
+
99
102
def get_attrs (self ): # pragma: no cover
100
103
raise NotImplementedError
101
104
@@ -195,6 +198,37 @@ def __init__(self, writer=None):
195
198
writer = ArrayWriter ()
196
199
self .writer = writer
197
200
201
+ def encode (self , variables , attributes ):
202
+ """
203
+ Encode the variables and attributes in this store
204
+
205
+ Parameters
206
+ ----------
207
+ variables : dict-like
208
+ Dictionary of key/value (variable name / xr.Variable) pairs
209
+ attributes : dict-like
210
+ Dictionary of key/value (attribute name / attribute) pairs
211
+
212
+ Returns
213
+ -------
214
+ variables : dict-like
215
+ attributes : dict-like
216
+
217
+ """
218
+ variables = OrderedDict ([(k , self .encode_variable (v ))
219
+ for k , v in variables .items ()])
220
+ attributes = OrderedDict ([(k , self .encode_attribute (v ))
221
+ for k , v in attributes .items ()])
222
+ return variables , attributes
223
+
224
+ def encode_variable (self , v ):
225
+ """encode one variable"""
226
+ return v
227
+
228
+ def encode_attribute (self , a ):
229
+ """encode one attribute"""
230
+ return a
231
+
198
232
def set_dimension (self , d , l ): # pragma: no cover
199
233
raise NotImplementedError
200
234
@@ -208,24 +242,74 @@ def sync(self):
208
242
self .writer .sync ()
209
243
210
244
def store_dataset (self , dataset ):
211
- # in stores variables are all variables AND coordinates
212
- # in xarray.Dataset variables are variables NOT coordinates,
213
- # so here we pass the whole dataset in instead of doing
214
- # dataset.variables
245
+ """
246
+ in stores, variables are all variables AND coordinates
247
+ in xarray.Dataset variables are variables NOT coordinates,
248
+ so here we pass the whole dataset in instead of doing
249
+ dataset.variables
250
+ """
215
251
self .store (dataset , dataset .attrs )
216
252
217
253
def store (self , variables , attributes , check_encoding_set = frozenset (),
218
254
unlimited_dims = None ):
255
+ """
256
+ Top level method for putting data on this store, this method:
257
+ - encodes variables/attributes
258
+ - sets dimensions
259
+ - sets variables
260
+
261
+ Parameters
262
+ ----------
263
+ variables : dict-like
264
+ Dictionary of key/value (variable name / xr.Variable) pairs
265
+ attributes : dict-like
266
+ Dictionary of key/value (attribute name / attribute) pairs
267
+ check_encoding_set : list-like
268
+ List of variables that should be checked for invalid encoding
269
+ values
270
+ unlimited_dims : list-like
271
+ List of dimension names that should be treated as unlimited
272
+ dimensions.
273
+ """
274
+
275
+ variables , attributes = self .encode (variables , attributes )
276
+
219
277
self .set_attributes (attributes )
278
+ self .set_dimensions (variables , unlimited_dims = unlimited_dims )
220
279
self .set_variables (variables , check_encoding_set ,
221
280
unlimited_dims = unlimited_dims )
222
281
223
282
def set_attributes (self , attributes ):
283
+ """
284
+ This provides a centralized method to set the dataset attributes on the
285
+ data store.
286
+
287
+ Parameters
288
+ ----------
289
+ attributes : dict-like
290
+ Dictionary of key/value (attribute name / attribute) pairs
291
+ """
224
292
for k , v in iteritems (attributes ):
225
293
self .set_attribute (k , v )
226
294
227
295
def set_variables (self , variables , check_encoding_set ,
228
296
unlimited_dims = None ):
297
+ """
298
+ This provides a centralized method to set the variables on the data
299
+ store.
300
+
301
+ Parameters
302
+ ----------
303
+ variables : dict-like
304
+ Dictionary of key/value (variable name / xr.Variable) pairs
305
+ check_encoding_set : list-like
306
+ List of variables that should be checked for invalid encoding
307
+ values
308
+ unlimited_dims : list-like
309
+ List of dimension names that should be treated as unlimited
310
+ dimensions.
311
+ """
312
+
229
313
for vn , v in iteritems (variables ):
230
314
name = _encode_variable_name (vn )
231
315
check = vn in check_encoding_set
@@ -234,24 +318,51 @@ def set_variables(self, variables, check_encoding_set,
234
318
235
319
self .writer .add (source , target )
236
320
237
- def set_necessary_dimensions (self , variable , unlimited_dims = None ):
321
+ def set_dimensions (self , variables , unlimited_dims = None ):
322
+ """
323
+ This provides a centralized method to set the dimensions on the data
324
+ store.
325
+
326
+ Parameters
327
+ ----------
328
+ variables : dict-like
329
+ Dictionary of key/value (variable name / xr.Variable) pairs
330
+ unlimited_dims : list-like
331
+ List of dimension names that should be treated as unlimited
332
+ dimensions.
333
+ """
238
334
if unlimited_dims is None :
239
335
unlimited_dims = set ()
240
- dims = self .get_dimensions ()
241
- for d , l in zip (variable .dims , variable .shape ):
242
- if d not in dims :
243
- is_unlimited = d in unlimited_dims
244
- self .set_dimension (d , l , is_unlimited )
336
+
337
+ existing_dims = self .get_dimensions ()
338
+
339
+ dims = OrderedDict ()
340
+ for v in unlimited_dims : # put unlimited_dims first
341
+ dims [v ] = None
342
+ for v in variables .values ():
343
+ dims .update (dict (zip (v .dims , v .shape )))
344
+
345
+ for dim , length in dims .items ():
346
+ if dim in existing_dims and length != existing_dims [dim ]:
347
+ raise ValueError (
348
+ "Unable to update size for existing dimension"
349
+ "%r (%d != %d)" % (dim , length , existing_dims [dim ]))
350
+ elif dim not in existing_dims :
351
+ is_unlimited = dim in unlimited_dims
352
+ self .set_dimension (dim , length , is_unlimited )
245
353
246
354
247
355
class WritableCFDataStore (AbstractWritableDataStore ):
248
356
249
- def store (self , variables , attributes , * args , ** kwargs ):
357
+ def encode (self , variables , attributes ):
250
358
# All NetCDF files get CF encoded by default, without this attempting
251
359
# to write times, for example, would fail.
252
- cf_variables , cf_attrs = cf_encoder (variables , attributes )
253
- AbstractWritableDataStore .store (self , cf_variables , cf_attrs ,
254
- * args , ** kwargs )
360
+ variables , attributes = cf_encoder (variables , attributes )
361
+ variables = OrderedDict ([(k , self .encode_variable (v ))
362
+ for k , v in variables .items ()])
363
+ attributes = OrderedDict ([(k , self .encode_attribute (v ))
364
+ for k , v in attributes .items ()])
365
+ return variables , attributes
255
366
256
367
257
368
class DataStorePickleMixin (object ):
0 commit comments