Package dap :: Module dtypes
[hide private]
[frames] | no frames]

Source Code for Module dap.dtypes

  1  """DAP variables. 
  2   
  3  This module is a Python implementation of the DAP data model. 
  4  """ 
  5   
  6  __author__ = "Roberto De Almeida <rob@pydap.org>" 
  7   
  8  import copy 
  9  import itertools 
 10   
 11  from dap.lib import quote 
 12  from dap.util.ordereddict import odict 
 13  from dap.util.filter import get_filters 
 14   
 15  __all__ = ['StructureType', 'SequenceType', 'DatasetType', 'GridType', 'ArrayType', 'BaseType', 
 16             'Float', 'Float0', 'Float8', 'Float16', 'Float32', 'Float64', 'Int', 'Int0', 'Int8', 
 17             'Int16', 'Int32', 'Int64', 'UInt16', 'UInt32', 'UInt64', 'Byte', 'String', 'Url'] 
 18   
 19  _basetypes = ['Float32', 'Float64', 'Int16', 'Int32', 'UInt16', 'UInt32', 'Byte', 'String', 'Url'] 
 20  _constructors = ['StructureType', 'SequenceType', 'DatasetType', 'GridType', 'ArrayType'] 
 21   
 22  # Constants. 
 23  Float   = 'Float64' 
 24  Float0  = 'Float64' 
 25  Float8  = 'Float32' 
 26  Float16 = 'Float32' 
 27  Float32 = 'Float32' 
 28  Float64 = 'Float64' 
 29  Int     = 'Int32' 
 30  Int0    = 'Int32' 
 31  Int8    = 'Byte' 
 32  Int16   = 'Int16' 
 33  Int32   = 'Int32' 
 34  Int64   = 'Int32' 
 35  UInt16  = 'UInt16' 
 36  UInt32  = 'UInt32' 
 37  UInt64  = 'UInt32' 
 38  UInt8   = 'Byte' 
 39  Byte    = 'Byte' 
 40  String  = 'String' 
 41  Url     = 'Url' 
 42   
 43  typemap = { 
 44             # numpy 
 45             'd': Float64, 
 46             'f': Float32, 
 47             'l': Int32, 
 48             'b': Byte, 
 49             'h': Int16, 
 50             'q': Int32, 
 51             'H': UInt16, 
 52             'L': UInt32, 
 53             'Q': UInt32, 
 54             'B': Byte, 
 55             'S': String, 
 56            } 
 57   
 58   
59 -class StructureType(odict):
60 """Structure contructor. 61 62 A structure is a dict-like object, which can hold other DAP variables. 63 Structures have a 'data' attribute that combines the data from the 64 stored variables when read, and propagates the data to the variables 65 when set. 66 67 This behaviour can be bypassed by setting the '_data' attribute; in 68 this case, no data is propagated, and further reads do not combine the 69 data from the stored variables. 70 """ 71
72 - def __init__(self, name='', attributes=None):
73 odict.__init__(self) 74 self.name = quote(name) 75 self.attributes = attributes or {} 76 77 self._id = name 78 self._filters = [] 79 self._data = None
80
81 - def __iter__(self):
82 # Iterate over the variables contained in the structure. 83 return self.itervalues()
84 85 walk = __iter__ 86
87 - def __getattr__(self, attr):
88 # Try to return stored variable. 89 try: 90 return self[attr] 91 except KeyError: 92 # Try to return attribute from self.attributes. 93 try: return self.attributes[attr] 94 except KeyError: raise AttributeError
95
96 - def __setitem__(self, key, item):
97 # Assign a new variable and apply the proper id. 98 self._dict.__setitem__(key, item) 99 if key not in self._keys: self._keys.append(key) 100 101 # Ensure that stored objects have the proper id. 102 item._set_id(self._id)
103
104 - def _get_data(self):
105 if self._data is not None: 106 return self._data 107 else: 108 return [var.data for var in self.values()]
109
110 - def _set_data(self, data):
111 # Propagate the data to the stored variables. 112 for data_, var in itertools.izip(data, self.values()): 113 var.data = data_
114 115 data = property(_get_data, _set_data) 116
117 - def _get_id(self):
118 return self._id
119
120 - def _set_id(self, parent=None):
121 if parent: 122 self._id = '%s.%s' % (parent, self.name) 123 else: 124 self._id = self.name 125 126 # Propagate id to stored variables. 127 for var in self.values(): var._set_id(self._id)
128 129 id = property(_get_id) # Read-only. 130
131 - def _get_filters(self):
132 return self._filters
133
134 - def _set_filters(self, f):
135 self._filters.append(f) 136 137 # Propagate filter to stored variables. 138 for var in self.values(): var._set_filters(f)
139 140 filters = property(_get_filters, _set_filters) 141
142 - def __copy__(self):
143 out = self.__class__(name=self.name, attributes=self.attributes.copy()) 144 out._id = self._id 145 out._filters = self._filters[:] 146 out._data = self._data 147 148 # Stored variables *are not* copied. 149 for k, v in self.items(): 150 out[k] = v 151 return out
152
153 - def __deepcopy__(self, memo=None, _nil=[]):
154 out = self.__class__(name=self.name, attributes=self.attributes.copy()) 155 out._id = self._id 156 out._filters = self._filters[:] 157 ##out._data = copy.copy(self._data) 158 out._data = self._data 159 160 # Stored variables *are* (deep) copied. 161 for k, v in self.items(): 162 out[k] = copy.deepcopy(v) 163 return out
164 165
166 -class DatasetType(StructureType):
167 """Dataset constructor. 168 169 A dataset is very similar to a structure -- the main difference is that 170 its name is not used when composing the fully qualified name of stored 171 variables. 172 """ 173
174 - def __setitem__(self, key, item):
175 self._dict.__setitem__(key, item) 176 if key not in self._keys: self._keys.append(key) 177 178 # Set the id. Here the parent should be None, since the dataset 179 # id is not part of the fully qualified name. 180 item._set_id(None)
181
182 - def _set_id(self, parent=None):
183 self._id = self.name 184 185 # Propagate id. 186 for var in self.values(): var._set_id(None)
187 188
189 -class SequenceType(StructureType):
190 """Sequence constructor. 191 192 A sequence contains ordered data, corresponding to the records in 193 a sequence of structures with the same stored variables. 194 """ 195 # Nesting level. Sequences inside sequences have a level 2, and so on. 196 level = 1 197
198 - def __setitem__(self, key, item):
199 # Assign a new variable and apply the proper id. 200 self._dict.__setitem__(key, item) 201 if key not in self._keys: self._keys.append(key) 202 203 # Ensure that stored objects have the proper id. 204 item._set_id(self._id) 205 206 # If the variable is a sequence, set the nesting level. 207 def set_level(seq, level): 208 if isinstance(seq, SequenceType): 209 seq.level = level 210 for child in seq.walk(): set_level(child, level+1)
211 set_level(item, self.level+1)
212
213 - def walk(self):
214 # Walk over the variables contained in the structure. 215 return self.itervalues()
216
217 - def _get_data(self):
218 # This is similar to the structure _get_data method, except that data 219 # is combined from stored variables using zip(), i.e., grouped values 220 # from each variable. 221 if self._data is not None: 222 return self._data 223 else: 224 return _build_data(self.level, *[var.data for var in self.values()])
225
226 - def _set_data(self, data):
227 for data_, var in itertools.izip(_propagate_data(self.level, data), self.values()): 228 var.data = data_
229 230 data = property(_get_data, _set_data) 231
232 - def __iter__(self):
233 """ 234 When iterating over a sequence, we yield structures containing the 235 corresponding data (first record, second, etc.). 236 """ 237 out = self.__deepcopy__() 238 239 # Set server-side filters. When the sequence is iterated in a 240 # listcomp/genexp, this function inspects the stack and tries to 241 # build a server-side filter from the client-side filter. This 242 # is voodoo black magic, take care. 243 filters = get_filters(out) 244 for filter_ in filters: 245 out._set_filters(filter_) 246 247 for values in out.data: 248 # Yield a nice structure. 249 struct_ = StructureType(name=out.name, attributes=out.attributes) 250 for data, name in zip(values, out.keys()): 251 var = struct_[name] = out[name].__deepcopy__() 252 var.data = data 253 # Set the id. This is necessary since the new structure is not 254 # contained inside a dataset. 255 parent = out._id[:-len(out.name)-1] 256 struct_._set_id(parent) 257 yield struct_
258
259 - def filter(self, *filters):
260 # Make a copy of the sequence. 261 out = self.__deepcopy__() 262 263 # And filter it according to the selection expression. 264 for filter_ in filters: 265 out._set_filters(filter_) 266 return out
267 268
269 -class GridType(object):
270 """Grid constructor. 271 272 A grid is a constructor holding an 'array' variable. The array has its 273 dimensions mapped to 'maps' stored in the grid (lat, lon, time, etc.). 274 Most of the requests are simply passed onto the stored array. 275 """ 276
277 - def __init__(self, name='', array=None, maps=None, attributes=None):
278 self.name = quote(name) 279 self.array = array 280 self.maps = maps or odict() 281 self.attributes = attributes or {} 282 283 self._id = name 284 self._filters = []
285
286 - def __len__(self):
287 return self.array.shape[0]
288
289 - def __iter__(self):
290 # Iterate over the grid. Yield the array and then the maps. 291 yield self.array 292 for map_ in self.maps.values(): yield map_
293 294 walk = __iter__ 295
296 - def __getattr__(self, attr):
297 # Try to return attribute from self.attributes. 298 try: 299 return self.attributes[attr] 300 except KeyError: 301 raise AttributeError
302
303 - def __getitem__(self, index):
304 # Return data from the array. 305 return self.array.