1111# TODO check_var too complex
1212# TODO createVariables too complex
1313# TODO implement from_file/from_cdl/from_json kwarg!?
14+ # TODO Allow for attribute types to be specified in JSON
1415
1516import json
1617from collections import OrderedDict
@@ -273,11 +274,6 @@ def from_json(cls, path):
273274 global_attributes = template .get ('global_attributes' )
274275 )
275276
276- def set_output (self , outfile , mode = 'w' , ** kwargs ):
277- """Create the dataset """
278- self .outfile = outfile
279- self .ncobj = netCDF4 .Dataset (self .outfile , mode = mode , ** kwargs )
280-
281277 def _create_var_opts (self , vdict ):
282278 """Return a list with attribute names required for the creation of variable
283279 defined by :vdict: This include creation/special options like:
@@ -295,6 +291,40 @@ def _create_var_opts(self, vdict):
295291 inside = inside .union (aliases )
296292 return list (inside )
297293
294+ def update_dimensinos (self ):
295+ """Update the sizes of dimensions to be consistent with the arrays set as variable values, if possible.
296+ Otherwise raise ValueError. Also raise ValueError if a dimension that already has a non-zero size is not
297+ consistent with variable array sizes.
298+ """
299+ for name , var in self .variables .iteritems ():
300+ values = var .get ('values' )
301+ if values is None :
302+ continue
303+
304+ var_shape = values .shape
305+ var_dims = var .get ('dims' , [])
306+ if len (var_shape ) != len (var_dims ):
307+ raise ValueError (
308+ "Variable '{name}' has {ndim} dimensions, but value array has {nshape} dimensions." .format (
309+ name = name , ndim = len (var_dims ), nshape = len (var_shape )
310+ )
311+ )
312+
313+ for dim , size in zip (var_dims , var_shape ):
314+ template_dim = self .dimensions [dim ]
315+ if template_dim is None or template_dim == 0 :
316+ self .dimensions [dim ] = size
317+
318+ # check that shape is now consistent
319+ template_shape = tuple (self .dimensions [d ] for d in var_dims )
320+ if var_shape != template_shape :
321+ raise ValueError (
322+ "Variable '{name}' has dimensions {var_dims} and shape {var_shape}, inconsistent with dimension "
323+ "sizes defined in template {template_shape}" .format (
324+ name = name , var_dims = var_dims , var_shape = var_shape , template_shape = template_shape
325+ )
326+ )
327+
298328 def createDimensions (self ):
299329 """Create the dimensions on the netcdf file"""
300330 for dname , dval in zip (self .dimensions .keys (),
@@ -306,20 +336,17 @@ def createVariables(self, **kwargs):
306336 **kwargs are included here to overload all options for all variables
307337 like `zlib` and friends.
308338 """
309- for v in self .variables .keys ():
310- varname = v #self.variables[v]['name']
311- datatype = self .variables [v ]['type' ]
312- dimensions = self .variables [v ]['dims' ]
313-
314- var_c_opts = {}
339+ for varname , var in self .variables .iteritems ():
340+ datatype = var ['type' ]
341+ dimensions = var ['dims' ]
315342 cwargs = kwargs .copy ()
316343 if dimensions is None : # no kwargs in createVariable
317- self .ncobj .createVariable (varname , datatype )
344+ ncvar = self .ncobj .createVariable (varname , datatype )
318345 else :
319- var_c_keys = list (self ._create_var_opts (self . variables [ v ] ))
346+ var_c_keys = list (self ._create_var_opts (var ))
320347
321348 var_c_opts = dict (
322- (x , self . variables [ v ] [x ]) for x in var_c_keys )
349+ (x , var [x ]) for x in var_c_keys )
323350
324351 ureq_fillvalue = [
325352 x for x in cwargs .keys () if x in self .fill_aliases
@@ -344,32 +371,33 @@ def createVariables(self, **kwargs):
344371 if fv_val :
345372 var_c_opts ['fill_value' ] = fv_val [- 1 ]
346373
347- self .ncobj .createVariable (
374+ ncvar = self .ncobj .createVariable (
348375 varname , datatype , dimensions = dimensions , ** var_c_opts )
349376
350- if 'attr' in self .variables [v ].keys ():
351- attrs = self .variables [v ]['attr' ].copy ()
377+ # add variable values
378+ ncvar [:] = var ['values' ]
379+
380+ # add variable attributes
381+ if var .get ('attr' ):
382+ attrs = var ['attr' ].copy ()
352383 for not_attr in self ._create_var_opts (attrs ):
353384 attrs .pop (not_attr )
354-
355- for attname in attrs .keys ():
356- var = self .ncobj .variables [varname ]
357- value = np .array (attrs [attname ]['value' ]).astype (
358- attrs [attname ]['type' ])
359- var .setncattr (attname , value )
385+ ncvar .setncatts (attrs )
360386
361387 def createGlobalAttrs (self ):
362388 """Add the global attributes for the current class"""
363389 for att in self .global_attributes .keys ():
364390 self .ncobj .setncattr (att , self .global_attributes [att ])
365391
366- def create (self , ** kwargs ):
367- """Create in the dimensions/variable and attributes and fill with
368- basic information"""
392+ def create (self , outfile , mode = 'w' , var_args = {}, ** kwargs ):
393+ """Create the file according to all the information in the template"""
394+ self .outfile = outfile
395+ self .ncobj = netCDF4 .Dataset (self .outfile , mode = mode , ** kwargs )
396+
397+ self .update_dimensinos ()
369398 self .createDimensions ()
370- self .createVariables (** kwargs )
399+ self .createVariables (** var_args )
371400 self .createGlobalAttrs ()
372401 self .ncobj .sync ()
373402 self .ncobj .close ()
374403 self .ncobj = netCDF4 .Dataset (self .outfile , 'a' )
375- pass
0 commit comments