| 1 | # Datasets/__init__.py - Base classes that define the interfaces used to access
|
|---|
| 2 | # table and grid datasets.
|
|---|
| 3 | #
|
|---|
| 4 | # Copyright (C) 2010 Jason J. Roberts
|
|---|
| 5 | #
|
|---|
| 6 | # This program is free software; you can redistribute it and/or
|
|---|
| 7 | # modify it under the terms of the GNU General Public License
|
|---|
| 8 | # as published by the Free Software Foundation; either version 2
|
|---|
| 9 | # of the License, or (at your option) any later version.
|
|---|
| 10 | #
|
|---|
| 11 | # This program is distributed in the hope that it will be useful,
|
|---|
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 14 | # GNU General Public License (available in the file LICENSE.TXT)
|
|---|
| 15 | # for more details.
|
|---|
| 16 | #
|
|---|
| 17 | # You should have received a copy of the GNU General Public License
|
|---|
| 18 | # along with this program; if not, write to the Free Software
|
|---|
| 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|---|
| 20 |
|
|---|
| 21 | import atexit
|
|---|
| 22 | import bisect
|
|---|
| 23 | import codecs
|
|---|
| 24 | import copy
|
|---|
| 25 | import datetime
|
|---|
| 26 | import math
|
|---|
| 27 | import locale
|
|---|
| 28 | import logging
|
|---|
| 29 | import os
|
|---|
| 30 | import re
|
|---|
| 31 | import shutil
|
|---|
| 32 | import types
|
|---|
| 33 | import weakref
|
|---|
| 34 |
|
|---|
| 35 | from GeoEco.DynamicDocString import DynamicDocString
|
|---|
| 36 | from GeoEco.Internationalization import _
|
|---|
| 37 | from GeoEco.Logging import Logger, ProgressReporter
|
|---|
| 38 |
|
|---|
| 39 |
|
|---|
| 40 | class CollectibleObject(object):
|
|---|
| 41 | __doc__ = DynamicDocString()
|
|---|
| 42 |
|
|---|
| 43 | # Public properties and methods
|
|---|
| 44 |
|
|---|
| 45 | def _GetDisplayNameProp(self):
|
|---|
| 46 | return self._GetDisplayName()
|
|---|
| 47 |
|
|---|
| 48 | DisplayName = property(_GetDisplayNameProp, doc=DynamicDocString())
|
|---|
| 49 |
|
|---|
| 50 | def _GetParentCollection(self):
|
|---|
| 51 | return self._ParentCollection
|
|---|
| 52 |
|
|---|
| 53 | ParentCollection = property(_GetParentCollection, doc=DynamicDocString())
|
|---|
| 54 |
|
|---|
| 55 | def GetQueryableAttribute(self, name):
|
|---|
| 56 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 57 |
|
|---|
| 58 | obj = self
|
|---|
| 59 | while obj is not None:
|
|---|
| 60 | if obj._QueryableAttributes is not None:
|
|---|
| 61 | for attr in obj._QueryableAttributes:
|
|---|
| 62 | if attr.Name == name:
|
|---|
| 63 | return attr
|
|---|
| 64 | obj = obj.ParentCollection
|
|---|
| 65 |
|
|---|
| 66 | return None
|
|---|
| 67 |
|
|---|
| 68 | def GetQueryableAttributesWithDataType(self, typeMetadata):
|
|---|
| 69 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 70 |
|
|---|
| 71 | attrs = []
|
|---|
| 72 | obj = self
|
|---|
| 73 | while obj is not None:
|
|---|
| 74 | if obj._QueryableAttributes is not None:
|
|---|
| 75 | for attr in obj._QueryableAttributes:
|
|---|
| 76 | if issubclass(attr.DataType.__class__, typeMetadata):
|
|---|
| 77 | attrs.append(attr)
|
|---|
| 78 | obj = obj.ParentCollection
|
|---|
| 79 |
|
|---|
| 80 | return attrs
|
|---|
| 81 |
|
|---|
| 82 | def GetAllQueryableAttributes(self):
|
|---|
| 83 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 84 |
|
|---|
| 85 | attrs = []
|
|---|
| 86 | obj = self
|
|---|
| 87 | while obj is not None:
|
|---|
| 88 | if obj._QueryableAttributes is not None:
|
|---|
| 89 | for attr in obj._QueryableAttributes:
|
|---|
| 90 | attrs.append(attr)
|
|---|
| 91 | obj = obj.ParentCollection
|
|---|
| 92 |
|
|---|
| 93 | return attrs
|
|---|
| 94 |
|
|---|
| 95 | def GetQueryableAttributeValue(self, name):
|
|---|
| 96 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 97 |
|
|---|
| 98 | # Check whether the value has been explicitly assigned to us
|
|---|
| 99 | # or our parents.
|
|---|
| 100 |
|
|---|
| 101 | obj = self
|
|---|
| 102 | while obj is not None:
|
|---|
| 103 | if obj._QueryableAttributeValues is not None:
|
|---|
| 104 | if name in obj._QueryableAttributeValues:
|
|---|
| 105 | return obj._QueryableAttributeValues[name]
|
|---|
| 106 | obj = obj.ParentCollection
|
|---|
| 107 |
|
|---|
| 108 | # Check whether the value is derived from another queryable
|
|---|
| 109 | # attribute.
|
|---|
| 110 |
|
|---|
| 111 | thisAttr = self.GetQueryableAttribute(name)
|
|---|
| 112 | if thisAttr is not None and thisAttr.DerivedFromAttr is not None:
|
|---|
| 113 | derivedFromValue = self.GetQueryableAttributeValue(thisAttr.DerivedFromAttr)
|
|---|
| 114 | if derivedFromValue is not None:
|
|---|
| 115 | if thisAttr.DerivedValueMap is not None:
|
|---|
| 116 | if derivedFromValue in thisAttr.DerivedValueMap:
|
|---|
| 117 | return thisAttr.DerivedValueMap[derivedFromValue]
|
|---|
| 118 | else:
|
|---|
| 119 | return thisAttr.DerivedValueFunc(self, derivedFromValue)
|
|---|
| 120 |
|
|---|
| 121 | # We did not find it. Return None.
|
|---|
| 122 |
|
|---|
| 123 | return None
|
|---|
| 124 |
|
|---|
| 125 | def GetLazyPropertyValue(self, name, allowPhysicalValue=True):
|
|---|
| 126 |
|
|---|
| 127 | # Check whether value is cached in our dictionary or our
|
|---|
| 128 | # parents' dictionaries.
|
|---|
| 129 |
|
|---|
| 130 | obj = self
|
|---|
| 131 | while obj is not None:
|
|---|
| 132 | if obj._LazyPropertyValues is not None and name in obj._LazyPropertyValues:
|
|---|
| 133 | return obj._LazyPropertyValues[name]
|
|---|
| 134 | obj = obj.ParentCollection
|
|---|
| 135 |
|
|---|
| 136 | # Check whether the value is assigned by a queryable
|
|---|
| 137 | # attribute.
|
|---|
| 138 |
|
|---|
| 139 | obj = self
|
|---|
| 140 | while obj is not None:
|
|---|
| 141 | if obj._QueryableAttributes is not None:
|
|---|
| 142 | for attr in obj._QueryableAttributes:
|
|---|
| 143 | if attr.DerivedLazyDatasetProps is not None:
|
|---|
| 144 | attrValue = self.GetQueryableAttributeValue(attr.Name)
|
|---|
| 145 | if attrValue in attr.DerivedLazyDatasetProps and name in attr.DerivedLazyDatasetProps[attrValue]:
|
|---|
| 146 | value = attr.DerivedLazyDatasetProps[attrValue][name]
|
|---|
| 147 | self.SetLazyPropertyValue(name, value)
|
|---|
| 148 | return value
|
|---|
| 149 | obj = obj.ParentCollection
|
|---|
| 150 |
|
|---|
| 151 | # If allowed, retrieve the value from physical storage. This
|
|---|
| 152 | # is typically slow and could involve downloading and/or
|
|---|
| 153 | # decompressing the dataset into a cache directory, if this is
|
|---|
| 154 | # the first time it is being physically accessed.
|
|---|
| 155 |
|
|---|
| 156 | if not allowPhysicalValue:
|
|---|
| 157 | return None
|
|---|
| 158 |
|
|---|
| 159 | value = self._GetLazyPropertyPhysicalValue(name)
|
|---|
| 160 | self.SetLazyPropertyValue(name, value)
|
|---|
| 161 | return value
|
|---|
| 162 |
|
|---|
| 163 | def SetLazyPropertyValue(self, name, value):
|
|---|
| 164 | if self._LazyPropertyValues is None:
|
|---|
| 165 | self._LazyPropertyValues = {}
|
|---|
| 166 | self._LazyPropertyValues[name] = value
|
|---|
| 167 |
|
|---|
| 168 | def HasLazyPropertyValue(self, name, allowPhysicalValue=True):
|
|---|
| 169 | return self.GetLazyPropertyValue(name, allowPhysicalValue) is not None or self._LazyPropertyValues is not None and name in self._LazyPropertyValues
|
|---|
| 170 |
|
|---|
| 171 | def Close(self):
|
|---|
| 172 | try:
|
|---|
| 173 | self._Close()
|
|---|
| 174 | except:
|
|---|
| 175 | pass
|
|---|
| 176 |
|
|---|
| 177 | @classmethod
|
|---|
| 178 | def TestCapability(cls, capability):
|
|---|
| 179 | cls.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 180 | return cls._TestCapability(capability)
|
|---|
| 181 |
|
|---|
| 182 | # Private base class constructor. Do not invoke directly; use a
|
|---|
| 183 | # derived class instead. If you override, be sure to call it from
|
|---|
| 184 | # your derived class's __init__.
|
|---|
| 185 |
|
|---|
| 186 | # TODO: Clean up comments like the one above. Either remove them
|
|---|
| 187 | # entirely (put instructions on creating derived classes in the
|
|---|
| 188 | # documentation) or make them completely clear and succinct.
|
|---|
| 189 |
|
|---|
| 190 | def __init__(self, parentCollection=None, queryableAttributes=None, queryableAttributeValues=None, lazyPropertyValues=None):
|
|---|
| 191 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 192 |
|
|---|
| 193 | # Initialize our properties.
|
|---|
| 194 |
|
|---|
| 195 | self._ParentCollection = parentCollection
|
|---|
| 196 | self._QueryableAttributes = None
|
|---|
| 197 |
|
|---|
| 198 | self._QueryableAttributeValues = {}
|
|---|
| 199 | if queryableAttributeValues is not None:
|
|---|
| 200 | self._QueryableAttributeValues.update(queryableAttributeValues)
|
|---|
| 201 |
|
|---|
| 202 | self._LazyPropertyValues = {}
|
|---|
| 203 | if lazyPropertyValues is not None:
|
|---|
| 204 | self._LazyPropertyValues.update(lazyPropertyValues)
|
|---|
| 205 |
|
|---|
| 206 | self._TempDirectories = None
|
|---|
| 207 |
|
|---|
| 208 | # If the caller wants to define queryable attributes, perform
|
|---|
| 209 | # additional validation.
|
|---|
| 210 |
|
|---|
| 211 | if queryableAttributes is not None:
|
|---|
| 212 |
|
|---|
| 213 | # Validate that the caller is not trying to define a
|
|---|
| 214 | # queryable attribute that has already been defined by our
|
|---|
| 215 | # chain of parent collections.
|
|---|
| 216 |
|
|---|
| 217 | for qa in queryableAttributes:
|
|---|
| 218 | if self.GetQueryableAttribute(qa.Name) is not None:
|
|---|
| 219 | raise ValueError(_(u'QueryableAttribute %(name)s has already been defined by a parent collection.') % {u'name': qa.Name})
|
|---|
| 220 |
|
|---|
| 221 | # Validate that there is no more than one queryable
|
|---|
| 222 | # attribute with data type DateTimeTypeMetadata among the
|
|---|
| 223 | # attributes we define and our chain of parent
|
|---|
| 224 | # collections.
|
|---|
| 225 |
|
|---|
| 226 | foundDateTime = False
|
|---|
| 227 |
|
|---|
| 228 | collection = parentCollection
|
|---|
| 229 | while collection is not None:
|
|---|
| 230 | if collection._QueryableAttributes is not None:
|
|---|
| 231 | for qa in collection._QueryableAttributes:
|
|---|
| 232 | if isinstance(qa.DataType, DateTimeTypeMetadata):
|
|---|
| 233 | foundDateTime = True
|
|---|
| 234 | break
|
|---|
| 235 | collection = collection.ParentCollection
|
|---|
| 236 |
|
|---|
| 237 | for qa in queryableAttributes:
|
|---|
| 238 | if isinstance(qa.DataType, DateTimeTypeMetadata):
|
|---|
| 239 | if foundDateTime:
|
|---|
| 240 | raise ValueError(_(u'Only one QueryableAttribute with data type DateTimeTypeMetadata may be defined for this object and its chain of parent collections.'))
|
|---|
| 241 | foundDateTime = True
|
|---|
| 242 |
|
|---|
| 243 | self._QueryableAttributes = queryableAttributes
|
|---|
| 244 |
|
|---|
| 245 | def __del__(self):
|
|---|
| 246 | self.Close()
|
|---|
| 247 |
|
|---|
| 248 | # Private methods that the derived class may override
|
|---|
| 249 |
|
|---|
| 250 | def _GetDisplayName(self):
|
|---|
| 251 | raise NotImplementedError(_(u'The _GetDisplayName method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 252 |
|
|---|
| 253 | def _GetLazyPropertyPhysicalValue(self, name):
|
|---|
| 254 | return None
|
|---|
| 255 |
|
|---|
| 256 | def _Close(self): # If you override, be sure to call the base class at the end of your implementation!
|
|---|
| 257 | if hasattr(self, '_TempDirectories') and self._TempDirectories is not None:
|
|---|
| 258 | while len(self._TempDirectories) > 0:
|
|---|
| 259 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Deleting temporary directory %(dir)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dir': self._Unicode(self._TempDirectories[0])})
|
|---|
| 260 | try:
|
|---|
| 261 | shutil.rmtree(self._TempDirectories[0], onerror=CollectibleObject._LogFailedRemoval)
|
|---|
| 262 | except:
|
|---|
| 263 | pass
|
|---|
| 264 | del self._TempDirectories[0]
|
|---|
| 265 |
|
|---|
| 266 | self._UnregisterForCloseAtExit()
|
|---|
| 267 |
|
|---|
| 268 | @classmethod
|
|---|
| 269 | def _TestCapability(cls, capability):
|
|---|
| 270 | if isinstance(cls, CollectibleObject):
|
|---|
| 271 | raise NotImplementedError(_(u'The _TestCapability method of class %s has not been implemented.') % cls.__class__.__name__)
|
|---|
| 272 | else:
|
|---|
| 273 | raise NotImplementedError(_(u'The _TestCapability method of class %s has not been implemented.') % cls.__name__)
|
|---|
| 274 |
|
|---|
| 275 | # Private properties and methods that the derived class may access
|
|---|
| 276 | # but generally does not override
|
|---|
| 277 |
|
|---|
| 278 | def _RegisterForCloseAtExit(self):
|
|---|
| 279 | if not hasattr(CollectibleObject, '_ObjectsToCloseAtExit'):
|
|---|
| 280 | CollectibleObject._ObjectsToCloseAtExit = []
|
|---|
| 281 |
|
|---|
| 282 | for r in CollectibleObject._ObjectsToCloseAtExit:
|
|---|
| 283 | if r() == self:
|
|---|
| 284 | return
|
|---|
| 285 |
|
|---|
| 286 | CollectibleObject._ObjectsToCloseAtExit.insert(0, weakref.ref(self))
|
|---|
| 287 |
|
|---|
| 288 | def _CreateTempDirectory(self):
|
|---|
| 289 | import tempfile
|
|---|
| 290 | tempDir = tempfile.mkdtemp(prefix='GeoEco_' + self.__class__.__name__ + '_Cache_')
|
|---|
| 291 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Created temporary directory %(dir)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dir': self._Unicode(tempDir)})
|
|---|
| 292 |
|
|---|
| 293 | if self._TempDirectories is None:
|
|---|
| 294 | self._TempDirectories = []
|
|---|
| 295 | self._TempDirectories.insert(0, tempDir)
|
|---|
| 296 |
|
|---|
| 297 | self._RegisterForCloseAtExit()
|
|---|
| 298 |
|
|---|
| 299 | return tempDir
|
|---|
| 300 |
|
|---|
| 301 | @classmethod
|
|---|
| 302 | def _RequireCapability(cls, capability):
|
|---|
| 303 | error = cls._TestCapability(capability.lower())
|
|---|
| 304 | if error is not None:
|
|---|
| 305 | raise error
|
|---|
| 306 |
|
|---|
| 307 | @classmethod
|
|---|
| 308 | def _ogr(cls):
|
|---|
| 309 | if not hasattr(CollectibleObject, '_OGRModule'):
|
|---|
| 310 | from GeoEco.Dependencies import ImportGDALModule
|
|---|
| 311 | ogr = ImportGDALModule('osgeo.ogr')
|
|---|
| 312 | ogr.UseExceptions()
|
|---|
| 313 | setattr(CollectibleObject, '_OGRModule', ogr)
|
|---|
| 314 |
|
|---|
| 315 | setattr(CollectibleObject, '_GeometryTypeForOGRGeometry', {ogr.wkbNone: None,
|
|---|
| 316 | ogr.wkbPoint: u'Point',
|
|---|
| 317 | ogr.wkbLineString: u'LineString',
|
|---|
| 318 | ogr.wkbPolygon: u'Polygon',
|
|---|
| 319 | ogr.wkbMultiPoint: u'MultiPoint',
|
|---|
| 320 | ogr.wkbMultiLineString: u'MultiLineString',
|
|---|
| 321 | ogr.wkbMultiPolygon: u'MultiPolygon',
|
|---|
| 322 | ogr.wkbGeometryCollection: u'GeometryCollection',
|
|---|
| 323 | ogr.wkbPoint25D: u'Point25D',
|
|---|
| 324 | ogr.wkbLineString25D: u'LineString25D',
|
|---|
| 325 | ogr.wkbPolygon25D: u'Polygon25D',
|
|---|
| 326 | ogr.wkbMultiPoint25D: u'MultiPoint25D',
|
|---|
| 327 | ogr.wkbMultiLineString25D: u'MultiLineString25D',
|
|---|
| 328 | ogr.wkbMultiPolygon25D: u'MultiPolygon25D',
|
|---|
| 329 | ogr.wkbGeometryCollection25D: u'GeometryCollection25D'})
|
|---|
| 330 |
|
|---|
| 331 | setattr(CollectibleObject, '_OGRGeometryForGeometryType', {None: ogr.wkbNone,
|
|---|
| 332 | u'Point': ogr.wkbPoint,
|
|---|
| 333 | u'LineString': ogr.wkbLineString,
|
|---|
| 334 | u'Polygon': ogr.wkbPolygon,
|
|---|
| 335 | u'MultiPoint': ogr.wkbMultiPoint,
|
|---|
| 336 | u'MultiLineString': ogr.wkbMultiLineString,
|
|---|
| 337 | u'MultiPolygon': ogr.wkbMultiPolygon,
|
|---|
| 338 | u'GeometryCollection': ogr.wkbGeometryCollection,
|
|---|
| 339 | u'Point25D': ogr.wkbPoint25D,
|
|---|
| 340 | u'LineString25D': ogr.wkbLineString25D,
|
|---|
| 341 | u'Polygon25D': ogr.wkbPolygon25D,
|
|---|
| 342 | u'MultiPoint25D': ogr.wkbMultiPoint25D,
|
|---|
| 343 | u'MultiLineString25D': ogr.wkbMultiLineString25D,
|
|---|
| 344 | u'MultiPolygon25D': ogr.wkbMultiPolygon25D,
|
|---|
| 345 | u'GeometryCollection25D': ogr.wkbGeometryCollection25D})
|
|---|
| 346 | return CollectibleObject._OGRModule
|
|---|
| 347 |
|
|---|
| 348 | @classmethod
|
|---|
| 349 | def _osr(cls):
|
|---|
| 350 | if not hasattr(CollectibleObject, '_OSRModule'):
|
|---|
| 351 | from GeoEco.Dependencies import ImportGDALModule
|
|---|
| 352 | osr = ImportGDALModule('osgeo.osr')
|
|---|
| 353 | osr.UseExceptions()
|
|---|
| 354 | setattr(CollectibleObject, '_OSRModule', osr)
|
|---|
| 355 | return CollectibleObject._OSRModule
|
|---|
| 356 |
|
|---|
| 357 | @classmethod
|
|---|
| 358 | def _gdal(cls):
|
|---|
| 359 | if not hasattr(CollectibleObject, '_GDALModule'):
|
|---|
| 360 | from GeoEco.Dependencies import ImportGDALModule
|
|---|
| 361 | gdal = ImportGDALModule('osgeo.gdal')
|
|---|
| 362 | gdal.UseExceptions()
|
|---|
| 363 | setattr(CollectibleObject, '_GDALModule', gdal)
|
|---|
| 364 | return CollectibleObject._GDALModule
|
|---|
| 365 |
|
|---|
| 366 | @classmethod
|
|---|
| 367 | def _gdalconst(cls):
|
|---|
| 368 | if not hasattr(CollectibleObject, '_GDALConstModule'):
|
|---|
| 369 | from GeoEco.Dependencies import ImportGDALModule
|
|---|
| 370 | gdalconst = ImportGDALModule('osgeo.gdalconst')
|
|---|
| 371 | setattr(CollectibleObject, '_GDALConstModule', gdalconst)
|
|---|
| 372 | return CollectibleObject._GDALConstModule
|
|---|
| 373 |
|
|---|
| 374 | @classmethod
|
|---|
| 375 | def _Str(cls, s):
|
|---|
| 376 | if isinstance(s, str):
|
|---|
| 377 | return s
|
|---|
| 378 | if not hasattr(CollectibleObject, '_Encoder'):
|
|---|
| 379 | setattr(CollectibleObject, '_Encoder', codecs.getencoder(locale.getpreferredencoding()))
|
|---|
| 380 | if isinstance(s, unicode):
|
|---|
| 381 | return CollectibleObject._Encoder(s)[0]
|
|---|
| 382 | return CollectibleObject._Encoder(str(s))[0]
|
|---|
| 383 |
|
|---|
| 384 | @classmethod
|
|---|
| 385 | def _Unicode(cls, s):
|
|---|
| 386 | if isinstance(s, unicode):
|
|---|
| 387 | return s
|
|---|
| 388 | if not hasattr(CollectibleObject, '_Decoder'):
|
|---|
| 389 | setattr(CollectibleObject, '_Decoder', codecs.getdecoder(locale.getpreferredencoding()))
|
|---|
| 390 | return CollectibleObject._Decoder(str(s))[0]
|
|---|
| 391 |
|
|---|
| 392 | _LoggingChannel = u'GeoEco.Datasets'
|
|---|
| 393 |
|
|---|
| 394 | @classmethod
|
|---|
| 395 | def _GetLogger(cls):
|
|---|
| 396 | try:
|
|---|
| 397 | return logging.getLogger(CollectibleObject._LoggingChannel)
|
|---|
| 398 | except:
|
|---|
| 399 | return None
|
|---|
| 400 |
|
|---|
| 401 | @classmethod
|
|---|
| 402 | def _LogDebug(cls, format, *args, **kwargs):
|
|---|
| 403 | try:
|
|---|
| 404 | logging.getLogger(CollectibleObject._LoggingChannel).debug(format, *args, **kwargs)
|
|---|
| 405 | except:
|
|---|
| 406 | pass
|
|---|
| 407 |
|
|---|
| 408 | @classmethod
|
|---|
| 409 | def _LogInfo(cls, format, *args, **kwargs):
|
|---|
| 410 | try:
|
|---|
| 411 | logging.getLogger(CollectibleObject._LoggingChannel).info(format, *args, **kwargs)
|
|---|
| 412 | except:
|
|---|
| 413 | pass
|
|---|
| 414 |
|
|---|
| 415 | @classmethod
|
|---|
| 416 | def _LogWarning(cls, format, *args, **kwargs):
|
|---|
| 417 | try:
|
|---|
| 418 | logging.getLogger(CollectibleObject._LoggingChannel).warning(format, *args, **kwargs)
|
|---|
| 419 | except:
|
|---|
| 420 | pass
|
|---|
| 421 |
|
|---|
| 422 | @classmethod
|
|---|
| 423 | def _LogError(cls, format, *args, **kwargs):
|
|---|
| 424 | try:
|
|---|
| 425 | logging.getLogger(CollectibleObject._LoggingChannel).error(format, *args, **kwargs)
|
|---|
| 426 | except:
|
|---|
| 427 | pass
|
|---|
| 428 |
|
|---|
| 429 | @classmethod
|
|---|
| 430 | def _DebugLoggingEnabled(cls):
|
|---|
| 431 | return logging.getLogger(u'GeoEco.Datasets').isEnabledFor(logging.DEBUG)
|
|---|
| 432 |
|
|---|
| 433 | # Private methods that the derived class should not use
|
|---|
| 434 |
|
|---|
| 435 | def _UnregisterForCloseAtExit(self):
|
|---|
| 436 | if hasattr(CollectibleObject, '_ObjectsToCloseAtExit'):
|
|---|
| 437 | for i, r in enumerate(CollectibleObject._ObjectsToCloseAtExit):
|
|---|
| 438 | if r() == self:
|
|---|
| 439 | del CollectibleObject._ObjectsToCloseAtExit[i]
|
|---|
| 440 | return
|
|---|
| 441 |
|
|---|
| 442 | @staticmethod
|
|---|
| 443 | def _CloseObjectsAtExit():
|
|---|
| 444 | if hasattr(CollectibleObject, '_ObjectsToCloseAtExit'):
|
|---|
| 445 | while len(CollectibleObject._ObjectsToCloseAtExit) > 0:
|
|---|
| 446 | if CollectibleObject._ObjectsToCloseAtExit[0]() is None: # Should never happen because CollectibleObject.__del__() removes the object from the list
|
|---|
| 447 | del CollectibleObject._ObjectsToCloseAtExit[0]
|
|---|
| 448 | else:
|
|---|
| 449 | CollectibleObject._ObjectsToCloseAtExit[0]()._Close() # This will remove it from the list.
|
|---|
| 450 |
|
|---|
| 451 | @staticmethod
|
|---|
| 452 | def _LogFailedRemoval(function, path, excinfo):
|
|---|
| 453 | try:
|
|---|
| 454 | logger = logging.getLogger(u'GeoEco.Datasets')
|
|---|
| 455 | _unicode = codecs.getdecoder(locale.getpreferredencoding())
|
|---|
| 456 | if function == os.remove:
|
|---|
| 457 | logger.warning(_(u'Could not delete temporary file %(path)s due to %(error)s: %(msg)s') % {u'path' : _unicode(path)[0], u'error' : excinfo[0].__name__, u'msg' : _unicode(str(excinfo[1]))[0]})
|
|---|
| 458 | elif function == os.rmdir:
|
|---|
| 459 | logger.warning(_(u'Could not delete temporary directory %(path)s due to %(error)s: %(msg)s') % {u'path' : _unicode(path)[0], u'error' : excinfo[0].__name__, u'msg' : _unicode(str(excinfo[1]))[0]})
|
|---|
| 460 | else:
|
|---|
| 461 | logger.warning(_(u'Could not delete temporary directory %(path)s. The directory contents could not be listed due to %(error)s: %(msg)s') % {u'path' : _unicode(path)[0], u'error' : excinfo[0].__name__, u'msg' : _unicode(str(excinfo[1]))[0]})
|
|---|
| 462 | except:
|
|---|
| 463 | pass
|
|---|
| 464 |
|
|---|
| 465 | atexit.register(CollectibleObject._CloseObjectsAtExit)
|
|---|
| 466 |
|
|---|
| 467 |
|
|---|
| 468 | class QueryableAttribute(object):
|
|---|
| 469 | __doc__ = DynamicDocString()
|
|---|
| 470 |
|
|---|
| 471 | def _GetName(self):
|
|---|
| 472 | return self._Name
|
|---|
| 473 |
|
|---|
| 474 | Name = property(_GetName, doc=DynamicDocString())
|
|---|
| 475 |
|
|---|
| 476 | def _GetDisplayName(self):
|
|---|
| 477 | return self._DisplayName
|
|---|
| 478 |
|
|---|
| 479 | DisplayName = property(_GetDisplayName, doc=DynamicDocString())
|
|---|
| 480 |
|
|---|
| 481 | def _GetDataType(self):
|
|---|
| 482 | return self._DataType
|
|---|
| 483 |
|
|---|
| 484 | DataType = property(_GetDataType, doc=DynamicDocString())
|
|---|
| 485 |
|
|---|
| 486 | def _GetDerivedLazyDatasetProps(self):
|
|---|
| 487 | return self._DerivedLazyDatasetProps
|
|---|
| 488 |
|
|---|
| 489 | DerivedLazyDatasetProps = property(_GetDerivedLazyDatasetProps, doc=DynamicDocString())
|
|---|
| 490 |
|
|---|
| 491 | def _GetDerivedFromAttr(self):
|
|---|
| 492 | return self._DerivedFromAttr
|
|---|
| 493 |
|
|---|
| 494 | DerivedFromAttr = property(_GetDerivedFromAttr, doc=DynamicDocString())
|
|---|
| 495 |
|
|---|
| 496 | def _GetDerivedValueMap(self):
|
|---|
| 497 | return self._DerivedValueMap
|
|---|
| 498 |
|
|---|
| 499 | DerivedValueMap = property(_GetDerivedValueMap, doc=DynamicDocString())
|
|---|
| 500 |
|
|---|
| 501 | def _GetDerivedValueFunc(self):
|
|---|
| 502 | return self._DerivedValueFunc
|
|---|
| 503 |
|
|---|
| 504 | DerivedValueFunc = property(_GetDerivedValueFunc, doc=DynamicDocString())
|
|---|
| 505 |
|
|---|
| 506 | def __init__(self, name, displayName, dataType, derivedLazyDatasetProps=None, derivedFromAttr=None, derivedValueMap=None, derivedValueFunc=None):
|
|---|
| 507 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 508 |
|
|---|
| 509 | if not isinstance(dataType, (UnicodeStringTypeMetadata, IntegerTypeMetadata, FloatTypeMetadata, DateTimeTypeMetadata)):
|
|---|
| 510 | raise TypeError(_(u'%(type)s is not an allowed data type for queryable attributes. Queryable attributes may only have the following data types: UnicodeStringTypeMetadata, IntegerTypeMetadata, FloatTypeMetadata, DateTimeTypeMetadata.') % {u'type': dataType.__class__.__name__})
|
|---|
| 511 |
|
|---|
| 512 | if derivedFromAttr is not None and (derivedValueMap is None and derivedValueFunc is None or derivedValueMap is not None and derivedValueFunc is not None):
|
|---|
| 513 | raise TypeError(_(u'If the derivedFromAttr parameter is not None, a value must be provided for either derivedValueMap or derivedValueFunc, but not for both.'))
|
|---|
| 514 |
|
|---|
| 515 | if not isinstance(derivedValueFunc, (types.NoneType, types.FunctionType, types.MethodType)):
|
|---|
| 516 | raise TypeError(_(u'The type of the derivedValueFunc parameter (%(type)s) is not an allowed type. It must be a function, a method, or None.') % {u'type': str(type(derivedValueFunc))})
|
|---|
| 517 |
|
|---|
| 518 | self._Name = name
|
|---|
| 519 | self._DisplayName = displayName
|
|---|
| 520 | self._DataType = dataType
|
|---|
| 521 | self._DerivedLazyDatasetProps = derivedLazyDatasetProps
|
|---|
| 522 | self._DerivedFromAttr = derivedFromAttr
|
|---|
| 523 | self._DerivedValueMap = derivedValueMap
|
|---|
| 524 | self._DerivedValueFunc = derivedValueFunc
|
|---|
| 525 |
|
|---|
| 526 |
|
|---|
| 527 | class Dataset(CollectibleObject):
|
|---|
| 528 | __doc__ = DynamicDocString()
|
|---|
| 529 |
|
|---|
| 530 | # Public properties and methods
|
|---|
| 531 |
|
|---|
| 532 | def GetSpatialReference(self, srType):
|
|---|
| 533 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 534 |
|
|---|
| 535 | srRef = self.GetLazyPropertyValue('SpatialReference')
|
|---|
| 536 |
|
|---|
| 537 | if srRef is None:
|
|---|
| 538 | if srType == 'arcgis':
|
|---|
| 539 | return u'{B286C06B-0879-11D2-AACA-00C04FA33C20}' # This is ESRI's GUID for the "Unknown" coordinate system
|
|---|
| 540 | return None
|
|---|
| 541 |
|
|---|
| 542 | if srType == 'obj':
|
|---|
| 543 | return srRef
|
|---|
| 544 |
|
|---|
| 545 | if srType == 'wkt':
|
|---|
| 546 | s = srRef.ExportToWkt()
|
|---|
| 547 | if isinstance(s, basestring) and len(s) > 0:
|
|---|
| 548 | s = self._Unicode(s)
|
|---|
| 549 | return s
|
|---|
| 550 |
|
|---|
| 551 | if srType == 'proj4':
|
|---|
| 552 | s = srRef.ExportToProj4()
|
|---|
| 553 | if isinstance(s, basestring) and len(s) > 0:
|
|---|
| 554 | s = self._Unicode(s)
|
|---|
| 555 | return s
|
|---|
| 556 |
|
|---|
| 557 | if srType == 'arcgis':
|
|---|
| 558 | s = srRef.ExportToWkt()
|
|---|
| 559 | if isinstance(s, basestring) and len(s) > 0:
|
|---|
| 560 | sr = self._osr().SpatialReference(s) # TODO: Need to explicitly destroy temporary sr allocated here?
|
|---|
| 561 | sr.MorphToESRI()
|
|---|
| 562 | s = sr.ExportToWkt()
|
|---|
| 563 | if isinstance(s, basestring) and len(s) > 0:
|
|---|
| 564 | s = self._Unicode(s)
|
|---|
| 565 | return s
|
|---|
| 566 |
|
|---|
| 567 | raise ValueError(_(u'"%(srType)s" is an invalid value for the srType parameter.') % {u'srType': srType})
|
|---|
| 568 |
|
|---|
| 569 | def SetSpatialReference(self, srType, sr):
|
|---|
| 570 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 571 |
|
|---|
| 572 | # Verify that we have the required capabilities.
|
|---|
| 573 |
|
|---|
| 574 | self._RequireCapability('SetSpatialReference')
|
|---|
| 575 |
|
|---|
| 576 | # Convert the caller's spatial reference to the type required
|
|---|
| 577 | # by the derived class and call the derived class to set it.
|
|---|
| 578 |
|
|---|
| 579 | if srType != 'obj' and not isinstance(sr, (types.NoneType, basestring)):
|
|---|
| 580 | raise TypeError(_(u'If the srType parameter is \'%(srType)s\', the sr parameter must be a string or None.') % {u'srType': srType})
|
|---|
| 581 |
|
|---|
| 582 | if sr is None or srType != 'obj' and len(sr.strip()) <= 0 or srType == 'arcgis' and sr.upper() == '{B286C06B-0879-11D2-AACA-00C04FA33C20}': # This is ESRI's GUID for the "Unknown" coordinate system
|
|---|
| 583 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Setting SpatialReference to None.'), {u'class': self.__class__.__name__, u'id': id(self)})
|
|---|
| 584 | elif srType == 'obj':
|
|---|
| 585 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Setting SpatialReference from OSR SpatialReference object 0x%(id2)08X that has WKT \'%(srString)s\'.'), {u'class': self.__class__.__name__, u'id': id(self), u'id2': id(sr), u'srString': self._Unicode(sr.ExportToWkt())})
|
|---|
| 586 | elif srType == 'wkt':
|
|---|
| 587 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Setting SpatialReference from WKT \'%(srString)s\'.'), {u'class': self.__class__.__name__, u'id': id(self), u'srString': self._Unicode(sr)})
|
|---|
| 588 | elif srType == 'proj4':
|
|---|
| 589 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Setting SpatialReference from Proj4 string "%(srString)s".'), {u'class': self.__class__.__name__, u'id': id(self), u'srString': self._Unicode(sr)})
|
|---|
| 590 | elif srType == 'arcgis':
|
|---|
| 591 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Setting SpatialReference from ArcGIS WKT \'%(srString)s\'.'), {u'class': self.__class__.__name__, u'id': id(self), u'srString': self._Unicode(sr)})
|
|---|
| 592 | else:
|
|---|
| 593 | raise ValueError(_(u'"%(srType)s" is an invalid value for the srType parameter.') % {u'srType': srType})
|
|---|
| 594 |
|
|---|
| 595 | try:
|
|---|
| 596 | self._SetSpatialReference(self.ConvertSpatialReference(srType, sr, self._GetSRTypeForSetting()))
|
|---|
| 597 | except Exception, e:
|
|---|
| 598 | raise RuntimeError(_(u'Failed to set the spatial reference of %(dn)s due to %(e)s: %(msg)s') % {u'dn': self.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 599 |
|
|---|
| 600 | # Set our SpatialReference property to a new OSR
|
|---|
| 601 | # SpatialReference.
|
|---|
| 602 |
|
|---|
| 603 | self.SetLazyPropertyValue('SpatialReference', self.ConvertSpatialReference(srType, sr, 'obj'))
|
|---|
| 604 |
|
|---|
| 605 | @classmethod
|
|---|
| 606 | def ConvertSpatialReference(cls, srType, sr, outputSRType):
|
|---|
| 607 | cls.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 608 |
|
|---|
| 609 | if srType != 'obj' and not isinstance(sr, (types.NoneType, basestring)):
|
|---|
| 610 | raise TypeError(_(u'If the srType parameter is \'%(srType)s\', the sr parameter must be a string or None.') % {u'srType': srType})
|
|---|
| 611 |
|
|---|
| 612 | if outputSRType != 'obj' and outputSRType == srType:
|
|---|
| 613 | return sr
|
|---|
| 614 |
|
|---|
| 615 | # Create a SpatialReference object
|
|---|
| 616 |
|
|---|
| 617 | if sr is None or srType != 'obj' and len(sr.strip()) <= 0 or srType == 'arcgis' and sr.upper() == '{B286C06B-0879-11D2-AACA-00C04FA33C20}': # This is ESRI's GUID for the "Unknown" coordinate system
|
|---|
| 618 | return None
|
|---|
| 619 |
|
|---|
| 620 | elif srType == 'obj':
|
|---|
| 621 | srObj = cls._osr().SpatialReference(sr.ExportToWkt())
|
|---|
| 622 |
|
|---|
| 623 | elif srType == 'wkt':
|
|---|
| 624 | srObj = cls._osr().SpatialReference(cls._Str(sr))
|
|---|
| 625 |
|
|---|
| 626 | elif srType == 'proj4':
|
|---|
| 627 | srObj = cls._osr().SpatialReference()
|
|---|
| 628 | srObj.ImportFromProj4(cls._Str(sr))
|
|---|
| 629 |
|
|---|
| 630 | elif srType == 'arcgis':
|
|---|
| 631 | sr = re.sub("\\[\\'[^\\']*\\'", Dataset._FixESRIQuotes, sr) # Convert ArcGIS's single quotes around WKT <name> tokens to double quotes, to conform to proper WKT syntax
|
|---|
| 632 | srObj = cls._osr().SpatialReference(cls._Str(sr))
|
|---|
| 633 | srObj.MorphFromESRI()
|
|---|
| 634 |
|
|---|
| 635 | else:
|
|---|
| 636 | raise ValueError(_(u'"%(srType)s" is an invalid value for the srType parameter.') % {u'srType': srType})
|
|---|
| 637 |
|
|---|
| 638 | # Return the appropriate string or the SpatialReference
|
|---|
| 639 | # object.
|
|---|
| 640 |
|
|---|
| 641 | if outputSRType == 'obj':
|
|---|
| 642 | return srObj
|
|---|
| 643 |
|
|---|
| 644 | if outputSRType == 'wkt':
|
|---|
| 645 | return cls._Unicode(srObj.ExportToWkt())
|
|---|
| 646 |
|
|---|
| 647 | if outputSRType == 'proj4':
|
|---|
| 648 | return cls._Unicode(srObj.ExportToProj4())
|
|---|
| 649 |
|
|---|
| 650 | srObj.MorphToESRI()
|
|---|
| 651 | return cls._Unicode(srObj.ExportToWkt())
|
|---|
| 652 |
|
|---|
| 653 | # Private properties and methods that the derived class may access
|
|---|
| 654 | # but generally does not override
|
|---|
| 655 |
|
|---|
| 656 | @staticmethod
|
|---|
| 657 | def _FixESRIQuotes(matchobj):
|
|---|
| 658 | return '["' + matchobj.group(0)[2:-1] + '"'
|
|---|
| 659 |
|
|---|
| 660 | # Private methods that the derived class is expected to override
|
|---|
| 661 |
|
|---|
| 662 | @classmethod
|
|---|
| 663 | def _GetSRTypeForSetting(cls):
|
|---|
| 664 | if isinstance(cls, Dataset):
|
|---|
| 665 | raise NotImplementedError(_(u'The _GetSRTypeForSetting method of class %s has not been implemented.') % cls.__class__.__name__)
|
|---|
| 666 | else:
|
|---|
| 667 | raise NotImplementedError(_(u'The _GetSRTypeForSetting method of class %s has not been implemented.') % cls.__name__)
|
|---|
| 668 |
|
|---|
| 669 | def _SetSpatialReference(self, sr):
|
|---|
| 670 | raise NotImplementedError(_(u'The _SetSpatialReference method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 671 |
|
|---|
| 672 |
|
|---|
| 673 | class DatasetCollection(CollectibleObject):
|
|---|
| 674 | __doc__ = DynamicDocString()
|
|---|
| 675 |
|
|---|
| 676 | def _GetCacheDirectory(self):
|
|---|
| 677 | return self._CacheDirectory
|
|---|
| 678 |
|
|---|
| 679 | def _SetCacheDirectory(self, value):
|
|---|
| 680 | self.__doc__.Obj.ValidatePropertyAssignment()
|
|---|
| 681 | self._CacheDirectory = value
|
|---|
| 682 |
|
|---|
| 683 | CacheDirectory = property(_GetCacheDirectory, _SetCacheDirectory, doc=DynamicDocString())
|
|---|
| 684 |
|
|---|
| 685 | def QueryDatasets(self, expression=None, reportProgress=True, **options):
|
|---|
| 686 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 687 |
|
|---|
| 688 | # Parse the query.
|
|---|
| 689 |
|
|---|
| 690 | parsedExpression, parentAttrValues = self._PrepareQuery(expression)
|
|---|
| 691 |
|
|---|
| 692 | # Log a message and start a progress reporter, if requested.
|
|---|
| 693 |
|
|---|
| 694 | if parsedExpression is not None:
|
|---|
| 695 | if reportProgress:
|
|---|
| 696 | self._LogInfo(_(u'Querying %(dn)s for datasets matching the expression "%(expr)s".'), {u'dn': self.DisplayName, u'expr': expression})
|
|---|
| 697 | else:
|
|---|
| 698 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Executing query for datasets matching expression: "%(expr)s"'), {u'class': self.__class__.__name__, u'id': id(self), u'expr': expression})
|
|---|
| 699 | else:
|
|---|
| 700 | if reportProgress:
|
|---|
| 701 | self._LogInfo(_(u'Querying %(dn)s.'), {u'dn': self.DisplayName})
|
|---|
| 702 | else:
|
|---|
| 703 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Executing query for all datasets.'), {u'class': self.__class__.__name__, u'id': id(self)})
|
|---|
| 704 |
|
|---|
| 705 | if reportProgress:
|
|---|
| 706 | progressReporter = ProgressReporter(progressMessage2=_(u'Query in progress: %(elapsed)s elapsed, %(opsCompleted)i datasets found so far, %(perOp)s per dataset.'),
|
|---|
| 707 | completionMessage=_(u'Query complete: %(elapsed)s elapsed, %(opsCompleted)i datasets found, %(perOp)s per dataset.'),
|
|---|
| 708 | loggingChannel=DatasetCollection._LoggingChannel)
|
|---|
| 709 | progressReporter.Start()
|
|---|
| 710 | else:
|
|---|
| 711 | progressReporter = None
|
|---|
| 712 |
|
|---|
| 713 | # Execute the query.
|
|---|
| 714 |
|
|---|
| 715 | try:
|
|---|
| 716 | datasets = self._QueryDatasets(parsedExpression, progressReporter, options, parentAttrValues)
|
|---|
| 717 | finally:
|
|---|
| 718 | if reportProgress:
|
|---|
| 719 | progressReporter.Stop()
|
|---|
| 720 |
|
|---|
| 721 | if not reportProgress:
|
|---|
| 722 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Query complete. Returning %(i)i datasets.'), {u'class': self.__class__.__name__, u'id': id(self), u'i': len(datasets)})
|
|---|
| 723 |
|
|---|
| 724 | # Return successfully.
|
|---|
| 725 |
|
|---|
| 726 | return datasets
|
|---|
| 727 |
|
|---|
| 728 | def GetOldestDataset(self, expression=None, **options):
|
|---|
| 729 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 730 |
|
|---|
| 731 | # Validate that the collection has a queryable attribute with
|
|---|
| 732 | # data type DateTimeTypeMetadata.
|
|---|
| 733 |
|
|---|
| 734 | from GeoEco.Types import DateTimeTypeMetadata
|
|---|
| 735 |
|
|---|
| 736 | attrs = self.GetQueryableAttributesWithDataType(DateTimeTypeMetadata)
|
|---|
| 737 | if len(attrs) <= 0:
|
|---|
| 738 | raise ValueError(_(u'This dataset collection does not have a queryable attribute defined with the data type DateTimeTypeMetadata. In order to retrieve the oldest dataset, a queryable attribute of that type must be defined.'))
|
|---|
| 739 | if len(attrs) > 1: # Should never happen; CollectibleObject.__init__ prevents it
|
|---|
| 740 | raise ValueError(_(u'This dataset collection has multiple queryable attributes defined with the data type DateTimeTypeMetadata. In order to retrieve the oldest dataset, only one queryable attribute of that type must be defined.'))
|
|---|
| 741 |
|
|---|
| 742 | dateTimeAttrName = attrs[0].Name
|
|---|
| 743 |
|
|---|
| 744 | # Get the dataset.
|
|---|
| 745 |
|
|---|
| 746 | parsedExpression, parentAttrValues = self._PrepareQuery(expression)
|
|---|
| 747 |
|
|---|
| 748 | if parsedExpression is not None:
|
|---|
| 749 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Getting the oldest dataset matching expression: "%(expr)s"'), {u'class': self.__class__.__name__, u'id': id(self), u'expr': expression})
|
|---|
| 750 | else:
|
|---|
| 751 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Getting the oldest dataset.'), {u'class': self.__class__.__name__, u'id': id(self)})
|
|---|
| 752 |
|
|---|
| 753 | dataset = self._GetOldestDataset(parsedExpression, options, parentAttrValues, dateTimeAttrName)
|
|---|
| 754 |
|
|---|
| 755 | if dataset is not None:
|
|---|
| 756 | self._LogDebug(_(u'%(class)s 0x%(id)08X: The oldest dataset is dated %(dt)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dt': dataset.GetQueryableAttributeValue(dateTimeAttrName).strftime('%Y-%m-%d %H:%M:%S')})
|
|---|
| 757 | elif parsedExpression is not None:
|
|---|
| 758 | self._LogDebug(_(u'%(class)s 0x%(id)08X: No datasets were found in this collection that match expression: "%(expr)s"'), {u'class': self.__class__.__name__, u'id': id(self), u'expr': expression})
|
|---|
| 759 | else:
|
|---|
| 760 | self._LogDebug(_(u'%(class)s 0x%(id)08X: No datasets were found in this collection.'), {u'class': self.__class__.__name__, u'id': id(self)})
|
|---|
| 761 |
|
|---|
| 762 | return dataset
|
|---|
| 763 |
|
|---|
| 764 | def GetNewestDataset(self, expression=None, **options):
|
|---|
| 765 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 766 |
|
|---|
| 767 | # Validate that the collection has a queryable attribute with
|
|---|
| 768 | # data type DateTimeTypeMetadata.
|
|---|
| 769 |
|
|---|
| 770 | from GeoEco.Types import DateTimeTypeMetadata
|
|---|
| 771 |
|
|---|
| 772 | attrs = self.GetQueryableAttributesWithDataType(DateTimeTypeMetadata)
|
|---|
| 773 | if len(attrs) <= 0:
|
|---|
| 774 | raise ValueError(_(u'This dataset collection does not have a queryable attribute defined with the data type DateTimeTypeMetadata. In order to retrieve the newest dataset, a queryable attribute of that type must be defined.'))
|
|---|
| 775 | if len(attrs) > 1: # Should never happen; CollectibleObject.__init__ prevents it
|
|---|
| 776 | raise ValueError(_(u'This dataset collection has multiple queryable attributes defined with the data type DateTimeTypeMetadata. In order to retrieve the newest dataset, only one queryable attribute of that type must be defined.'))
|
|---|
| 777 |
|
|---|
| 778 | dateTimeAttrName = attrs[0].Name
|
|---|
| 779 |
|
|---|
| 780 | # Get the dataset.
|
|---|
| 781 |
|
|---|
| 782 | parsedExpression, parentAttrValues = self._PrepareQuery(expression)
|
|---|
| 783 |
|
|---|
| 784 | if parsedExpression is not None:
|
|---|
| 785 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Getting the newest dataset matching expression: "%(expr)s"'), {u'class': self.__class__.__name__, u'id': id(self), u'expr': expression})
|
|---|
| 786 | else:
|
|---|
| 787 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Getting the newest dataset.'), {u'class': self.__class__.__name__, u'id': id(self)})
|
|---|
| 788 |
|
|---|
| 789 | dataset = self._GetNewestDataset(parsedExpression, options, parentAttrValues, dateTimeAttrName)
|
|---|
| 790 |
|
|---|
| 791 | if dataset is not None:
|
|---|
| 792 | self._LogDebug(_(u'%(class)s 0x%(id)08X: The newest dataset is dated %(dt)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dt': dataset.GetQueryableAttributeValue(dateTimeAttrName).strftime('%Y-%m-%d %H:%M:%S')})
|
|---|
| 793 | elif parsedExpression is not None:
|
|---|
| 794 | self._LogDebug(_(u'%(class)s 0x%(id)08X: No datasets were found in this collection that match expression: "%(expr)s"'), {u'class': self.__class__.__name__, u'id': id(self), u'expr': expression})
|
|---|
| 795 | else:
|
|---|
| 796 | self._LogDebug(_(u'%(class)s 0x%(id)08X: No datasets were found in this collection.'), {u'class': self.__class__.__name__, u'id': id(self)})
|
|---|
| 797 |
|
|---|
| 798 | return dataset
|
|---|
| 799 |
|
|---|
| 800 | def ImportDatasets(self, datasets, mode=u'Add', reportProgress=True, **options):
|
|---|
| 801 | # TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 802 |
|
|---|
| 803 | # TODO: Test capabilities
|
|---|
| 804 |
|
|---|
| 805 | # If the caller provided an empty list, return now.
|
|---|
| 806 |
|
|---|
| 807 | if len(datasets) <= 0:
|
|---|
| 808 | if reportProgress:
|
|---|
| 809 | self._LogInfo(_(u'There are no datasets to import.'))
|
|---|
| 810 | return
|
|---|
| 811 |
|
|---|
| 812 | # Call the derived class to import the datasets.
|
|---|
| 813 |
|
|---|
| 814 | try:
|
|---|
| 815 | self._ImportDatasets(datasets, mode.lower(), reportProgress, options)
|
|---|
| 816 |
|
|---|
| 817 | # Ensure all of the datasets are closed. The derived class
|
|---|
| 818 | # should be closing them as it goes along, but we do it here
|
|---|
| 819 | # as an additional convenince to the derived class.
|
|---|
| 820 |
|
|---|
| 821 | finally:
|
|---|
| 822 | for dataset in datasets:
|
|---|
| 823 | dataset.Close()
|
|---|
| 824 |
|
|---|
| 825 | def __init__(self, parentCollection=None, queryableAttributes=None, queryableAttributeValues=None, lazyPropertyValues=None, cacheDirectory=None):
|
|---|
| 826 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 827 | super(DatasetCollection, self).__init__(parentCollection, queryableAttributes, queryableAttributeValues, lazyPropertyValues)
|
|---|
| 828 | self._CacheDirectory = cacheDirectory
|
|---|
| 829 |
|
|---|
| 830 | @classmethod
|
|---|
| 831 | def _GetQueryExpressionParser(cls):
|
|---|
| 832 |
|
|---|
| 833 | # If we have not built the parser yet, build it using the
|
|---|
| 834 | # pyparsing module.
|
|---|
| 835 |
|
|---|
| 836 | if not hasattr(DatasetCollection, '_QueryExpressionParser'):
|
|---|
| 837 |
|
|---|
| 838 | # Define helper classes and functions used to evaluate the
|
|---|
| 839 | # parsed expression.
|
|---|
| 840 | #
|
|---|
| 841 | # Many thanks to Paul McGuire for pyparsing examples that
|
|---|
| 842 | # inspired this code, particularly eval_arith.py.
|
|---|
| 843 |
|
|---|
| 844 | class _EvalLiteral(object):
|
|---|
| 845 | def __init__(self, tokens):
|
|---|
| 846 | self.value = tokens[0]
|
|---|
| 847 |
|
|---|
| 848 | def eval(self, valuesDict=None):
|
|---|
| 849 | if self.value[0] in '0123456789.':
|
|---|
| 850 | if '.' in self.value or 'e' in self.value.lower():
|
|---|
| 851 | return float(self.value)
|
|---|
| 852 | return int(self.value)
|
|---|
| 853 |
|
|---|
| 854 | if self.value[0] == '"':
|
|---|
| 855 | return self.value[1:-1].replace('""', '"')
|
|---|
| 856 |
|
|---|
| 857 | if self.value[0] == "'":
|
|---|
| 858 | return self.value[1:-1].replace("''", "'")
|
|---|
| 859 |
|
|---|
| 860 | if self.value[0] == '#':
|
|---|
| 861 | if len(self.value) == 21:
|
|---|
| 862 | return datetime.datetime(int(self.value[1:5]), int(self.value[6:8]), int(self.value[9:11]), int(self.value[12:14]), int(self.value[15:17]), int(self.value[18:20])) # The form of #YYYY-mm-dd HH:MM:SS#
|
|---|
| 863 | return datetime.datetime(int(self.value[1:5]), int(self.value[6:8]), int(self.value[9:11])) # The form of #YYYY-mm-dd#
|
|---|
| 864 |
|
|---|
| 865 | if self.value.lower() in ['false', 'true']:
|
|---|
| 866 | return self.value[0] in ['t', 'T']
|
|---|
| 867 |
|
|---|
| 868 | raise ValueError(_(u'The token %(token)s cannot be parsed as a literal value.') % {u'token': token[0]})
|
|---|
| 869 |
|
|---|
| 870 | class _EvalVariable(object):
|
|---|
| 871 | def __init__(self, tokens):
|
|---|
| 872 | self.variable = tokens[0]
|
|---|
| 873 |
|
|---|
| 874 | def eval(self, valuesDict=None):
|
|---|
| 875 | if valuesDict is not None and self.variable in valuesDict:
|
|---|
| 876 | return valuesDict[self.variable]
|
|---|
| 877 | return None
|
|---|
| 878 |
|
|---|
| 879 | class _EvalSignOp(object):
|
|---|
| 880 | def __init__(self, tokens):
|
|---|
| 881 | self.sign, self.value = tokens[0]
|
|---|
| 882 |
|
|---|
| 883 | def eval(self, valuesDict=None):
|
|---|
| 884 | val = self.value.eval(valuesDict)
|
|---|
| 885 | if val is None:
|
|---|
| 886 | return None
|
|---|
| 887 | if self.sign == '-':
|
|---|
| 888 | return -1 * val
|
|---|
| 889 | return val
|
|---|
| 890 |
|
|---|
| 891 | def _OperatorOperands(tokenlist):
|
|---|
| 892 | it = iter(tokenlist)
|
|---|
| 893 | while 1:
|
|---|
| 894 | try:
|
|---|
| 895 | yield (it.next(), it.next())
|
|---|
| 896 | except StopIteration:
|
|---|
| 897 | break
|
|---|
| 898 |
|
|---|
| 899 | class _EvalMultOp(object):
|
|---|
| 900 | def __init__(self, tokens):
|
|---|
| 901 | self.value = tokens[0]
|
|---|
| 902 |
|
|---|
| 903 | def eval(self, valuesDict=None):
|
|---|
| 904 | prod = self.value[0].eval(valuesDict)
|
|---|
| 905 | if prod is None:
|
|---|
| 906 | return None
|
|---|
| 907 | for op, val in _OperatorOperands(self.value[1:]):
|
|---|
| 908 | val = val.eval(valuesDict)
|
|---|
| 909 | if val is None:
|
|---|
| 910 | return None
|
|---|
| 911 | elif op == '*':
|
|---|
| 912 | prod *= val
|
|---|
| 913 | elif op == '/':
|
|---|
| 914 | prod /= val
|
|---|
| 915 | return prod
|
|---|
| 916 |
|
|---|
| 917 | class _EvalAddOp(object):
|
|---|
| 918 | def __init__(self, tokens):
|
|---|
| 919 | self.value = tokens[0]
|
|---|
| 920 |
|
|---|
| 921 | def eval(self, valuesDict=None):
|
|---|
| 922 | sum = self.value[0].eval(valuesDict)
|
|---|
| 923 | if sum is None:
|
|---|
| 924 | return None
|
|---|
| 925 | for op, val in _OperatorOperands(self.value[1:]):
|
|---|
| 926 | val = val.eval(valuesDict)
|
|---|
| 927 | if val is None:
|
|---|
| 928 | return None
|
|---|
| 929 | elif op == '+':
|
|---|
| 930 | sum += val
|
|---|
| 931 | elif op == '-':
|
|---|
| 932 | sum -= val
|
|---|
| 933 | return sum
|
|---|
| 934 |
|
|---|
| 935 | class _EvalLiteralList(object):
|
|---|
| 936 | def __init__(self, tokens):
|
|---|
| 937 | self.tokens = tokens
|
|---|
| 938 |
|
|---|
| 939 | def eval(self, valuesDict=None):
|
|---|
| 940 | return map(lambda v: v.eval(valuesDict), self.tokens[1:-1])
|
|---|
| 941 |
|
|---|
| 942 | class _EvalComparisonOp(object):
|
|---|
| 943 | def __init__(self, tokens):
|
|---|
| 944 | self.tokens = tokens
|
|---|
| 945 |
|
|---|
| 946 | def eval(self, valuesDict=None):
|
|---|
| 947 | val1 = self.tokens[0].eval(valuesDict)
|
|---|
| 948 | if val1 is None:
|
|---|
| 949 | return None
|
|---|
| 950 |
|
|---|
| 951 | if len(self.tokens) == 3:
|
|---|
| 952 | val2 = self.tokens[2].eval(valuesDict)
|
|---|
| 953 | else:
|
|---|
| 954 | val2 = self.tokens[3].eval(valuesDict)
|
|---|
| 955 | if val2 is None:
|
|---|
| 956 | return None
|
|---|
| 957 |
|
|---|
| 958 | if self.tokens[1] == '=':
|
|---|
| 959 | return val1 == val2
|
|---|
| 960 | if self.tokens[1] == '<':
|
|---|
| 961 | return val1 < val2
|
|---|
| 962 | if self.tokens[1] == '>':
|
|---|
| 963 | return val1 > val2
|
|---|
| 964 | if self.tokens[1] == '<=':
|
|---|
| 965 | return val1 <= val2
|
|---|
| 966 | if self.tokens[1] == '>=':
|
|---|
| 967 | return val1 >= val2
|
|---|
| 968 | if self.tokens[1] == '<>':
|
|---|
| 969 | return val1 != val2
|
|---|
| 970 |
|
|---|
| 971 | if self.tokens[1].lower() == 'matches':
|
|---|
| 972 | if not isinstance(val1, basestring):
|
|---|
| 973 | raise TypeError(_(u'%(value)s is not permitted as the left-hand operand of the matches operator; both operands of the matches operator must be strings.') % {u'value': repr(val1)})
|
|---|
| 974 | if not isinstance(val2, basestring):
|
|---|
| 975 | raise TypeError(_(u'%(value)s is not permitted as the right-hand operand of the matches operator; both operands of the matches operator must be strings.') % {u'value': repr(val2)})
|
|---|
| 976 | return re.match(val2, val1, re.IGNORECASE) is not None
|
|---|
| 977 |
|
|---|
| 978 | if self.tokens[1].lower() == 'in':
|
|---|
| 979 | return val1 in val2
|
|---|
| 980 |
|
|---|
| 981 | if self.tokens[1].lower() == 'not' and self.tokens[2].lower() == 'in':
|
|---|
| 982 | return val1 not in val2
|
|---|
| 983 |
|
|---|
| 984 | raise RuntimeError(_(u'Unknown comparison operator "%(op)s".') % {u'op': self.tokens[1]})
|
|---|
| 985 |
|
|---|
| 986 | class _EvalNotOp(object):
|
|---|
| 987 | def __init__(self, tokens):
|
|---|
| 988 | self.value = tokens[0]
|
|---|
| 989 |
|
|---|
| 990 | def eval(self, valuesDict=None):
|
|---|
| 991 | val = self.value[1].eval(valuesDict)
|
|---|
| 992 | if val is None:
|
|---|
| 993 | return None
|
|---|
| 994 | return not val
|
|---|
| 995 |
|
|---|
| 996 | class _EvalAndOp(object):
|
|---|
| 997 | def __init__(self, tokens):
|
|---|
| 998 | self.value = tokens[0]
|
|---|
| 999 |
|
|---|
| 1000 | def eval(self, valuesDict=None):
|
|---|
| 1001 | val = self.value[0].eval(valuesDict)
|
|---|
| 1002 | if val is not None and not val:
|
|---|
| 1003 | return False
|
|---|
| 1004 | gotNone = val is None
|
|---|
| 1005 | for op, val in _OperatorOperands(self.value[1:]):
|
|---|
| 1006 | val = val.eval(valuesDict)
|
|---|
| 1007 | if val is not None and not val:
|
|---|
| 1008 | return False
|
|---|
| 1009 | gotNone = gotNone or val is None
|
|---|
| 1010 | if gotNone:
|
|---|
| 1011 | return None
|
|---|
| 1012 | return True
|
|---|
| 1013 |
|
|---|
| 1014 | class _EvalOrOp(object):
|
|---|
| 1015 | def __init__(self, tokens):
|
|---|
| 1016 | self.value = tokens[0]
|
|---|
| 1017 |
|
|---|
| 1018 | def eval(self, valuesDict=None):
|
|---|
| 1019 | val = self.value[0].eval(valuesDict)
|
|---|
| 1020 | if val:
|
|---|
| 1021 | return True
|
|---|
| 1022 | gotNone = val is None
|
|---|
| 1023 | for op, val in _OperatorOperands(self.value[1:]):
|
|---|
| 1024 | val = val.eval(valuesDict)
|
|---|
| 1025 | if val:
|
|---|
| 1026 | return True
|
|---|
| 1027 | gotNone = gotNone or val is None
|
|---|
| 1028 | if gotNone:
|
|---|
| 1029 | return None
|
|---|
| 1030 | return False
|
|---|
| 1031 |
|
|---|
| 1032 | # Import pyparsing and enable "packrat" mode for higher
|
|---|
| 1033 | # performance. Note that pyparsing is included in the
|
|---|
| 1034 | # AggregatedModules sub-package of GeoEco. It can be
|
|---|
| 1035 | # imported here without referencing the sub-package
|
|---|
| 1036 | # because it was already imported by means of a
|
|---|
| 1037 | # PythonAggregatedModuleDependency attached to the
|
|---|
| 1038 | # DatasetCollection.QueryDatasets metadata.
|
|---|
| 1039 |
|
|---|
| 1040 | from pyparsing import CaselessKeyword, CaselessLiteral, Combine, delimitedList, nums, oneOf, opAssoc, operatorPrecedence, Optional, ParserElement, QuotedString, Regex, Word
|
|---|
| 1041 | ParserElement.enablePackrat()
|
|---|
| 1042 |
|
|---|
| 1043 | # Define the parser using pyparsing.
|
|---|
| 1044 | #
|
|---|
| 1045 | # booleanExpr is the parser. It takes an expression
|
|---|
| 1046 | # resembling a SQL where clause and a dictionary of
|
|---|
| 1047 | # variable values and returns True or False. If the
|
|---|
| 1048 | # dictionary does not contain all of the variables
|
|---|
| 1049 | # referenced in the expression, the parser still works,
|
|---|
| 1050 | # but if a missing variable causes the value of the
|
|---|
| 1051 | # expression to be indeterminate--i.e. it the result
|
|---|
| 1052 | # cannot be determined without knowing the value of the
|
|---|
| 1053 | # variable, the parser returns None.
|
|---|
| 1054 |
|
|---|
| 1055 | booleanLiteral = CaselessKeyword('false') | CaselessKeyword('true')
|
|---|
| 1056 | integerLiteral = Word(nums)
|
|---|
| 1057 | floatLiteral = Combine(((Word(nums) + '.' + Optional(Word(nums))) | ('.' + Word(nums))) + Optional(CaselessLiteral('E') + Optional(oneOf('+ -')) + Word(nums)))
|
|---|
| 1058 | dateLiteral = Combine('#' + (Regex('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}') | Regex('[0-9]{4}-[0-9]{2}-[0-9]{2}')) + '#')
|
|---|
| 1059 | stringLiteral = QuotedString("'", "\\", "''", True, False) ^ QuotedString('"', "\\", '""', True, False)
|
|---|
| 1060 |
|
|---|
| 1061 | literal = booleanLiteral | integerLiteral | floatLiteral | dateLiteral | stringLiteral
|
|---|
| 1062 | literal.setParseAction(_EvalLiteral)
|
|---|
| 1063 |
|
|---|
| 1064 | variable = Regex('[a-zA-Z][a-zA-Z0-9_]*')
|
|---|
| 1065 | variable.setParseAction(_EvalVariable)
|
|---|
| 1066 |
|
|---|
| 1067 | arithExpr = operatorPrecedence(literal | variable,
|
|---|
| 1068 | [(oneOf('+ -'), 1, opAssoc.RIGHT, _EvalSignOp),
|
|---|
| 1069 | (oneOf('* /'), 2, opAssoc.LEFT, _EvalMultOp),
|
|---|
| 1070 | (oneOf('+ -'), 2, opAssoc.LEFT, _EvalAddOp)])
|
|---|
| 1071 |
|
|---|
| 1072 | literalList = '(' + delimitedList(literal) + ')'
|
|---|
| 1073 | literalList.setParseAction(_EvalLiteralList)
|
|---|
| 1074 |
|
|---|
| 1075 | comparisonExpr = arithExpr + (oneOf("= < > >= <= <>") | CaselessKeyword("matches")) + arithExpr | arithExpr + CaselessKeyword("in") + literalList | arithExpr + CaselessKeyword("not") + CaselessKeyword("in") + literalList
|
|---|
| 1076 | comparisonExpr.setParseAction(_EvalComparisonOp)
|
|---|
| 1077 |
|
|---|
| 1078 | booleanExpr = operatorPrecedence(comparisonExpr,
|
|---|
| 1079 | [(CaselessKeyword("not"), 1, opAssoc.RIGHT, _EvalNotOp),
|
|---|
| 1080 | (CaselessKeyword("and"), 2, opAssoc.LEFT, _EvalAndOp),
|
|---|
| 1081 | (CaselessKeyword("or"), 2, opAssoc.LEFT, _EvalOrOp)])
|
|---|
| 1082 |
|
|---|
| 1083 | # Store the parser as a class attribute.
|
|---|
| 1084 |
|
|---|
| 1085 | setattr(DatasetCollection, '_QueryExpressionParser', booleanExpr)
|
|---|
| 1086 |
|
|---|
| 1087 | return DatasetCollection._QueryExpressionParser
|
|---|
| 1088 |
|
|---|
| 1089 | def _PrepareQuery(self, expression):
|
|---|
| 1090 |
|
|---|
| 1091 | # Parse the expression.
|
|---|
| 1092 |
|
|---|
| 1093 | if expression is not None and len(expression) > 0:
|
|---|
| 1094 | parser = self._GetQueryExpressionParser()
|
|---|
| 1095 | try:
|
|---|
| 1096 | parsedExpression = parser.parseString(expression, parseAll=True)[0]
|
|---|
| 1097 | except Exception, e:
|
|---|
| 1098 | raise ValueError(_(u'Failed to parse the query expression "%(expr)s". The parser reported %(e)s: %(msg)s') % {u'expr': expression, u'e': e.__class__.__name__, u'msg': self._Unicode(e)})
|
|---|
| 1099 | else:
|
|---|
| 1100 | parsedExpression = None
|
|---|
| 1101 |
|
|---|
| 1102 | # Build a dictionary of queryable attribute values defined by
|
|---|
| 1103 | # us and our chain of parent collections, so that the derived
|
|---|
| 1104 | # class can use it in evaluating the query.
|
|---|
| 1105 |
|
|---|
| 1106 | parentAttrValues = {}
|
|---|
| 1107 | collection = self
|
|---|
| 1108 | while collection is not None:
|
|---|
| 1109 | if collection._QueryableAttributeValues is not None:
|
|---|
| 1110 | parentAttrValues.update(collection._QueryableAttributeValues)
|
|---|
| 1111 | collection = collection.ParentCollection
|
|---|
| 1112 |
|
|---|
| 1113 | # Return the parsed expression and dictionary.
|
|---|
| 1114 |
|
|---|
| 1115 | return parsedExpression, parentAttrValues
|
|---|
| 1116 |
|
|---|
| 1117 | # Private methods that the derived class should override.
|
|---|
| 1118 |
|
|---|
| 1119 | def _QueryDatasets(self, parsedExpression, progressReporter, options, parentAttrValues):
|
|---|
| 1120 | raise NotImplementedError(_(u'The _QueryDatasets method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 1121 |
|
|---|
| 1122 | def _GetOldestDataset(self, parsedExpression, options, parentAttrValues, dateTimeAttrName):
|
|---|
| 1123 |
|
|---|
| 1124 | # The base class implementation just retrieves all of the
|
|---|
| 1125 | # datasets and iterates through them to find the oldest one.
|
|---|
| 1126 | # The derived class should override this if it can implement
|
|---|
| 1127 | # it more efficiently.
|
|---|
| 1128 |
|
|---|
| 1129 | datasets = self._QueryDatasets(parsedExpression, None, options, parentAttrValues)
|
|---|
| 1130 | if len(datasets) <= 0:
|
|---|
| 1131 | return None
|
|---|
| 1132 |
|
|---|
| 1133 | oldest = 0
|
|---|
| 1134 | for i in range(1, len(datasets)):
|
|---|
| 1135 | if datasets[i].GetQueryableAttributeValue(dateTimeAttrName) < datasets[oldest].GetQueryableAttributeValue(dateTimeAttrName):
|
|---|
| 1136 | oldest = i
|
|---|
| 1137 |
|
|---|
| 1138 | return datasets[oldest]
|
|---|
| 1139 |
|
|---|
| 1140 | def _GetNewestDataset(self, parsedExpression, options, parentAttrValues, dateTimeAttrName):
|
|---|
| 1141 |
|
|---|
| 1142 | # The base class implementation just retrieves all of the
|
|---|
| 1143 | # datasets and iterates through them to find the newest one.
|
|---|
| 1144 | # The derived class should override this if it can implement
|
|---|
| 1145 | # it more efficiently.
|
|---|
| 1146 |
|
|---|
| 1147 | datasets = self._QueryDatasets(parsedExpression, None, options, parentAttrValues)
|
|---|
| 1148 | if len(datasets) <= 0:
|
|---|
| 1149 | return None
|
|---|
| 1150 |
|
|---|
| 1151 | newest = 0
|
|---|
| 1152 | for i in range(1, len(datasets)):
|
|---|
| 1153 | if datasets[i].GetQueryableAttributeValue(dateTimeAttrName) > datasets[newest].GetQueryableAttributeValue(dateTimeAttrName):
|
|---|
| 1154 | newest = i
|
|---|
| 1155 |
|
|---|
| 1156 | return datasets[newest]
|
|---|
| 1157 |
|
|---|
| 1158 | def _ImportDatasets(self, datasets, mode, reportProgress, options):
|
|---|
| 1159 | raise NotImplementedError(_(u'The _ImportDatasets method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 1160 |
|
|---|
| 1161 |
|
|---|
| 1162 | class Database(object):
|
|---|
| 1163 | __doc__ = DynamicDocString()
|
|---|
| 1164 |
|
|---|
| 1165 | # Public interface.
|
|---|
| 1166 |
|
|---|
| 1167 | def TableExists(self, tableName):
|
|---|
| 1168 | # TODO: Validation
|
|---|
| 1169 | exists = self._TableExists(tableName)
|
|---|
| 1170 |
|
|---|
| 1171 | if exists:
|
|---|
| 1172 | self._LogDebug(_(u'%(class)s 0x%(id)08X: The %(objectType)s %(table)s exists in %(dn)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'objectType': self._GetObjectTypeDisplayName(tableName), u'table': tableName, u'dn': self.DisplayName})
|
|---|
| 1173 | else:
|
|---|
| 1174 | self._LogDebug(_(u'%(class)s 0x%(id)08X: The %(objectType)s %(table)s does not exist in %(dn)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'objectType': self._GetObjectTypeDisplayName(tableName), u'table': tableName, u'dn': self.DisplayName})
|
|---|
| 1175 |
|
|---|
| 1176 | return exists
|
|---|
| 1177 |
|
|---|
| 1178 | def CreateTable(self, tableName, geometryType=None, spatialReference=None, geometryFieldName=None):
|
|---|
| 1179 | # TODO: Validation
|
|---|
| 1180 |
|
|---|
| 1181 | self._RequireCapability('CreateTable')
|
|---|
| 1182 | if geometryType is not None:
|
|---|
| 1183 | self._RequireCapability('GeometryType %s %s' % (geometryType, tableName))
|
|---|
| 1184 | if geometryType is not None:
|
|---|
| 1185 | self._RequireCapability('GeometryFieldName')
|
|---|
| 1186 |
|
|---|
| 1187 | if self.TableExists(tableName):
|
|---|
| 1188 | raise RuntimeError(_(u'Cannot create %(objectType)s %(table)s in %(dn)s because that %(objectType)s already exists.') % {u'objectType': self._GetObjectTypeDisplayName(tableName), u'table': tableName, u'dn': self.DisplayName})
|
|---|
| 1189 |
|
|---|
| 1190 | if geometryType is None:
|
|---|
| 1191 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Creating %(objectType)s %(table)s in %(dn)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'objectType': self._GetObjectTypeDisplayName(tableName), u'table': tableName, u'dn': self.DisplayName})
|
|---|
| 1192 | else:
|
|---|
| 1193 | if spatialReference is None:
|
|---|
| 1194 | wkt = None
|
|---|
| 1195 | else:
|
|---|
| 1196 | wkt = spatialReference.ExportToWkt()
|
|---|
| 1197 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Creating %(objectType)s %(table)s in %(dn)s with geometryType=%(geometryType)s, spatialReference=%(wkt)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'objectType': self._GetObjectTypeDisplayName(tableName), u'table': tableName, u'dn': self.DisplayName, u'geometryType': geometryType, u'wkt': repr(wkt)})
|
|---|
| 1198 |
|
|---|
| 1199 | try:
|
|---|
| 1200 | return self._CreateTable(tableName, geometryType, spatialReference, geometryFieldName)
|
|---|
| 1201 | except Exception, e:
|
|---|
| 1202 | raise RuntimeError(_(u'Failed to create %(objectType)s %(tableName)s in %(dn)s due to %(e)s: %(msg)s.') % {u'objectType': self._GetObjectTypeDisplayName(tableName), u'tableName': tableName, u'dn': self._DisplayName, u'e': e.__class__.__name__, u'msg': self._Str(e)})
|
|---|
| 1203 |
|
|---|
| 1204 | def CreateTableFromTemplate(self, tableName, templateTable, fields=None, allowSafeCoercions=True):
|
|---|
| 1205 | # TODO: Validation
|
|---|
| 1206 |
|
|---|
| 1207 | # If the caller specified a list of fields to use, make sure
|
|---|
| 1208 | # all of those fields exist.
|
|---|
| 1209 |
|
|---|
| 1210 | createGeometryField = False
|
|---|
| 1211 |
|
|---|
| 1212 | if fields is not None:
|
|---|
| 1213 | sourceFields = []
|
|---|
| 1214 | for name in fields:
|
|---|
| 1215 | if name == templateTable.OIDFieldName: # Skip the OID field, if the caller specified it.
|
|---|
| 1216 | continue
|
|---|
| 1217 |
|
|---|
| 1218 | if name == templateTable.GeometryFieldName: # Also skip the geometry field.
|
|---|
| 1219 | createGeometryField = True
|
|---|
| 1220 | continue
|
|---|
| 1221 |
|
|---|
| 1222 | field = templateTable.GetFieldByName(name)
|
|---|
| 1223 | if field is None:
|
|---|
| 1224 | raise ValueError(_(u'Cannot create a field named %(field)s in new table %(table)s because that field does not exist in %(template)s.') % {u'field': name, u'table': tableName, u'template': templateTable.DisplayName})
|
|---|
| 1225 |
|
|---|
| 1226 | sourceFields.append(field)
|
|---|
| 1227 |
|
|---|
| 1228 | # Otherwise, use all of the fields except the OID and geometry
|
|---|
| 1229 | # field.
|
|---|
| 1230 |
|
|---|
| 1231 | else:
|
|---|
| 1232 | createGeometryField = True
|
|---|
| 1233 | sourceFields = list(templateTable.Fields)
|
|---|
| 1234 | i = 0
|
|---|
| 1235 | while i < len(sourceFields):
|
|---|
| 1236 | if sourceFields[i].Name in [templateTable.OIDFieldName, templateTable.GeometryFieldName]:
|
|---|
| 1237 | del sourceFields[i]
|
|---|
| 1238 | else:
|
|---|
| 1239 | i += 1
|
|---|
| 1240 |
|
|---|
| 1241 | # Create the table.
|
|---|
| 1242 |
|
|---|
| 1243 | if createGeometryField:
|
|---|
| 1244 | table = self.CreateTable(tableName, templateTable.GeometryType, templateTable.GetSpatialReference('Obj'), templateTable.GeometryFieldName)
|
|---|
| 1245 | else:
|
|---|
| 1246 | table = self.CreateTable(tableName)
|
|---|
| 1247 |
|
|---|
| 1248 | # Add the fields.
|
|---|
| 1249 |
|
|---|
| 1250 | for field in sourceFields:
|
|---|
| 1251 | table.AddField(field.Name, field.DataType, field.Length, field.Precision, field.IsNullable, allowSafeCoercions, True)
|
|---|
| 1252 |
|
|---|
| 1253 | # Return successfully.
|
|---|
| 1254 |
|
|---|
| 1255 | return table
|
|---|
| 1256 |
|
|---|
| 1257 | def ImportTable(self, destTableName, sourceTable, fields=None, where=None, orderBy=None, rowCount=None, reportProgress=True, rowDescriptionSingular=None, rowDescriptionPlural=None, copiedOIDFieldName=None, allowSafeCoercions=True):
|
|---|
| 1258 | # TODO: Validation
|
|---|
| 1259 |
|
|---|
| 1260 | # Create the destination table.
|
|---|
| 1261 |
|
|---|
| 1262 | destTable = self.CreateTableFromTemplate(destTableName, sourceTable, fields, allowSafeCoercions)
|
|---|
| 1263 |
|
|---|
| 1264 | # If the caller requested that the OID field be copied from
|
|---|
| 1265 | # the source table to a new field in the destination table,
|
|---|
| 1266 | # add a field for that.
|
|---|
| 1267 |
|
|---|
| 1268 | if copiedOIDFieldName is not None:
|
|---|
| 1269 | destTable.AddField(copiedOIDFieldName, 'int32', None, None, False, allowSafeCoercions, True)
|
|---|
| 1270 |
|
|---|
| 1271 | # If the caller specified a list of fields to copy, make sure
|
|---|
| 1272 | # the list includes the OID and/or geometry fields, if they
|
|---|
| 1273 | # are needed.
|
|---|
| 1274 |
|
|---|
| 1275 | if fields is not None:
|
|---|
| 1276 | if copiedOIDFieldName is not None and sourceTable.OIDFieldName not in fields:
|
|---|
| 1277 | fields.append(sourceTable.OIDFieldName)
|
|---|
| 1278 | if destTable.GeometryType is not None and sourceTable.GeometryFieldName not in fields:
|
|---|
| 1279 | fields.append(sourceTable.GeometryFieldName)
|
|---|
| 1280 |
|
|---|
| 1281 | # Otherwise create a list of fields to copy, removing the OID
|
|---|
| 1282 | # and/or geometry fields, if they are not needed.
|
|---|
| 1283 |
|
|---|
| 1284 | else:
|
|---|
| 1285 | fields = [field.Name for field in sourceTable.Fields]
|
|---|
| 1286 | if copiedOIDFieldName is None:
|
|---|
| 1287 | fields.remove(sourceTable.OIDFieldName)
|
|---|
| 1288 | if destTable.GeometryType is None:
|
|---|
| 1289 | fields.remove(sourceTable.GeometryFieldName)
|
|---|
| 1290 |
|
|---|
| 1291 | # Open a select cursor on the source table and an insert
|
|---|
| 1292 | # cursor on the destination table, and copy the rows.
|
|---|
| 1293 |
|
|---|
| 1294 | selectCursor = sourceTable.OpenSelectCursor(fields, where, orderBy, rowCount, False, rowDescriptionSingular, rowDescriptionPlural)
|
|---|
| 1295 | try:
|
|---|
| 1296 | insertCursor = destTable.OpenInsertCursor(rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural)
|
|---|
| 1297 | try:
|
|---|
| 1298 | while selectCursor.NextRow():
|
|---|
| 1299 | for field in fields:
|
|---|
| 1300 | if field == sourceTable.OIDFieldName:
|
|---|
| 1301 | insertCursor.SetValue(copiedOIDFieldName, selectCursor.GetOID())
|
|---|
| 1302 | elif field == sourceTable.GeometryFieldName:
|
|---|
| 1303 | insertCursor.SetGeometry(selectCursor.GetGeometry())
|
|---|
| 1304 | else:
|
|---|
| 1305 | insertCursor.SetValue(field, selectCursor.GetValue(value))
|
|---|
| 1306 | finally:
|
|---|
| 1307 | del insertCursor
|
|---|
| 1308 | finally:
|
|---|
| 1309 | del selectCursor
|
|---|
| 1310 |
|
|---|
| 1311 |
|
|---|
| 1312 | def DeleteTable(self, tableName, failIfNotExists=False):
|
|---|
| 1313 | # TODO: Validation
|
|---|
| 1314 |
|
|---|
| 1315 | self._RequireCapability('DeleteTable')
|
|---|
| 1316 |
|
|---|
| 1317 | if not self.TableExists(tableName):
|
|---|
| 1318 | if failIfNotExists:
|
|---|
| 1319 | raise RuntimeError(_(u'Cannot create %(objectType)s %(table)s in %(dn)s because that %(objectType)s already exists.') % {u'objectType': self._GetObjectTypeDisplayName(tableName), u'table': tableName, u'dn': self.DisplayName})
|
|---|
| 1320 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Not deleting %(objectType)s %(table)s from %(dn)s because that %(objectType)s does not exist.'), {u'class': self.__class__.__name__, u'id': id(self), u'objectType': self._GetObjectTypeDisplayName(tableName), u'table': tableName, u'dn': self.DisplayName})
|
|---|
| 1321 | return
|
|---|
| 1322 |
|
|---|
| 1323 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Deleting %(objectType)s %(table)s from %(dn)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'objectType': self._GetObjectTypeDisplayName(tableName), u'table': tableName, u'dn': self.DisplayName})
|
|---|
| 1324 |
|
|---|
| 1325 | try:
|
|---|
| 1326 | self._DeleteTable(tableName)
|
|---|
| 1327 | except Exception, e:
|
|---|
| 1328 | raise RuntimeError(_(u'Failed to delete %(objectType)s %(tableName)s from %(dn)s due to %(e)s: %(msg)s.') % {u'objectType': self._GetObjectTypeDisplayName(tableName), u'tableName': tableName, u'dn': self._DisplayName, u'e': e.__class__.__name__, u'msg': self._Str(e)})
|
|---|
| 1329 |
|
|---|
| 1330 |
|
|---|
| 1331 | # Private members that the derived class should override.
|
|---|
| 1332 |
|
|---|
| 1333 | def _GetObjectTypeDisplayName(self, tableName):
|
|---|
| 1334 | return _(u'table')
|
|---|
| 1335 |
|
|---|
| 1336 | def _TableExists(self, tableName):
|
|---|
| 1337 | raise RuntimeError(_(u'Programming error in this tool: The %(cls)s class does not define the Database._TableExists method. Please contact the author of this tool for assistance.') % {u'cls': self.__class__.__name__})
|
|---|
| 1338 |
|
|---|
| 1339 | def _CreateTable(self, tableName, geometryType=None, spatialReference=None, geometryFieldName=u'geometry'):
|
|---|
| 1340 | raise RuntimeError(_(u'Programming error in this tool: The %(cls)s class does not define the Database._CreateTable method. Please contact the author of this tool for assistance.') % {u'cls': self.__class__.__name__})
|
|---|
| 1341 |
|
|---|
| 1342 | def _DeleteTable(self, tableName):
|
|---|
| 1343 | raise RuntimeError(_(u'Programming error in this tool: The %(cls)s class does not define the Database._DeleteTable method. Please contact the author of this tool for assistance.') % {u'cls': self.__class__.__name__})
|
|---|
| 1344 |
|
|---|
| 1345 |
|
|---|
| 1346 | class Table(Dataset):
|
|---|
| 1347 | __doc__ = DynamicDocString()
|
|---|
| 1348 |
|
|---|
| 1349 | # Public properties and instance methods
|
|---|
| 1350 |
|
|---|
| 1351 | def _GetHasOID(self):
|
|---|
| 1352 | return self.GetLazyPropertyValue('HasOID')
|
|---|
| 1353 |
|
|---|
| 1354 | HasOID = property(_GetHasOID, doc=DynamicDocString())
|
|---|
| 1355 |
|
|---|
| 1356 | def _GetOIDFieldName(self):
|
|---|
| 1357 | return self.GetLazyPropertyValue('OIDFieldName')
|
|---|
| 1358 |
|
|---|
| 1359 | OIDFieldName = property(_GetOIDFieldName, doc=DynamicDocString())
|
|---|
| 1360 |
|
|---|
| 1361 | def _GetGeometryType(self):
|
|---|
| 1362 | return self.GetLazyPropertyValue('GeometryType')
|
|---|
| 1363 |
|
|---|
| 1364 | GeometryType = property(_GetGeometryType, doc=DynamicDocString())
|
|---|
| 1365 |
|
|---|
| 1366 | def _GetGeometryFieldName(self):
|
|---|
| 1367 | return self.GetLazyPropertyValue('GeometryFieldName')
|
|---|
| 1368 |
|
|---|
| 1369 | GeometryFieldName = property(_GetGeometryFieldName, doc=DynamicDocString())
|
|---|
| 1370 |
|
|---|
| 1371 | def _GetMaxStringLength(self):
|
|---|
| 1372 | return self.GetLazyPropertyValue('MaxStringLength')
|
|---|
| 1373 |
|
|---|
| 1374 | MaxStringLength = property(_GetMaxStringLength, doc=DynamicDocString())
|
|---|
| 1375 |
|
|---|
| 1376 | def _GetFields(self):
|
|---|
| 1377 | return self.GetLazyPropertyValue('Fields')
|
|---|
| 1378 |
|
|---|
| 1379 | Fields = property(_GetFields, doc=DynamicDocString())
|
|---|
| 1380 |
|
|---|
| 1381 | def GetFieldByName(self, name):
|
|---|
| 1382 | # TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 1383 | if not hasattr(self, '_FieldsDict') or self._FieldsDict is None:
|
|---|
| 1384 | self._FieldsDict = {}
|
|---|
| 1385 | for field in self.Fields:
|
|---|
| 1386 | self._FieldsDict[field.Name.upper()] = field
|
|---|
| 1387 | if name.upper() not in self._FieldsDict:
|
|---|
| 1388 | return None
|
|---|
| 1389 | return self._FieldsDict[name.upper()]
|
|---|
| 1390 |
|
|---|
| 1391 | def AddField(self, name, dataType, length=None, precision=None, isNullable=None, allowSafeCoercions=True, failIfExists=False):
|
|---|
| 1392 | # TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 1393 |
|
|---|
| 1394 | # Verify that we have the required capabilities. If needed and
|
|---|
| 1395 | # allowed by the caller, coerce unsupported data types to
|
|---|
| 1396 | # supported ones.
|
|---|
| 1397 |
|
|---|
| 1398 | self._RequireCapability('AddField')
|
|---|
| 1399 |
|
|---|
| 1400 | if allowSafeCoercions and dataType in ['date', 'int16', 'int32', 'float32']:
|
|---|
| 1401 | if self._TestCapability(dataType + ' datatype') is not None:
|
|---|
| 1402 | if dataType == 'date':
|
|---|
| 1403 | newDataType = 'datetime'
|
|---|
| 1404 | if self._TestCapability(newDataType + ' datatype') is not None:
|
|---|
| 1405 | self._RequireCapability(dataType + ' DataType')
|
|---|
| 1406 |
|
|---|
| 1407 | elif dataType == 'int16':
|
|---|
| 1408 | newDataType = 'int32'
|
|---|
| 1409 | if self._TestCapability(newDataType + ' datatype') is not None:
|
|---|
| 1410 | newDataType = 'float32'
|
|---|
| 1411 | if self._TestCapability(newDataType + ' datatype') is not None:
|
|---|
| 1412 | newDataType = 'float64'
|
|---|
| 1413 | if self._TestCapability(newDataType + ' datatype') is not None:
|
|---|
| 1414 | self._RequireCapability(dataType + ' DataType')
|
|---|
| 1415 |
|
|---|
| 1416 | else:
|
|---|
| 1417 | newDataType = 'float64'
|
|---|
| 1418 | if self._TestCapability(newDataType + ' datatype') is not None:
|
|---|
| 1419 | self._RequireCapability(dataType + ' DataType')
|
|---|
| 1420 |
|
|---|
| 1421 | dataType = newDataType
|
|---|
| 1422 | else:
|
|---|
| 1423 | self._RequireCapability(dataType + ' DataType')
|
|---|
| 1424 |
|
|---|
| 1425 | if isNullable:
|
|---|
| 1426 | self._RequireCapability(dataType + ' IsNullable')
|
|---|
| 1427 |
|
|---|
| 1428 | # If the data type is 'string', verify that the length
|
|---|
| 1429 | # parameter was supplied and that it does not exceed the
|
|---|
| 1430 | # maximum allowed length.
|
|---|
| 1431 |
|
|---|
| 1432 | if dataType == 'string':
|
|---|
| 1433 | if length is None:
|
|---|
| 1434 | raise ValueError(_(u'Cannot add string field %(name)s to %(dn)s because the field length was not specified. When adding a string field, you must specify the field length.') % {u'name': name, u'dn': self.DisplayName})
|
|---|
| 1435 | if self.MaxStringLength is not None and length > self.MaxStringLength:
|
|---|
| 1436 | raise ValueError(_(u'Cannot add string field %(name)s to %(dn)s because the field length (%(length)i) exceeds the maximum allowed for this dataset (%(max)i).') % {u'name': name, u'length': length, u'dn': self.DisplayName, u'max': self.MaxStringLength})
|
|---|
| 1437 |
|
|---|
| 1438 | # If the field already exists with the exact parameters
|
|---|
| 1439 | # requested by the caller and the caller does not want us to
|
|---|
| 1440 | # fail in that situation, return silently now.
|
|---|
| 1441 |
|
|---|
| 1442 | existingField = self.GetFieldByName(name)
|
|---|
| 1443 | if existingField is not None:
|
|---|
| 1444 | if not failIfExists:
|
|---|
| 1445 | if existingField.DataType == dataType and (length is None or existingField.Length >= length) and (precision is None or existingField.Precision >= precision) and (isNullable is None or existingField.IsNullable == isNullable):
|
|---|
| 1446 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Not adding field with name %(Name)s because it already exists.'), {u'class': self.__class__.__name__, u'id': id(self), u'Name': name})
|
|---|
| 1447 | return
|
|---|
| 1448 | raise ValueError(_(u'Cannot add field %(name)s to %(dn)s because a field with that name already exists and it has different characteristics than those you requested.') % {u'name': name, u'dn': self.DisplayName})
|
|---|
| 1449 | raise ValueError(_(u'Cannot add field %(name)s to %(dn)s because a field with that name already exists.') % {u'name': name, u'dn': self.DisplayName})
|
|---|
| 1450 |
|
|---|
| 1451 | # Call the derived class to add the field.
|
|---|
| 1452 |
|
|---|
| 1453 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Adding field %(i)i: Name=%(Name)s, DataType=%(DataType)s, Length=%(Length)s, Precision=%(Precision)s, IsNullable=%(IsNullable)s.'),
|
|---|
| 1454 | {u'class': self.__class__.__name__, u'id': id(self), u'i': len(self.Fields), u'Name': name, u'DataType': dataType, u'Length': repr(length), u'Precision': repr(precision), u'IsNullable': repr(isNullable)})
|
|---|
| 1455 |
|
|---|
| 1456 | try:
|
|---|
| 1457 | field = self._AddField(name, dataType, length, precision, isNullable)
|
|---|
| 1458 | except Exception, e:
|
|---|
| 1459 | raise RuntimeError(_(u'Failed to add a field named %(name)s to %(dn)s due to %(e)s: %(msg)s') % {u'name': name, u'dn': self.DisplayName, u'e': e.__class__.__name__, u'msg': self._Unicode(e)})
|
|---|
| 1460 |
|
|---|
| 1461 | # If we succeeded, add the field to our cached list and
|
|---|
| 1462 | # dictionary of fields.
|
|---|
| 1463 |
|
|---|
| 1464 | self.Fields.append(field)
|
|---|
| 1465 | self._FieldsDict[name.upper()] = field
|
|---|
| 1466 |
|
|---|
| 1467 | def DeleteField(self, name, failIfDoesNotExist=False):
|
|---|
| 1468 | # TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 1469 |
|
|---|
| 1470 | # Verify that we have the required capabilities.
|
|---|
| 1471 |
|
|---|
| 1472 | self._RequireCapability('DeleteField')
|
|---|
| 1473 |
|
|---|
| 1474 | # If the field does not already exist and the caller does not
|
|---|
| 1475 | # want us to fail in that situation, return silently now.
|
|---|
| 1476 |
|
|---|
| 1477 | existingField = self.GetFieldByName(name)
|
|---|
| 1478 | if existingField is None:
|
|---|
| 1479 | if not failIfDoesNotExist:
|
|---|
| 1480 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Not deleting field with name %(Name)s because it does not exist.'), {u'class': self.__class__.__name__, u'id': id(self), u'Name': name})
|
|---|
| 1481 | return
|
|---|
| 1482 | raise ValueError(_(u'Cannot delete field %(name)s from %(dn)s because a field with that name does not exist.') % {u'name': name, u'dn': self.DisplayName})
|
|---|
| 1483 |
|
|---|
| 1484 | # Call the derived class to delete the field.
|
|---|
| 1485 |
|
|---|
| 1486 | for i, f in enumerate(self.Fields):
|
|---|
| 1487 | if f.Name == existingField.Name:
|
|---|
| 1488 | break
|
|---|
| 1489 |
|
|---|
| 1490 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Deleting field %(i)i: Name=%(Name)s, DataType=%(DataType)s, Length=%(Length)s, Precision=%(Precision)s, IsNullable=%(IsNullable)s.'),
|
|---|
| 1491 | {u'class': self.__class__.__name__, u'id': id(self), u'i': i, u'Name': existingField.Name, u'DataType': existingField.DataType, u'Length': repr(existingField.Length), u'Precision': repr(existingField.Precision), u'IsNullable': repr(existingField.IsNullable)})
|
|---|
| 1492 |
|
|---|
| 1493 | try:
|
|---|
| 1494 | self._DeleteField(name)
|
|---|
| 1495 | except Exception, e:
|
|---|
| 1496 | raise RuntimeError(_(u'Failed to delete field %(name)s from %(dn)s due to %(e)s: %(msg)s') % {u'name': name, u'dn': self.DisplayName, u'e': e.__class__.__name__, u'msg': self._Unicode(e)})
|
|---|
| 1497 |
|
|---|
| 1498 | # If we succeeded, remove the field from our cached list of
|
|---|
| 1499 | # fields.
|
|---|
| 1500 |
|
|---|
| 1501 | del self.Fields[i]
|
|---|
| 1502 | del self._FieldsDict[existingField.Name.upper()]
|
|---|
| 1503 |
|
|---|
| 1504 | def GetRowCount(self):
|
|---|
| 1505 | try:
|
|---|
| 1506 | rowCount = self._GetRowCount()
|
|---|
| 1507 | except Exception, e:
|
|---|
| 1508 | raise RuntimeError(_(u'Failed to obtain the count of rows in %(dn)s due to %(e)s: %(msg)s') % {u'dn': self.DisplayName, u'e': e.__class__.__name__, u'msg': self._Unicode(e)})
|
|---|
| 1509 | self._LogDebug(_(u'%(class)s 0x%(id)08X: GetRowCount returned %(rc)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'rc': repr(rowCount)})
|
|---|
| 1510 | return rowCount
|
|---|
| 1511 |
|
|---|
| 1512 | def OpenSelectCursor(self, fields=None, where=None, orderBy=None, rowCount=None, reportProgress=True, rowDescriptionSingular=None, rowDescriptionPlural=None): #TODO: Add spatial filter
|
|---|
| 1513 | #TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 1514 | self._RequireCapability('SelectCursor')
|
|---|
| 1515 | #TODO: self._RequireCapability('OrderBy')
|
|---|
| 1516 | return self._OpenSelectCursor(fields, where, orderBy, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural)
|
|---|
| 1517 |
|
|---|
| 1518 | def OpenUpdateCursor(self, fields=None, where=None, orderBy=None, rowCount=None, reportProgress=True, rowDescriptionSingular=None, rowDescriptionPlural=None): #TODO: Add spatial filter
|
|---|
| 1519 | #TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 1520 | self._RequireCapability('UpdateCursor')
|
|---|
| 1521 | #TODO: self._RequireCapability('OrderBy')
|
|---|
| 1522 | return self._OpenUpdateCursor(fields, where, orderBy, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural)
|
|---|
| 1523 |
|
|---|
| 1524 | def OpenInsertCursor(self, rowCount=None, reportProgress=True, rowDescriptionSingular=None, rowDescriptionPlural=None):
|
|---|
| 1525 | #TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 1526 | self._RequireCapability('InsertCursor')
|
|---|
| 1527 | return self._OpenInsertCursor(rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural)
|
|---|
| 1528 |
|
|---|
| 1529 | # Private instance methods that the derived class should override
|
|---|
| 1530 | # if the capability is supported
|
|---|
| 1531 |
|
|---|
| 1532 | def _AddField(self, name, dataType, length, precision, isNullable):
|
|---|
| 1533 | raise NotImplementedError(_(u'The _AddField method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 1534 |
|
|---|
| 1535 | def _DeleteField(self, name):
|
|---|
| 1536 | raise NotImplementedError(_(u'The _DeleteField method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 1537 |
|
|---|
| 1538 | def _GetRowCount(self):
|
|---|
| 1539 | raise NotImplementedError(_(u'The _GetRowCount method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 1540 |
|
|---|
| 1541 | def _OpenSelectCursor(self, fields, where, orderBy, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural):
|
|---|
| 1542 | raise NotImplementedError(_(u'The _OpenSelectCursor method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 1543 |
|
|---|
| 1544 | def _OpenUpdateCursor(self, fields, where, orderBy, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural):
|
|---|
| 1545 | raise NotImplementedError(_(u'The _OpenUpdateCursor method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 1546 |
|
|---|
| 1547 | def _OpenInsertCursor(self, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural):
|
|---|
| 1548 | raise NotImplementedError(_(u'The _OpenInsertCursor method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 1549 |
|
|---|
| 1550 |
|
|---|
| 1551 | class Field(object):
|
|---|
| 1552 | __doc__ = DynamicDocString()
|
|---|
| 1553 |
|
|---|
| 1554 | # Public properties
|
|---|
| 1555 |
|
|---|
| 1556 | def _GetName(self):
|
|---|
| 1557 | return self._Name
|
|---|
| 1558 |
|
|---|
| 1559 | def _GetDataType(self):
|
|---|
| 1560 | return self._DataType
|
|---|
| 1561 |
|
|---|
| 1562 | def _GetLength(self):
|
|---|
| 1563 | return self._Length
|
|---|
| 1564 |
|
|---|
| 1565 | def _GetPrecision(self):
|
|---|
| 1566 | return self._Precision
|
|---|
| 1567 |
|
|---|
| 1568 | def _GetIsNullable(self):
|
|---|
| 1569 | return self._IsNullable
|
|---|
| 1570 |
|
|---|
| 1571 | def _GetIsSettable(self):
|
|---|
| 1572 | return self._IsSettable
|
|---|
| 1573 |
|
|---|
| 1574 | Name = property(_GetName, doc=DynamicDocString())
|
|---|
| 1575 | DataType = property(_GetDataType, doc=DynamicDocString())
|
|---|
| 1576 | Length = property(_GetLength, doc=DynamicDocString())
|
|---|
| 1577 | Precision = property(_GetPrecision, doc=DynamicDocString())
|
|---|
| 1578 | IsNullable = property(_GetIsNullable, doc=DynamicDocString())
|
|---|
| 1579 | IsSettable = property(_GetIsSettable, doc=DynamicDocString())
|
|---|
| 1580 |
|
|---|
| 1581 | # Private properties and instance methods that the derived class
|
|---|
| 1582 | # may access but generally does not override
|
|---|
| 1583 |
|
|---|
| 1584 | def __init__(self, name, dataType, length, precision, isNullable, isSettable):
|
|---|
| 1585 | self._Name = name
|
|---|
| 1586 | self._DataType = dataType
|
|---|
| 1587 | self._Length = length
|
|---|
| 1588 | self._Precision = precision
|
|---|
| 1589 | self._IsNullable = isNullable
|
|---|
| 1590 | self._IsSettable = isSettable
|
|---|
| 1591 |
|
|---|
| 1592 |
|
|---|
| 1593 | class _Cursor(object):
|
|---|
| 1594 | __doc__ = DynamicDocString()
|
|---|
| 1595 |
|
|---|
| 1596 | # Public properties and instance methods
|
|---|
| 1597 |
|
|---|
| 1598 | def _GetTable(self):
|
|---|
| 1599 | return self._Table
|
|---|
| 1600 |
|
|---|
| 1601 | Table = property(_GetTable, doc=DynamicDocString())
|
|---|
| 1602 |
|
|---|
| 1603 | def _GetRowDescriptionSingular(self):
|
|---|
| 1604 | return self._RowDescriptionSingular
|
|---|
| 1605 |
|
|---|
| 1606 | RowDescriptionSingular = property(_GetRowDescriptionSingular, doc=DynamicDocString())
|
|---|
| 1607 |
|
|---|
| 1608 | def _GetRowDescriptionPlural(self):
|
|---|
| 1609 | return self._RowDescriptionPlural
|
|---|
| 1610 |
|
|---|
| 1611 | RowDescriptionPlural = property(_GetRowDescriptionPlural, doc=DynamicDocString())
|
|---|
| 1612 |
|
|---|
| 1613 | def _GetIsOpen(self):
|
|---|
| 1614 | return self._IsOpen
|
|---|
| 1615 |
|
|---|
| 1616 | IsOpen = property(_GetIsOpen, doc=DynamicDocString())
|
|---|
| 1617 |
|
|---|
| 1618 | def Close(self):
|
|---|
| 1619 | if hasattr(self, '_IsOpen') and self._IsOpen:
|
|---|
| 1620 | if hasattr(self, '_ProgressReporter') and self._ProgressReporter is not None and self._ProgressReporter.HasStarted and not self._ProgressReporter.HasCompleted:
|
|---|
| 1621 | self._ProgressReporter.Stop()
|
|---|
| 1622 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Closing cursor on %(dn)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dn': self._Table.DisplayName})
|
|---|
| 1623 | try:
|
|---|
| 1624 | self._Close()
|
|---|
| 1625 | except:
|
|---|
| 1626 | pass
|
|---|
| 1627 |
|
|---|
| 1628 | self._IsOpen = False
|
|---|
| 1629 |
|
|---|
| 1630 | for i, r in enumerate(_Cursor._CursorsToCloseAtExit):
|
|---|
| 1631 | if r() == self:
|
|---|
| 1632 | del _Cursor._CursorsToCloseAtExit[i]
|
|---|
| 1633 | break
|
|---|
| 1634 |
|
|---|
| 1635 | self._Table = None
|
|---|
| 1636 |
|
|---|
| 1637 | def SetRowCount(self, rowCount):
|
|---|
| 1638 | # TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 1639 |
|
|---|
| 1640 | if not self._IsOpen:
|
|---|
| 1641 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 1642 |
|
|---|
| 1643 | if hasattr(self, '_ProgressReporter') and self._ProgressReporter is not None and not self._ProgressReporter.HasCompleted:
|
|---|
| 1644 | self._ProgressReporter.TotalOperations = rowCount
|
|---|
| 1645 |
|
|---|
| 1646 | # The rest of the methods of this class are private and are not
|
|---|
| 1647 | # intended to be invoked by external callers.
|
|---|
| 1648 |
|
|---|
| 1649 | def __init__(self, table, rowDescriptionSingular, rowDescriptionPlural):
|
|---|
| 1650 | self._Table = table
|
|---|
| 1651 | self._IsOpen = False
|
|---|
| 1652 |
|
|---|
| 1653 | if rowDescriptionSingular is None and rowDescriptionPlural is None:
|
|---|
| 1654 | if self._Table.GeometryType in ['Point', 'Point25D']:
|
|---|
| 1655 | self._RowDescriptionSingular = _(u'point')
|
|---|
| 1656 | self._RowDescriptionPlural = _(u'points')
|
|---|
| 1657 | elif self._Table.GeometryType in ['LineString', 'LineString25D', 'MultiLineString', 'MultiLineString25D']:
|
|---|
| 1658 | self._RowDescriptionSingular = _(u'line')
|
|---|
| 1659 | self._RowDescriptionPlural = _(u'lines')
|
|---|
| 1660 | elif self._Table.GeometryType in ['Polygon', 'Polygon25D', 'MultiPolygon', 'MultiPolygon25D']:
|
|---|
| 1661 | self._RowDescriptionSingular = _(u'polygon')
|
|---|
| 1662 | self._RowDescriptionPlural = _(u'polygons')
|
|---|
| 1663 | elif self._Table.GeometryType in ['MultiPoint', 'MultiPoint25D']:
|
|---|
| 1664 | self._RowDescriptionSingular = _(u'multipoint')
|
|---|
| 1665 | self._RowDescriptionPlural = _(u'multipoints')
|
|---|
| 1666 | elif self._Table.GeometryType in ['GeometryCollection', 'GeometryCollection25D']:
|
|---|
| 1667 | self._RowDescriptionSingular = _(u'geometry collection')
|
|---|
| 1668 | self._RowDescriptionPlural = _(u'geometry collections')
|
|---|
| 1669 | else:
|
|---|
| 1670 | self._RowDescriptionSingular = _(u'row')
|
|---|
| 1671 | self._RowDescriptionPlural = _(u'rows')
|
|---|
| 1672 | else:
|
|---|
| 1673 | self._RowDescriptionSingular = rowDescriptionSingular
|
|---|
| 1674 | self._RowDescriptionPlural = rowDescriptionPlural
|
|---|
| 1675 |
|
|---|
| 1676 | def __del__(self):
|
|---|
| 1677 | self.Close()
|
|---|
| 1678 |
|
|---|
| 1679 | def _Close(self): # If the derived class overrides _Close(), it should call the base class at the end of its implementation.
|
|---|
| 1680 | pass
|
|---|
| 1681 |
|
|---|
| 1682 | def _SetValue_Base(self, field, value, requestedFields=None):
|
|---|
| 1683 |
|
|---|
| 1684 | if not self._IsOpen:
|
|---|
| 1685 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 1686 |
|
|---|
| 1687 | # Validate that field exists and that it is not the OID or
|
|---|
| 1688 | # geometry field.
|
|---|
| 1689 |
|
|---|
| 1690 | if not isinstance(field, basestring):
|
|---|
| 1691 | raise TypeError(_(u'The field parameter must be a string.'))
|
|---|
| 1692 |
|
|---|
| 1693 | f = self._Table.GetFieldByName(field)
|
|---|
| 1694 | if f is None:
|
|---|
| 1695 | raise RuntimeError(_(u'Cannot set the value of the "%(field)s" field of this %(singular)s of %(dn)s to %(value)s because the field does not exist.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': field, u'value': repr(value)})
|
|---|
| 1696 |
|
|---|
| 1697 | if requestedFields is not None and f.Name not in requestedFields:
|
|---|
| 1698 | raise RuntimeError(_(u'Cannot retrieve the value of the %(field)s field of this %(singular)s of %(dn)s. The field exists but was not included in the list of requested fields when the cursor was opened.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name})
|
|---|
| 1699 |
|
|---|
| 1700 | if f.Name == self._Table.OIDFieldName:
|
|---|
| 1701 | raise RuntimeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because that field is the object ID (OID) or feature ID (FID) field, which is read-only.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value)})
|
|---|
| 1702 |
|
|---|
| 1703 | if f.Name == self._Table.GeometryFieldName:
|
|---|
| 1704 | raise RuntimeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because that field is the geometry field. To set the geometry field, call SetGeometry() rather than SetValue().') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value)})
|
|---|
| 1705 |
|
|---|
| 1706 | # Validate that the field is settable. Non-settable fields are
|
|---|
| 1707 | # those managed by the underlying data format or programming
|
|---|
| 1708 | # library. These include the OID field (which is handled
|
|---|
| 1709 | # above) as well as the ArcGIS SHAPE_Length and SHAPE_Area
|
|---|
| 1710 | # fields, which are set by ArcGIS.
|
|---|
| 1711 |
|
|---|
| 1712 | if not f.IsSettable:
|
|---|
| 1713 | raise RuntimeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because that field is read-only; its values are managed by the underlying data format.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value)})
|
|---|
| 1714 |
|
|---|
| 1715 | # If the caller is trying to set the field to null, validate
|
|---|
| 1716 | # that the field is nullable.
|
|---|
| 1717 |
|
|---|
| 1718 | if value is None:
|
|---|
| 1719 | if not f.IsNullable:
|
|---|
| 1720 | raise RuntimeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to None because that field is not nullable. You must provide a value for that field.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name})
|
|---|
| 1721 |
|
|---|
| 1722 | # Otherwise, validate that the value's data type matches that
|
|---|
| 1723 | # of the field, that it is within an acceptable range, etc.
|
|---|
| 1724 |
|
|---|
| 1725 | else:
|
|---|
| 1726 | if f.DataType == u'int16' or f.DataType == u'int32':
|
|---|
| 1727 | if not isinstance(value, (types.IntType, types.LongType)):
|
|---|
| 1728 | raise TypeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because the data type of that field is %(dt)s. To set %(dt)s fields, you must provide an instance of %(type1)s or %(type2)s.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value), u'dt': f.DataType, u'type1': unicode(types.IntType), u'type2': unicode(types.LongType)})
|
|---|
| 1729 | if f.DataType == u'int16' and (value < -32768 or value > 32767):
|
|---|
| 1730 | raise ValueError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because that value is outside of the allowed range of values for the field (-32768 to 32767).') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value)})
|
|---|
| 1731 | if f.DataType == u'int32' and (value < -2147483648 or value > 2147483647):
|
|---|
| 1732 | raise ValueError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because that value is outside of the allowed range of values for the field (-2147483648 to 2147483647).') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value)})
|
|---|
| 1733 | value = int(value)
|
|---|
| 1734 |
|
|---|
| 1735 | elif f.DataType == u'float32' or f.DataType == u'float64':
|
|---|
| 1736 | if not isinstance(value, types.FloatType):
|
|---|
| 1737 | raise TypeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because the data type of that field is %(dt)s. To set %(dt)s fields, you must provide an instance of %(type)s.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value), u'dt': f.DataType, u'type': unicode(types.FloatType)})
|
|---|
| 1738 |
|
|---|
| 1739 | # I'm not doing a range check on float32 because it is
|
|---|
| 1740 | # too complicated to implement correctly and it seems
|
|---|
| 1741 | # unlikely that anyone would exceed the range of
|
|---|
| 1742 | # float32 in normal circumstances. If they do, the
|
|---|
| 1743 | # underlying programming library will hopefully catch
|
|---|
| 1744 | # the problem.
|
|---|
| 1745 |
|
|---|
| 1746 | elif f.DataType == u'string':
|
|---|
| 1747 | if not isinstance(value, basestring):
|
|---|
| 1748 | raise TypeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because the data type of that field is %(dt)s. To set %(dt)s fields, you must provide an instance of %(type1)s or %(type2)s.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value), u'dt': f.DataType, u'type1': unicode(types.StringType), u'type2': unicode(types.UnicodeType)})
|
|---|
| 1749 | if f.Length is not None and len(value) > f.Length:
|
|---|
| 1750 | raise TypeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because the length of that string (%(len1)i) exceeds the maximum allowed by the field (%(len2)i).') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value), u'len1': len(value), u'len2': f.Length})
|
|---|
| 1751 |
|
|---|
| 1752 | elif f.DataType == u'date' or f.DataType == u'datetime':
|
|---|
| 1753 | if not isinstance(value, (datetime.date, datetime.datetime)):
|
|---|
| 1754 | raise TypeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because the data type of that field is %(dt)s. To set %(dt)s fields, you must provide an instance of %(type1)s or %(type2)s.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value), u'dt': f.DataType, u'type1': unicode(datetime.date), u'type2': unicode(datetime.datetime)})
|
|---|
| 1755 |
|
|---|
| 1756 | elif f.DataType == u'binary':
|
|---|
| 1757 | if not isinstance(value, types.StringType):
|
|---|
| 1758 | raise TypeError(_(u'Cannot set the value of the %(field)s field of this %(singular)s of %(dn)s to %(value)s because the data type of that field is binary. To set binary fields, you must provide an instance of %(type)s.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name, u'value': repr(value), u'type': unicode(types.StringType)})
|
|---|
| 1759 |
|
|---|
| 1760 | # Set the field.
|
|---|
| 1761 |
|
|---|
| 1762 | if Dataset._DebugLoggingEnabled():
|
|---|
| 1763 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Setting field %(field)s to %(value)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'field': f.Name, u'value': repr(value)})
|
|---|
| 1764 |
|
|---|
| 1765 | try:
|
|---|
| 1766 | self._SetValue(field, value)
|
|---|
| 1767 | except Exception, e:
|
|---|
| 1768 | raise RuntimeError(_(u'Failed to set the value of the %(field)s field of a %(singular)s from %(dn)s to %(value)s due to %(e)s: %(msg)s') % {u'field': f.Name, u'value': repr(value), u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 1769 |
|
|---|
| 1770 | def _SetGeometry_Base(self, geometry, requestedFields=None):
|
|---|
| 1771 |
|
|---|
| 1772 | if not self._IsOpen:
|
|---|
| 1773 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 1774 |
|
|---|
| 1775 | # Validate that the dataset has geometry and that the caller's
|
|---|
| 1776 | # geometry type matches the dataset's geometry type.
|
|---|
| 1777 |
|
|---|
| 1778 | if self._Table.GeometryType is None:
|
|---|
| 1779 | raise RuntimeError(_(u'Cannot set the geometry of this %(singular)s of %(dn)s because the %(singular)s does not have geometry.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName})
|
|---|
| 1780 |
|
|---|
| 1781 | if requestedFields is not None and self._Table.GeometryFieldName is not None and self._Table.GeometryFieldName not in requestedFields:
|
|---|
| 1782 | raise RuntimeError(_(u'Cannot retrieve the geometry of this %(singular)s of %(dn)s. The %(singular)s has geometry but the geometry field (%(field)s) was not included in the list of requested fields when the cursor was opened.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': self._Table.GeometryFieldName})
|
|---|
| 1783 |
|
|---|
| 1784 | if geometry is None:
|
|---|
| 1785 | raise ValueError(_(u'Cannot set the geometry of this %(singular)s of %(dn)s to None because null geometries are not supported.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName})
|
|---|
| 1786 |
|
|---|
| 1787 | if not hasattr(geometry, '__class__') or geometry.__class__.__name__ != 'Geometry': # Test by name rather than isinstance to allow caller to pass in Geometry instances allocated by their own OGR module rather than MGET's assimilated copy
|
|---|
| 1788 | raise TypeError(_(u'The geometry parameter must be an instance of the OGR Geometry class.'))
|
|---|
| 1789 |
|
|---|
| 1790 | Dataset._ogr()
|
|---|
| 1791 | if geometry.GetGeometryType() not in Dataset._GeometryTypeForOGRGeometry:
|
|---|
| 1792 | raise ValueError(_(u'Cannot set the geometry of this %(singular)s of %(dn)s because the provided Geometry object has the geometry type %(gt)i ("%(gtname)s"), which is not currently supported.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'gt': geometry.GetGeometryType(), u'gtname': geometry.GetGeometryName()})
|
|---|
| 1793 |
|
|---|
| 1794 | geometryType = Dataset._GeometryTypeForOGRGeometry[geometry.GetGeometryType()]
|
|---|
| 1795 | if geometryType != self._Table.GeometryType:
|
|---|
| 1796 | if self._Table.GeometryType in [u'Point', u'LineString', u'Polygon', u'Point25D', u'LineString25D', u'Polygon25D']:
|
|---|
| 1797 | raise ValueError(_(u'Cannot set the geometry of this %(singular)s of %(dn)s because the provided Geometry object has the incompatible geometry type %(gt1)s. The Geometry object must have a geometry type of %(gt2)s.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'gt1': geometryType, u'gt2': self._Table.GeometryType})
|
|---|
| 1798 | elif self._Table.GeometryType.startswith(u'Multi') and geometryType != self._Table.GeometryType[5:]:
|
|---|
| 1799 | raise ValueError(_(u'Cannot set the geometry of this %(singular)s of %(dn)s because the provided Geometry object has the incompatible geometry type %(gt1)s. The Geometry object must have a geometry type of %(gt2)s or %(gt3)s.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'gt1': geometryType, u'gt2': self._Table.GeometryType[5:], u'gt3': self._Table.GeometryType})
|
|---|
| 1800 | elif self._Table.GeometryType == u'GeometryCollection' and geometryType.endswith(u'25D'):
|
|---|
| 1801 | raise ValueError(_(u'Cannot set the geometry of this %(singular)s of %(dn)s because the provided Geometry object has Z coordinates but the dataset does not.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName})
|
|---|
| 1802 | elif self._Table.GeometryType == u'GeometryCollection25D' and not geometryType.endswith(u'25D'):
|
|---|
| 1803 | raise ValueError(_(u'Cannot set the geometry of this %(singular)s of %(dn)s because the provided Geometry object does not have Z coordinates but the dataset requires them.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName})
|
|---|
| 1804 |
|
|---|
| 1805 | # Set the geometry.
|
|---|
| 1806 |
|
|---|
| 1807 | if Dataset._DebugLoggingEnabled():
|
|---|
| 1808 | wkt = geometry.ExportToWkt()
|
|---|
| 1809 | if len(wkt) > 256:
|
|---|
| 1810 | wkt = wkt[:256] + '...'
|
|---|
| 1811 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Setting geometry to WKT "%(wkt)s".'), {u'class': self.__class__.__name__, u'id': id(self), u'wkt': wkt})
|
|---|
| 1812 |
|
|---|
| 1813 | try:
|
|---|
| 1814 | self._SetGeometry(geometry)
|
|---|
| 1815 | except Exception, e:
|
|---|
| 1816 | wkt = geometry.ExportToWkt()
|
|---|
| 1817 | if len(wkt) > 256:
|
|---|
| 1818 | wkt = wkt[:256] + '...'
|
|---|
| 1819 | raise RuntimeError(_(u'Failed to set the geometry of a %(singular)s from %(dn)s to the equivalent of WKT "%(wkt)s" due to %(e)s: %(msg)s') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'wkt': wkt, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 1820 |
|
|---|
| 1821 | @staticmethod
|
|---|
| 1822 | def _CloseCursorsAtExit():
|
|---|
| 1823 | if hasattr(_Cursor, '_CursorsToCloseAtExit'):
|
|---|
| 1824 | while len(_Cursor._CursorsToCloseAtExit) > 0:
|
|---|
| 1825 | if _Cursor._CursorsToCloseAtExit[0]() is None: # Should never happen because _Cursor.__del__() removes the object from the list
|
|---|
| 1826 | del _Cursor._CursorsToCloseAtExit[0]
|
|---|
| 1827 | else:
|
|---|
| 1828 | _Cursor._CursorsToCloseAtExit[0]().Close() # This will remove it from the list.
|
|---|
| 1829 |
|
|---|
| 1830 | atexit.register(_Cursor._CloseCursorsAtExit)
|
|---|
| 1831 |
|
|---|
| 1832 |
|
|---|
| 1833 | class SelectCursor(_Cursor):
|
|---|
| 1834 | __doc__ = DynamicDocString()
|
|---|
| 1835 |
|
|---|
| 1836 | # Public properties and instance methods
|
|---|
| 1837 |
|
|---|
| 1838 | def _GetAtEnd(self):
|
|---|
| 1839 | return bool(self._AtEnd)
|
|---|
| 1840 |
|
|---|
| 1841 | AtEnd = property(_GetAtEnd, doc=DynamicDocString())
|
|---|
| 1842 |
|
|---|
| 1843 | def NextRow(self):
|
|---|
| 1844 | if self._AtEnd:
|
|---|
| 1845 | raise IndexError(_(u'The last %(singular)s has already been retrieved.') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 1846 |
|
|---|
| 1847 | if not self._IsOpen:
|
|---|
| 1848 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 1849 |
|
|---|
| 1850 | if Dataset._DebugLoggingEnabled():
|
|---|
| 1851 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Retrieving a %(singular)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'singular': self._RowDescriptionSingular})
|
|---|
| 1852 |
|
|---|
| 1853 | try:
|
|---|
| 1854 | rowAvailable = self._NextRow()
|
|---|
| 1855 | except Exception, e:
|
|---|
| 1856 | raise RuntimeError(_(u'Failed to retrieve a %(singular)s from %(dn)s due to %(e)s: %(msg)s') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 1857 |
|
|---|
| 1858 | if rowAvailable:
|
|---|
| 1859 | self._AtEnd = False
|
|---|
| 1860 | if self._ProgressReporter is not None:
|
|---|
| 1861 | self._ProgressReporter.ReportProgress()
|
|---|
| 1862 | else:
|
|---|
| 1863 | self._AtEnd = True
|
|---|
| 1864 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: No more %(plural)s available.'), {u'class': self.__class__.__name__, u'id': id(self), u'plural': self._RowDescriptionPlural})
|
|---|
| 1865 | self.Close()
|
|---|
| 1866 |
|
|---|
| 1867 | return rowAvailable
|
|---|
| 1868 |
|
|---|
| 1869 | def GetValue(self, field):
|
|---|
| 1870 |
|
|---|
| 1871 | # Validate that a row has been retrieved and that we're not at
|
|---|
| 1872 | # the end.
|
|---|
| 1873 |
|
|---|
| 1874 | if self._IsOpen and self._AtEnd is None:
|
|---|
| 1875 | raise RuntimeError(_(u'The first %(singular)s has not been retrieved yet. Call NextRow() before calling GetValue().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 1876 |
|
|---|
| 1877 | if self._AtEnd:
|
|---|
| 1878 | raise RuntimeError(_(u'All of the %(plural)s have already been retrieved. Do not call GetValue() after NextRow() has returned False.') % {u'plural': self._RowDescriptionPlural})
|
|---|
| 1879 |
|
|---|
| 1880 | if not self._IsOpen:
|
|---|
| 1881 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 1882 |
|
|---|
| 1883 | # Validate that the field exists and that the caller requested
|
|---|
| 1884 | # it when opening the cursor.
|
|---|
| 1885 |
|
|---|
| 1886 | if not isinstance(field, basestring):
|
|---|
| 1887 | raise TypeError(_(u'The field parameter must be a string.'))
|
|---|
| 1888 |
|
|---|
| 1889 | f = self._Table.GetFieldByName(field)
|
|---|
| 1890 | if f is None:
|
|---|
| 1891 | raise RuntimeError(_(u'Cannot retrieve the value of field "%(field)s" of this %(singular)s of %(dn)s because the field does not exist.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': field})
|
|---|
| 1892 |
|
|---|
| 1893 | if self._RequestedFields is not None and f.Name not in self._RequestedFields:
|
|---|
| 1894 | raise RuntimeError(_(u'Cannot retrieve the value of the %(field)s field of this %(singular)s of %(dn)s. The field exists but was not included in the list of requested fields when the cursor was opened.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name})
|
|---|
| 1895 |
|
|---|
| 1896 | # Validate that it is not the geometry field.
|
|---|
| 1897 |
|
|---|
| 1898 | if f.Name == self._Table.GeometryFieldName:
|
|---|
| 1899 | raise RuntimeError(_(u'Cannot retrieve the value of the %(field)s field of this %(singular)s of %(dn)s because that field is the geometry field. To get the geometry field, call GetGeometry() rather than GetValue().') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name})
|
|---|
| 1900 |
|
|---|
| 1901 | # Get and return the value of the field.
|
|---|
| 1902 |
|
|---|
| 1903 | try:
|
|---|
| 1904 | value = self._GetValue(field)
|
|---|
| 1905 | except Exception, e:
|
|---|
| 1906 | raise RuntimeError(_(u'Failed to retrieve the value of the %(field)s field of a %(singular)s from %(dn)s due to %(e)s: %(msg)s') % {u'field': f.Name, u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 1907 |
|
|---|
| 1908 | if Dataset._DebugLoggingEnabled():
|
|---|
| 1909 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Get field %(field)s returned %(value)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'field': f.Name, u'value': repr(value)})
|
|---|
| 1910 |
|
|---|
| 1911 | return value
|
|---|
| 1912 |
|
|---|
| 1913 | def GetOID(self):
|
|---|
| 1914 |
|
|---|
| 1915 | # Validate that a row has been retrieved and that we're not at
|
|---|
| 1916 | # the end.
|
|---|
| 1917 |
|
|---|
| 1918 | if self._IsOpen and self._AtEnd is None:
|
|---|
| 1919 | raise RuntimeError(_(u'The first %(singular)s has not been retrieved yet. Call NextRow() before calling GetOID().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 1920 |
|
|---|
| 1921 | if self._AtEnd:
|
|---|
| 1922 | raise RuntimeError(_(u'All of the %(plural)s have already been retrieved. Do not call GetOID() after NextRow() has returned False.') % {u'plural': self._RowDescriptionPlural})
|
|---|
| 1923 |
|
|---|
| 1924 | if not self._IsOpen:
|
|---|
| 1925 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 1926 |
|
|---|
| 1927 | # Validate that the dataset has an OID, and if it has an OID
|
|---|
| 1928 | # field, that the caller requested that field when opening the
|
|---|
| 1929 | # cursor.
|
|---|
| 1930 |
|
|---|
| 1931 | if self._Table.HasOID is None:
|
|---|
| 1932 | raise RuntimeError(_(u'Cannot retrieve the object ID (OID) of this %(singular)s of %(dn)s because the %(singular)s does not have an OID.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName})
|
|---|
| 1933 |
|
|---|
| 1934 | if self._RequestedFields is not None and self._Table.OIDFieldName is not None and self._Table.OIDFieldName not in self._RequestedFields:
|
|---|
| 1935 | raise RuntimeError(_(u'Cannot retrieve the object ID (OID) of this %(singular)s of %(dn)s. The %(singular)s has an OID but the OID field (%(field)s) was not included in the list of requested fields when the cursor was opened.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': self._Table.OIDFieldName})
|
|---|
| 1936 |
|
|---|
| 1937 | # Get and return the OID.
|
|---|
| 1938 |
|
|---|
| 1939 | try:
|
|---|
| 1940 | oid = self._GetOID()
|
|---|
| 1941 | except Exception, e:
|
|---|
| 1942 | raise RuntimeError(_(u'Failed to retrieve the object ID (OID) of a %(singular)s from %(dn)s due to %(e)s: %(msg)s') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 1943 |
|
|---|
| 1944 | if Dataset._DebugLoggingEnabled():
|
|---|
| 1945 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Get OID returned "%(oid)s".'), {u'class': self.__class__.__name__, u'id': id(self), u'oid': repr(oid)})
|
|---|
| 1946 |
|
|---|
| 1947 | return oid
|
|---|
| 1948 |
|
|---|
| 1949 | def GetGeometry(self):
|
|---|
| 1950 |
|
|---|
| 1951 | # Validate that a row has been retrieved and that we're not at
|
|---|
| 1952 | # the end.
|
|---|
| 1953 |
|
|---|
| 1954 | if self._IsOpen and self._AtEnd is None:
|
|---|
| 1955 | raise RuntimeError(_(u'The first %(singular)s has not been retrieved yet. Call NextRow() before calling GetGeometry().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 1956 |
|
|---|
| 1957 | if self._AtEnd:
|
|---|
| 1958 | raise RuntimeError(_(u'All of the %(plural)s have already been retrieved. Do not call GetGeometry() after NextRow() has returned False.') % {u'plural': self._RowDescriptionPlural})
|
|---|
| 1959 |
|
|---|
| 1960 | if not self._IsOpen:
|
|---|
| 1961 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 1962 |
|
|---|
| 1963 | # Validate that the dataset has geometry, and if it has a
|
|---|
| 1964 | # geometry field, that the caller requested that field when
|
|---|
| 1965 | # opening the cursor.
|
|---|
| 1966 |
|
|---|
| 1967 | if self._Table.GeometryType is None:
|
|---|
| 1968 | raise RuntimeError(_(u'Cannot retrieve the geometry of this %(singular)s of %(dn)s because the %(singular)s does not have geometry.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName})
|
|---|
| 1969 |
|
|---|
| 1970 | if self._RequestedFields is not None and self._Table.GeometryFieldName is not None and self._Table.GeometryFieldName not in self._RequestedFields:
|
|---|
| 1971 | raise RuntimeError(_(u'Cannot retrieve the geometry of this %(singular)s of %(dn)s. The %(singular)s has geometry but the geometry field (%(field)s) was not included in the list of requested fields when the cursor was opened.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': self._Table.GeometryFieldName})
|
|---|
| 1972 |
|
|---|
| 1973 | # Get and return the geometry.
|
|---|
| 1974 |
|
|---|
| 1975 | try:
|
|---|
| 1976 | geometry = self._GetGeometry()
|
|---|
| 1977 | except Exception, e:
|
|---|
| 1978 | raise RuntimeError(_(u'Failed to retrieve the geometry of a %(singular)s from %(dn)s due to %(e)s: %(msg)s') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 1979 |
|
|---|
| 1980 | if Dataset._DebugLoggingEnabled():
|
|---|
| 1981 | wkt = geometry.ExportToWkt()
|
|---|
| 1982 | if len(wkt) > 256:
|
|---|
| 1983 | wkt = wkt[:256] + '...'
|
|---|
| 1984 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Get geometry returned WKT "%(wkt)s".'), {u'class': self.__class__.__name__, u'id': id(self), u'wkt': wkt})
|
|---|
| 1985 |
|
|---|
| 1986 | return geometry
|
|---|
| 1987 |
|
|---|
| 1988 | # Private base class constructor. Do not invoke directly; use
|
|---|
| 1989 | # Table.OpenSelectCursor instead. Do not override; put
|
|---|
| 1990 | # your initialization code the derive class's _Open method.
|
|---|
| 1991 |
|
|---|
| 1992 | def __init__(self, dataset, fields, where, orderBy, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural):
|
|---|
| 1993 |
|
|---|
| 1994 | # Initialize the base class and our attributes.
|
|---|
| 1995 |
|
|---|
| 1996 | super(SelectCursor, self).__init__(dataset, rowDescriptionSingular, rowDescriptionPlural)
|
|---|
| 1997 |
|
|---|
| 1998 | self._AtEnd = None
|
|---|
| 1999 | self._RequestedFields = None
|
|---|
| 2000 |
|
|---|
| 2001 | # Validate that the caller is requesting existing fields.
|
|---|
| 2002 |
|
|---|
| 2003 | if fields is not None:
|
|---|
| 2004 | self._RequestedFields = set()
|
|---|
| 2005 | for field in fields:
|
|---|
| 2006 | f = self._Table.GetFieldByName(field)
|
|---|
| 2007 | if f is None:
|
|---|
| 2008 | raise ValueError(_(u'Cannot retrieve field "%(field)s" of %(dn)s because the field does not exist.') % {'dn': self._Table.DisplayName, u'field': field})
|
|---|
| 2009 | self._RequestedFields.add(f.Name)
|
|---|
| 2010 | fields = list(self._RequestedFields)
|
|---|
| 2011 |
|
|---|
| 2012 | # Validate that the orderBy expression references valid fields
|
|---|
| 2013 | # and includes valid sort orders.
|
|---|
| 2014 |
|
|---|
| 2015 | if orderBy is not None:
|
|---|
| 2016 | orderByList = map(lambda s: s.strip(), orderBy.split(','))
|
|---|
| 2017 | for i in range(len(orderByList)):
|
|---|
| 2018 | parts = orderByList[i].split()
|
|---|
| 2019 | if len(parts) not in [1, 2] or len(parts) == 2 and parts[1].upper() not in ['A', 'ASC', 'ASCENDING', 'D', 'DESC', 'DESCENDING']:
|
|---|
| 2020 | raise ValueError(_(u'Cannot retrieve %(plural)s from %(dn)s using the ORDER BY expression "%(orderBy)s". The expression is invalid.') % {'plural': self._RowDescriptionPlural, u'dn': dataset.DisplayName, u'orderBy': orderBy})
|
|---|
| 2021 | f = self._Table.GetFieldByName(parts[0])
|
|---|
| 2022 | if f is None:
|
|---|
| 2023 | raise ValueError(_(u'Cannot retrieve %(plural)s from %(dn)s using the ORDER BY expression "%(orderBy)s". The expression refers to a field "%(field)s" that does not exist.') % {'plural': self._RowDescriptionPlural, u'dn': dataset.DisplayName, u'orderBy': orderBy, u'field': parts[0]})
|
|---|
| 2024 | if len(parts) == 1 or parts[1][0].upper() == 'A':
|
|---|
| 2025 | orderByList[i] = f.Name + ' ASC'
|
|---|
| 2026 | else:
|
|---|
| 2027 | orderByList[i] = f.Name + ' DESC'
|
|---|
| 2028 | orderBy = ', '.join(orderByList)
|
|---|
| 2029 |
|
|---|
| 2030 | # Call the derived class to open the cursor.
|
|---|
| 2031 |
|
|---|
| 2032 | if isinstance(self, UpdateCursor):
|
|---|
| 2033 | cursorType = _(u'update')
|
|---|
| 2034 | else:
|
|---|
| 2035 | cursorType = _(u'select')
|
|---|
| 2036 |
|
|---|
| 2037 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Opening %(curtype)s cursor on %(dn)s, fields=%(fields)s, where=%(where)s, orderBy=%(orderBy)s, rowCount=%(rc)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dn': dataset.DisplayName, u'curtype': cursorType, u'fields': repr(fields), u'where': repr(where), u'orderBy': repr(orderBy), u'rc': repr(rowCount)})
|
|---|
| 2038 | try:
|
|---|
| 2039 | self._Open(fields, where, orderBy)
|
|---|
| 2040 | except Exception, e:
|
|---|
| 2041 | self._Table = None
|
|---|
| 2042 | raise RuntimeError(_(u'Cannot retrieve %(plural)s from %(dn)s. Failed to open a %(curtype)s cursor due to %(e)s: %(msg)s') % {u'plural': self._RowDescriptionPlural, u'dn': dataset.DisplayName, u'curtype': cursorType, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 2043 |
|
|---|
| 2044 | self._IsOpen = True
|
|---|
| 2045 |
|
|---|
| 2046 | if not hasattr(_Cursor, '_CursorsToCloseAtExit'):
|
|---|
| 2047 | _Cursor._CursorsToCloseAtExit = []
|
|---|
| 2048 | _Cursor._CursorsToCloseAtExit.insert(0, weakref.ref(self))
|
|---|
| 2049 |
|
|---|
| 2050 | # If the caller wants progress to be reported, start a
|
|---|
| 2051 | # progress reporter.
|
|---|
| 2052 |
|
|---|
| 2053 | if reportProgress:
|
|---|
| 2054 | self._ProgressReporter = ProgressReporter(progressMessage1=_(u'Still retrieving %(plural)s: %%(elapsed)s elapsed, %%(opsCompleted)i %(plural)s retrieved, %%(perOp)s per %(singular)s, %%(opsRemaining)i remaining, estimated completion time: %%(etc)s.') % {u'singular': self._RowDescriptionSingular, u'plural': self._RowDescriptionPlural},
|
|---|
| 2055 | progressMessage2=_(u'Still retrieving %(plural)s: %%(elapsed)s elapsed, %%(opsCompleted)i %(plural)s retrieved, %%(perOp)s per %(singular)s.') % {u'singular': self._RowDescriptionSingular, u'plural': self._RowDescriptionPlural},
|
|---|
| 2056 | completionMessage=_(u'Finished retrieving %(plural)s: %%(elapsed)s elapsed, %%(opsCompleted)i %(plural)s retrieved, %%(perOp)s per %(singular)s.') % {u'singular': self._RowDescriptionSingular, u'plural': self._RowDescriptionPlural},
|
|---|
| 2057 | abortedMessage=_(u'Query operation stopped before all %(plural)s were retrieved: %%(elapsed)s elapsed, %%(opsCompleted)i %(plural)s retrieved, %%(perOp)s per %(singular)s, %%(opsIncomplete)i %(plural)s not retrieved.') % {u'singular': self._RowDescriptionSingular, u'plural': self._RowDescriptionPlural})
|
|---|
| 2058 | self._ProgressReporter.Start(rowCount)
|
|---|
| 2059 | else:
|
|---|
| 2060 | self._ProgressReporter = None
|
|---|
| 2061 |
|
|---|
| 2062 | # Private methods that the derived class must override (except
|
|---|
| 2063 | # _GetOID and _GetGeometry, if appropriate).
|
|---|
| 2064 |
|
|---|
| 2065 | def _Open(self, fields, where, orderBy):
|
|---|
| 2066 | raise NotImplementedError(_(u'The _Open method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2067 |
|
|---|
| 2068 | def _NextRow(self):
|
|---|
| 2069 | raise NotImplementedError(_(u'The _NextRow method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2070 |
|
|---|
| 2071 | def _GetValue(self, field):
|
|---|
| 2072 | raise NotImplementedError(_(u'The _GetValue method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2073 |
|
|---|
| 2074 | def _GetOID(self):
|
|---|
| 2075 | raise NotImplementedError(_(u'The _GetOID method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2076 |
|
|---|
| 2077 | def _GetGeometry(self):
|
|---|
| 2078 | raise NotImplementedError(_(u'The _GetGeometry method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2079 |
|
|---|
| 2080 |
|
|---|
| 2081 | class UpdateCursor(SelectCursor):
|
|---|
| 2082 | __doc__ = DynamicDocString()
|
|---|
| 2083 |
|
|---|
| 2084 | # Public properties and instance methods
|
|---|
| 2085 |
|
|---|
| 2086 | def NextRow(self):
|
|---|
| 2087 | if self._AtEnd:
|
|---|
| 2088 | raise IndexError(_(u'The last %(singular)s has already been retrieved.') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2089 |
|
|---|
| 2090 | if not self._IsOpen:
|
|---|
| 2091 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 2092 |
|
|---|
| 2093 | if self._ProgressReporter is not None and self._NeedToReportProgress:
|
|---|
| 2094 | self._ProgressReporter.ReportProgress()
|
|---|
| 2095 | self._NeedToReportProgress = False
|
|---|
| 2096 |
|
|---|
| 2097 | if Dataset._DebugLoggingEnabled():
|
|---|
| 2098 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Retrieving a %(singular)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'singular': self._RowDescriptionSingular})
|
|---|
| 2099 |
|
|---|
| 2100 | self._RowUpdatedOrDeleted = False
|
|---|
| 2101 |
|
|---|
| 2102 | try:
|
|---|
| 2103 | rowAvailable = self._NextRow()
|
|---|
| 2104 | except Exception, e:
|
|---|
| 2105 | raise RuntimeError(_(u'Failed to retrieve a %(singular)s from %(dn)s due to %(e)s: %(msg)s') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 2106 |
|
|---|
| 2107 | if rowAvailable:
|
|---|
| 2108 | self._AtEnd = False
|
|---|
| 2109 | self._NeedToReportProgress = self._ProgressReporter is not None
|
|---|
| 2110 | else:
|
|---|
| 2111 | self._AtEnd = True
|
|---|
| 2112 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: No more %(plural)s available.'), {u'class': self.__class__.__name__, u'id': id(self), u'plural': self._RowDescriptionPlural})
|
|---|
| 2113 | self.Close()
|
|---|
| 2114 |
|
|---|
| 2115 | return rowAvailable
|
|---|
| 2116 |
|
|---|
| 2117 | def GetValue(self, field):
|
|---|
| 2118 |
|
|---|
| 2119 | # Validate that we haven't updated or deleted this row yet and
|
|---|
| 2120 | # call the base class method. The base class will take care of
|
|---|
| 2121 | # the other validation.
|
|---|
| 2122 |
|
|---|
| 2123 | if self._RowUpdatedOrDeleted:
|
|---|
| 2124 | raise RuntimeError(_(u'This %(singular)s has already been updated or deleted. Do not call GetValue() after calling UpdateRow() or DeleteRow(). Call NextRow() after calling UpdateRow() or DeleteRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2125 |
|
|---|
| 2126 | return super(UpdateCursor, self).GetValue(field)
|
|---|
| 2127 |
|
|---|
| 2128 | def GetOID(self):
|
|---|
| 2129 |
|
|---|
| 2130 | # Validate that we haven't updated or deleted this row yet and
|
|---|
| 2131 | # call the base class method. The base class will take care of
|
|---|
| 2132 | # the other validation.
|
|---|
| 2133 |
|
|---|
| 2134 | if self._RowUpdatedOrDeleted:
|
|---|
| 2135 | raise RuntimeError(_(u'This %(singular)s has already been updated or deleted. Do not call GetOID() after calling UpdateRow() or DeleteRow(). Call NextRow() after calling UpdateRow() or DeleteRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2136 |
|
|---|
| 2137 | return super(UpdateCursor, self).GetOID()
|
|---|
| 2138 |
|
|---|
| 2139 | def GetGeometry(self):
|
|---|
| 2140 |
|
|---|
| 2141 | # Validate that we haven't updated or deleted this row yet and
|
|---|
| 2142 | # call the base class method. The base class will take care of
|
|---|
| 2143 | # the other validation.
|
|---|
| 2144 |
|
|---|
| 2145 | if self._RowUpdatedOrDeleted:
|
|---|
| 2146 | raise RuntimeError(_(u'This %(singular)s has already been updated or deleted. Do not call GetGeometry() after calling UpdateRow() or DeleteRow(). Call NextRow() after calling UpdateRow() or DeleteRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2147 |
|
|---|
| 2148 | return super(UpdateCursor, self).GetGeometry()
|
|---|
| 2149 |
|
|---|
| 2150 | def SetValue(self, field, value):
|
|---|
| 2151 |
|
|---|
| 2152 | # Validate that a row has been retrieved, that we're not at
|
|---|
| 2153 | # the end, and that we haven't updated or deleted this row
|
|---|
| 2154 | # yet.
|
|---|
| 2155 |
|
|---|
| 2156 | if self._IsOpen and self._AtEnd is None:
|
|---|
| 2157 | raise RuntimeError(_(u'The first %(singular)s has not been retrieved yet. Call NextRow() before calling SetValue().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2158 |
|
|---|
| 2159 | if self._AtEnd:
|
|---|
| 2160 | raise RuntimeError(_(u'All of the %(plural)s have already been retrieved. Do not call SetValue() after NextRow() has returned False.') % {u'plural': self._RowDescriptionPlural})
|
|---|
| 2161 |
|
|---|
| 2162 | if not self._IsOpen:
|
|---|
| 2163 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 2164 |
|
|---|
| 2165 | if self._RowUpdatedOrDeleted:
|
|---|
| 2166 | raise RuntimeError(_(u'This %(singular)s has already been updated or deleted. Do not call SetValue() after calling UpdateRow() or DeleteRow(). Call NextRow() after calling UpdateRow() or DeleteRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2167 |
|
|---|
| 2168 | # Set the field.
|
|---|
| 2169 |
|
|---|
| 2170 | self._SetValue_Base(field, value, self._RequestedFields)
|
|---|
| 2171 |
|
|---|
| 2172 | def SetGeometry(self, geometry):
|
|---|
| 2173 |
|
|---|
| 2174 | # Validate that a row has been retrieved, that we're not at
|
|---|
| 2175 | # the end, and that we haven't updated or deleted this row
|
|---|
| 2176 | # yet.
|
|---|
| 2177 |
|
|---|
| 2178 | if self._IsOpen and self._AtEnd is None:
|
|---|
| 2179 | raise RuntimeError(_(u'The first %(singular)s has not been retrieved yet. Call NextRow() before calling SetGeometry().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2180 |
|
|---|
| 2181 | if self._AtEnd:
|
|---|
| 2182 | raise RuntimeError(_(u'All of the %(plural)s have already been retrieved. Do not call SetGeometry() after NextRow() has returned False.') % {u'plural': self._RowDescriptionPlural})
|
|---|
| 2183 |
|
|---|
| 2184 | if not self._IsOpen:
|
|---|
| 2185 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 2186 |
|
|---|
| 2187 | if self._RowUpdatedOrDeleted:
|
|---|
| 2188 | raise RuntimeError(_(u'This %(singular)s has already been updated or deleted. Do not call SetGeometry() after calling UpdateRow() or DeleteRow(). Call NextRow() after calling UpdateRow() or DeleteRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2189 |
|
|---|
| 2190 | # Set the geometry.
|
|---|
| 2191 |
|
|---|
| 2192 | self._SetGeometry_Base(geometry, self._RequestedFields)
|
|---|
| 2193 |
|
|---|
| 2194 | def UpdateRow(self):
|
|---|
| 2195 |
|
|---|
| 2196 | # Validate that this dataset supports row updating, that a row
|
|---|
| 2197 | # has been retrieved, that we're not at the end, and that we
|
|---|
| 2198 | # haven't updated or deleted this row yet.
|
|---|
| 2199 |
|
|---|
| 2200 | if self._UpdateRowCapabilityError is not None:
|
|---|
| 2201 | raise self._UpdateRowCapabilityError
|
|---|
| 2202 |
|
|---|
| 2203 | if self._IsOpen and self._AtEnd is None:
|
|---|
| 2204 | raise RuntimeError(_(u'The first %(singular)s has not been retrieved yet. Call NextRow() before calling UpdateRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2205 |
|
|---|
| 2206 | if self._AtEnd:
|
|---|
| 2207 | raise RuntimeError(_(u'All of the %(plural)s have already been retrieved. Do not call UpdateRow() after NextRow() has returned False.') % {u'plural': self._RowDescriptionPlural})
|
|---|
| 2208 |
|
|---|
| 2209 | if not self._IsOpen:
|
|---|
| 2210 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 2211 |
|
|---|
| 2212 | if self._RowUpdatedOrDeleted:
|
|---|
| 2213 | raise RuntimeError(_(u'This %(singular)s has already been updated or deleted. Do not call UpdateRow() after calling UpdateRow() or DeleteRow(). Call NextRow() after calling UpdateRow() or DeleteRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2214 |
|
|---|
| 2215 | # Update the row and report progress.
|
|---|
| 2216 |
|
|---|
| 2217 | if Dataset._DebugLoggingEnabled():
|
|---|
| 2218 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Updating this %(singular)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'singular': self._RowDescriptionSingular})
|
|---|
| 2219 |
|
|---|
| 2220 | try:
|
|---|
| 2221 | self._UpdateRow()
|
|---|
| 2222 | except Exception, e:
|
|---|
| 2223 | raise RuntimeError(_(u'Failed to update a %(singular)s in %(dn)s due to %(e)s: %(msg)s') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 2224 |
|
|---|
| 2225 | self._RowUpdatedOrDeleted = True
|
|---|
| 2226 | self._ProgressReporter.RowsUpdated += 1
|
|---|
| 2227 | if self._ProgressReporter is not None:
|
|---|
| 2228 | self._ProgressReporter.ReportProgress()
|
|---|
| 2229 | self._NeedToReportProgress = False
|
|---|
| 2230 |
|
|---|
| 2231 | def DeleteRow(self):
|
|---|
| 2232 |
|
|---|
| 2233 | # Validate that this dataset supports row deletion, that a row
|
|---|
| 2234 | # has been retrieved, that we're not at the end, and that we
|
|---|
| 2235 | # haven't updated or deleted this row yet.
|
|---|
| 2236 |
|
|---|
| 2237 | if self._DeleteRowCapabilityError is not None:
|
|---|
| 2238 | raise self._DeleteRowCapabilityError
|
|---|
| 2239 |
|
|---|
| 2240 | if self._IsOpen and self._AtEnd is None:
|
|---|
| 2241 | raise RuntimeError(_(u'The first %(singular)s has not been retrieved yet. Call NextRow() before calling DeleteRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2242 |
|
|---|
| 2243 | if self._AtEnd:
|
|---|
| 2244 | raise RuntimeError(_(u'All of the %(plural)s have already been retrieved. Do not call DeleteRow() after NextRow() has returned False.') % {u'plural': self._RowDescriptionPlural})
|
|---|
| 2245 |
|
|---|
| 2246 | if not self._IsOpen:
|
|---|
| 2247 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 2248 |
|
|---|
| 2249 | if self._RowUpdatedOrDeleted:
|
|---|
| 2250 | raise RuntimeError(_(u'This %(singular)s has already been updated or deleted. Do not call DeleteRow() after calling UpdateRow() or DeleteRow(). Call NextRow() after calling UpdateRow() or DeleteRow().') % {u'singular': self._RowDescriptionSingular})
|
|---|
| 2251 |
|
|---|
| 2252 | # Update the row and report progress.
|
|---|
| 2253 |
|
|---|
| 2254 | if Dataset._DebugLoggingEnabled():
|
|---|
| 2255 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Deleting this %(singular)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'singular': self._RowDescriptionSingular})
|
|---|
| 2256 |
|
|---|
| 2257 | try:
|
|---|
| 2258 | self._DeleteRow()
|
|---|
| 2259 | except Exception, e:
|
|---|
| 2260 | raise RuntimeError(_(u'Failed to delete a %(singular)s from %(dn)s due to %(e)s: %(msg)s') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 2261 |
|
|---|
| 2262 | self._RowUpdatedOrDeleted = True
|
|---|
| 2263 | self._ProgressReporter.RowsDeleted += 1
|
|---|
| 2264 | if self._ProgressReporter is not None:
|
|---|
| 2265 | self._ProgressReporter.ReportProgress()
|
|---|
| 2266 | self._NeedToReportProgress = False
|
|---|
| 2267 |
|
|---|
| 2268 | # Private base class constructor. Do not invoke directly; use
|
|---|
| 2269 | # Table.OpenUpdateCursor instead. Do not override; put
|
|---|
| 2270 | # your initialization code the derive class's _Open method.
|
|---|
| 2271 |
|
|---|
| 2272 | def __init__(self, dataset, fields, where, orderBy, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural):
|
|---|
| 2273 | super(UpdateCursor, self).__init__(dataset, fields, where, orderBy, rowCount, False, rowDescriptionSingular, rowDescriptionPlural)
|
|---|
| 2274 |
|
|---|
| 2275 | self._UpdateRowCapabilityError = self._Table._TestCapability('updaterow')
|
|---|
| 2276 | self._DeleteRowCapabilityError = self._Table._TestCapability('deleterow')
|
|---|
| 2277 | self._RowUpdatedOrDeleted = False
|
|---|
| 2278 | self._NeedToReportProgress = False
|
|---|
| 2279 |
|
|---|
| 2280 | if reportProgress:
|
|---|
| 2281 | self._ProgressReporter = _UpdateCursorProgressReporter(self._RowDescriptionSingular, self._RowDescriptionPlural)
|
|---|
| 2282 | self._ProgressReporter.Start(rowCount)
|
|---|
| 2283 |
|
|---|
| 2284 | # Private methods that the derived class must override (except
|
|---|
| 2285 | # _SetGeometry when the derived class does not support geometry).
|
|---|
| 2286 | # These are in addition to those defined by SelectCursor.
|
|---|
| 2287 |
|
|---|
| 2288 | def _Close(self): # Be sure to call the base class from the derived class's implementation!
|
|---|
| 2289 | try:
|
|---|
| 2290 | if hasattr(self, '_ProgressReporter') and self._ProgressReporter is not None and hasattr(self, '_NeedToReportProgress') and self._NeedToReportProgress:
|
|---|
| 2291 | self._ProgressReporter.ReportProgress()
|
|---|
| 2292 | self._NeedToReportProgress = False
|
|---|
| 2293 | finally:
|
|---|
| 2294 | super(UpdateCursor, self)._Close()
|
|---|
| 2295 |
|
|---|
| 2296 | def _SetValue(self, field, value):
|
|---|
| 2297 | raise NotImplementedError(_(u'The _SetValue method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2298 |
|
|---|
| 2299 | def _SetGeometry(self, geometry):
|
|---|
| 2300 | raise NotImplementedError(_(u'The _SetGeometry method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2301 |
|
|---|
| 2302 | def _UpdateRow(self):
|
|---|
| 2303 | raise NotImplementedError(_(u'The _UpdateRow method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2304 |
|
|---|
| 2305 | def _DeleteRow(self):
|
|---|
| 2306 | raise NotImplementedError(_(u'The _DeleteRow method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2307 |
|
|---|
| 2308 |
|
|---|
| 2309 | class _UpdateCursorProgressReporter(ProgressReporter):
|
|---|
| 2310 |
|
|---|
| 2311 | def __init__(self, rowDescriptionSingular, rowDescriptionPlural):
|
|---|
| 2312 | self.RowsUpdated = 0
|
|---|
| 2313 | self.RowsDeleted = 0
|
|---|
| 2314 | super(_UpdateCursorProgressReporter, self).__init__(
|
|---|
| 2315 | progressMessage1=_(u'Update in progress: %%(elapsed)s elapsed, %%(updated)i %(plural)s updated, %%(deleted)i deleted, %%(unchanged)i unchanged, %%(perOp)s per %(singular)s, %%(opsRemaining)i remaining, estimated completion time: %%(etc)s.') % {u'singular': rowDescriptionSingular, u'plural': rowDescriptionPlural},
|
|---|
| 2316 | progressMessage2=_(u'Update in progress: %%(elapsed)s elapsed, %%(updated)i %(plural)s updated, %%(deleted)i deleted, %%(unchanged)i unchanged, %%(perOp)s per %(singular)s.') % {u'singular': rowDescriptionSingular, u'plural': rowDescriptionPlural},
|
|---|
| 2317 | completionMessage=_(u'Update complete: %%(elapsed)s elapsed, %%(updated)i %(plural)s updated, %%(deleted)i deleted, %%(unchanged)i unchanged, %%(perOp)s per %(singular)s.') % {u'singular': rowDescriptionSingular, u'plural': rowDescriptionPlural},
|
|---|
| 2318 | abortedMessage=_(u'Update stopped before all %(plural)s were processed: %%(elapsed)s elapsed, %%(updated)i %(plural)s updated, %%(deleted)i deleted, %%(unchanged)i unchanged, %%(perOp)s per %(singular)s, %%(opsIncomplete)i %(plural)s not processed.') % {u'singular': rowDescriptionSingular, u'plural': rowDescriptionPlural})
|
|---|
| 2319 |
|
|---|
| 2320 | def _FormatProgressMessage1(self, timeElapsed, opsCompleted, timePerOp, opsRemaining, estimatedTimeOfCompletionString):
|
|---|
| 2321 | return self._ProgressMessage1 % {u'elapsed' : unicode(datetime.timedelta(days=timeElapsed.days, seconds=timeElapsed.seconds)), u'updated': self.RowsUpdated, u'deleted': self.RowsDeleted, u'unchanged': opsCompleted - self.RowsUpdated - self.RowsDeleted, u'perOp': unicode(timePerOp), u'opsRemaining': opsRemaining, u'etc': estimatedTimeOfCompletionString}
|
|---|
| 2322 |
|
|---|
| 2323 | def _FormatProgressMessage2(self, timeElapsed, opsCompleted, timePerOp):
|
|---|
| 2324 | return self._ProgressMessage2 % {u'elapsed' : unicode(datetime.timedelta(days=timeElapsed.days, seconds=timeElapsed.seconds)), u'updated': self.RowsUpdated, u'deleted': self.RowsDeleted, u'unchanged': opsCompleted - self.RowsUpdated - self.RowsDeleted, u'perOp': unicode(timePerOp)}
|
|---|
| 2325 |
|
|---|
| 2326 | def _FormatCompletionMessage(self, timeElapsed, opsCompleted, timePerOp):
|
|---|
| 2327 | return self._CompletionMessage % {u'elapsed' : unicode(datetime.timedelta(days=timeElapsed.days, seconds=timeElapsed.seconds)), u'updated': self.RowsUpdated, u'deleted': self.RowsDeleted, u'unchanged': opsCompleted - self.RowsUpdated - self.RowsDeleted, u'perOp': unicode(timePerOp)}
|
|---|
| 2328 |
|
|---|
| 2329 | def _FormatAbortedMessage(self, timeElapsed, opsCompleted, timePerOp, opsIncomplete):
|
|---|
| 2330 | return self._AbortedMessage % {u'elapsed' : unicode(datetime.timedelta(days=timeElapsed.days, seconds=timeElapsed.seconds)), u'updated': self.RowsUpdated, u'deleted': self.RowsDeleted, u'unchanged': opsCompleted - self.RowsUpdated - self.RowsDeleted, u'perOp': unicode(timePerOp), u'opsIncomplete': opsIncomplete}
|
|---|
| 2331 |
|
|---|
| 2332 |
|
|---|
| 2333 | class InsertCursor(_Cursor):
|
|---|
| 2334 | __doc__ = DynamicDocString()
|
|---|
| 2335 |
|
|---|
| 2336 | # Public properties and instance methods
|
|---|
| 2337 |
|
|---|
| 2338 | def SetValue(self, field, value):
|
|---|
| 2339 | self._SetValue_Base(field, value)
|
|---|
| 2340 | self._FieldSet[field] = True
|
|---|
| 2341 |
|
|---|
| 2342 | def SetGeometry(self, geometry):
|
|---|
| 2343 | self._SetGeometry_Base(geometry)
|
|---|
| 2344 | self._GeometrySet = True
|
|---|
| 2345 |
|
|---|
| 2346 | def InsertRow(self):
|
|---|
| 2347 |
|
|---|
| 2348 | if not self._IsOpen:
|
|---|
| 2349 | raise RuntimeError(_(u'The cursor is closed.'))
|
|---|
| 2350 |
|
|---|
| 2351 | # For datasets with geometry, validate that the caller has
|
|---|
| 2352 | # set the geometry.
|
|---|
| 2353 |
|
|---|
| 2354 | if self._Table.GeometryType is not None and not self._GeometrySet:
|
|---|
| 2355 | raise RuntimeError(_(u'This %(singular)s cannot be inserted into %(dn)s because its geometry has not been set.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName})
|
|---|
| 2356 |
|
|---|
| 2357 | # Set to null all settable nullable fields that were not set
|
|---|
| 2358 | # by the caller.
|
|---|
| 2359 |
|
|---|
| 2360 | debug = Dataset._DebugLoggingEnabled()
|
|---|
| 2361 |
|
|---|
| 2362 | for f in self._Table.Fields:
|
|---|
| 2363 | if f.Name != self._Table.OIDFieldName and f.Name != self._Table.GeometryFieldName and f.IsSettable and f.Name not in self._FieldSet:
|
|---|
| 2364 | if f.IsNullable:
|
|---|
| 2365 | if debug:
|
|---|
| 2366 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Setting field %(field)s to None.'), {u'class': self.__class__.__name__, u'id': id(self), u'field': f.Name})
|
|---|
| 2367 | self._SetValue(f.Name, None)
|
|---|
| 2368 | self._FieldSet[f.Name] = True
|
|---|
| 2369 | else:
|
|---|
| 2370 | raise RuntimeError(_(u'This %(singular)s cannot be inserted into %(dn)s because field %(field)s has not been assigned a value and it is not nullable. You must provide a value for this field.') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'field': f.Name})
|
|---|
| 2371 |
|
|---|
| 2372 | # Insert the row and report progress.
|
|---|
| 2373 |
|
|---|
| 2374 | if debug:
|
|---|
| 2375 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Inserting this %(singular)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'singular': self._RowDescriptionSingular})
|
|---|
| 2376 |
|
|---|
| 2377 | try:
|
|---|
| 2378 | self._InsertRow()
|
|---|
| 2379 | except Exception, e:
|
|---|
| 2380 | raise RuntimeError(_(u'Failed to insert a %(singular)s into %(dn)s due to %(e)s: %(msg)s') % {u'singular': self._RowDescriptionSingular, u'dn': self._Table.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 2381 |
|
|---|
| 2382 | self._FieldSet = {}
|
|---|
| 2383 | self._GeometrySet = False
|
|---|
| 2384 |
|
|---|
| 2385 | if self._ProgressReporter is not None:
|
|---|
| 2386 | self._ProgressReporter.ReportProgress()
|
|---|
| 2387 |
|
|---|
| 2388 | # Private base class constructor. Do not invoke directly; use
|
|---|
| 2389 | # Table.OpenInsertCursor instead. Do not override; put
|
|---|
| 2390 | # your initialization code the derive class's _Open method.
|
|---|
| 2391 |
|
|---|
| 2392 | def __init__(self, dataset, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural):
|
|---|
| 2393 |
|
|---|
| 2394 | # Initialize the base class and our attributes.
|
|---|
| 2395 |
|
|---|
| 2396 | super(InsertCursor, self).__init__(dataset, rowDescriptionSingular, rowDescriptionPlural)
|
|---|
| 2397 |
|
|---|
| 2398 | self._FieldSet = {}
|
|---|
| 2399 | self._GeometrySet = False
|
|---|
| 2400 |
|
|---|
| 2401 | # Call the derived class to open the cursor.
|
|---|
| 2402 |
|
|---|
| 2403 | self._Table._LogDebug(_(u'%(class)s 0x%(id)08X: Opening insert cursor on %(dn)s, rowCount=%(rc)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dn': dataset.DisplayName, u'rc': repr(rowCount)})
|
|---|
| 2404 | try:
|
|---|
| 2405 | self._Open()
|
|---|
| 2406 | except Exception, e:
|
|---|
| 2407 | self._Table = None # Set this to None to make sure a reference is not leaked due when this constructor fails.
|
|---|
| 2408 | raise RuntimeError(_(u'Cannot insert %(plural)s into %(dn)s. Failed to open an insert cursor due to %(e)s: %(msg)s') % {u'plural': self._RowDescriptionPlural, u'dn': dataset.DisplayName, u'e': e.__class__.__name__, u'msg': unicode(e)})
|
|---|
| 2409 |
|
|---|
| 2410 | self._IsOpen = True
|
|---|
| 2411 |
|
|---|
| 2412 | if not hasattr(_Cursor, '_CursorsToCloseAtExit'):
|
|---|
| 2413 | _Cursor._CursorsToCloseAtExit = []
|
|---|
| 2414 | _Cursor._CursorsToCloseAtExit.insert(0, weakref.ref(self))
|
|---|
| 2415 |
|
|---|
| 2416 | # If the caller wants progress to be reported, start a
|
|---|
| 2417 | # progress reporter.
|
|---|
| 2418 |
|
|---|
| 2419 | if reportProgress:
|
|---|
| 2420 | self._ProgressReporter = ProgressReporter(progressMessage1=_(u'Still inserting %(plural)s: %%(elapsed)s elapsed, %%(opsCompleted)i %(plural)s inserted, %%(perOp)s per %(singular)s, %%(opsRemaining)i remaining, estimated completion time: %%(etc)s.') % {u'singular': self._RowDescriptionSingular, u'plural': self._RowDescriptionPlural},
|
|---|
| 2421 | progressMessage2=_(u'Still inserting %(plural)s: %%(elapsed)s elapsed, %%(opsCompleted)i %(plural)s inserted, %%(perOp)s per %(singular)s.') % {u'singular': self._RowDescriptionSingular, u'plural': self._RowDescriptionPlural},
|
|---|
| 2422 | completionMessage=_(u'Finished inserting %(plural)s: %%(elapsed)s elapsed, %%(opsCompleted)i %(plural)s inserted, %%(perOp)s per %(singular)s.') % {u'singular': self._RowDescriptionSingular, u'plural': self._RowDescriptionPlural},
|
|---|
| 2423 | abortedMessage=_(u'Insert operation stopped before all %(plural)s were inserted: %%(elapsed)s elapsed, %%(opsCompleted)i %(plural)s inserted, %%(perOp)s per %(singular)s, %%(opsIncomplete)i %(plural)s not inserted.') % {u'singular': self._RowDescriptionSingular, u'plural': self._RowDescriptionPlural})
|
|---|
| 2424 | self._ProgressReporter.Start(rowCount)
|
|---|
| 2425 | else:
|
|---|
| 2426 | self._ProgressReporter = None
|
|---|
| 2427 |
|
|---|
| 2428 | # Private methods that the derived class must override (except
|
|---|
| 2429 | # _SetGeometry when the derived class does not support geometry).
|
|---|
| 2430 |
|
|---|
| 2431 | def _Open(self):
|
|---|
| 2432 | raise NotImplementedError(_(u'The _Open method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2433 |
|
|---|
| 2434 | def _SetValue(self, field, value):
|
|---|
| 2435 | raise NotImplementedError(_(u'The _SetValue method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2436 |
|
|---|
| 2437 | def _SetGeometry(self, geometry):
|
|---|
| 2438 | raise NotImplementedError(_(u'The _SetGeometry method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2439 |
|
|---|
| 2440 | def _InsertRow(self):
|
|---|
| 2441 | raise NotImplementedError(_(u'The _InsertRow method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 2442 |
|
|---|
| 2443 |
|
|---|
| 2444 | class Grid(Dataset):
|
|---|
| 2445 | __doc__ = DynamicDocString()
|
|---|
| 2446 |
|
|---|
| 2447 | # Public properties and instance methods
|
|---|
| 2448 |
|
|---|
| 2449 | def _GetDimensions(self):
|
|---|
| 2450 | return self.GetLazyPropertyValue('Dimensions')
|
|---|
| 2451 |
|
|---|
| 2452 | Dimensions = property(_GetDimensions, doc=DynamicDocString())
|
|---|
| 2453 |
|
|---|
| 2454 | def _GetShape(self):
|
|---|
| 2455 | return self.GetLazyPropertyValue('Shape')
|
|---|
| 2456 |
|
|---|
| 2457 | Shape = property(_GetShape, doc=DynamicDocString())
|
|---|
| 2458 |
|
|---|
| 2459 | def _GetCoordDependencies(self):
|
|---|
| 2460 | return self.GetLazyPropertyValue('CoordDependencies')
|
|---|
| 2461 |
|
|---|
| 2462 | CoordDependencies = property(_GetCoordDependencies, doc=DynamicDocString())
|
|---|
| 2463 |
|
|---|
| 2464 | def _GetCoordIncrements(self):
|
|---|
| 2465 | return self.GetLazyPropertyValue('CoordIncrements')
|
|---|
| 2466 |
|
|---|
| 2467 | CoordIncrements = property(_GetCoordIncrements, doc=DynamicDocString())
|
|---|
| 2468 |
|
|---|
| 2469 | def _GetTIncrementUnit(self):
|
|---|
| 2470 | return self.GetLazyPropertyValue('TIncrementUnit')
|
|---|
| 2471 |
|
|---|
| 2472 | TIncrementUnit = property(_GetTIncrementUnit, doc=DynamicDocString())
|
|---|
| 2473 |
|
|---|
| 2474 | def _GetTSemiRegularity(self):
|
|---|
| 2475 | return self.GetLazyPropertyValue('TSemiRegularity')
|
|---|
| 2476 |
|
|---|
| 2477 | TSemiRegularity = property(_GetTSemiRegularity, doc=DynamicDocString())
|
|---|
| 2478 |
|
|---|
| 2479 | def _GetTCountPerSemiRegularPeriod(self):
|
|---|
| 2480 | return self.GetLazyPropertyValue('TCountPerSemiRegularPeriod')
|
|---|
| 2481 |
|
|---|
| 2482 | TCountPerSemiRegularPeriod = property(_GetTCountPerSemiRegularPeriod, doc=DynamicDocString())
|
|---|
| 2483 |
|
|---|
| 2484 | def _GetMinCoords(self):
|
|---|
| 2485 | return self._MinCoords
|
|---|
| 2486 |
|
|---|
| 2487 | MinCoords = property(_GetMinCoords, doc=DynamicDocString())
|
|---|
| 2488 |
|
|---|
| 2489 | def _GetCenterCoords(self):
|
|---|
| 2490 | return self._CenterCoords
|
|---|
| 2491 |
|
|---|
| 2492 | CenterCoords = property(_GetCenterCoords, doc=DynamicDocString())
|
|---|
| 2493 |
|
|---|
| 2494 | def _GetMaxCoords(self):
|
|---|
| 2495 | return self._MaxCoords
|
|---|
| 2496 |
|
|---|
| 2497 | MaxCoords = property(_GetMaxCoords, doc=DynamicDocString())
|
|---|
| 2498 |
|
|---|
| 2499 | def _GetDataType(self):
|
|---|
| 2500 | if self.DataIsScaled:
|
|---|
| 2501 | return self.GetLazyPropertyValue('ScaledDataType')
|
|---|
| 2502 | return self.UnscaledDataType
|
|---|
| 2503 |
|
|---|
| 2504 | DataType = property(_GetDataType, doc=DynamicDocString())
|
|---|
| 2505 |
|
|---|
| 2506 | def _GetNoDataValue(self):
|
|---|
| 2507 | if self.DataIsScaled:
|
|---|
| 2508 | return self.GetLazyPropertyValue('ScaledNoDataValue')
|
|---|
| 2509 | return self.UnscaledNoDataValue
|
|---|
| 2510 |
|
|---|
| 2511 | NoDataValue = property(_GetNoDataValue, doc=DynamicDocString())
|
|---|
| 2512 |
|
|---|
| 2513 | def _GetData(self):
|
|---|
| 2514 | if self.DataIsScaled:
|
|---|
| 2515 | return self._ScaledData
|
|---|
| 2516 | return self._UnscaledData
|
|---|
| 2517 |
|
|---|
| 2518 | Data = property(_GetData, doc=DynamicDocString())
|
|---|
| 2519 |
|
|---|
| 2520 | def _GetDataIsScaled(self):
|
|---|
| 2521 | return self.GetLazyPropertyValue('ScalingFunction') is not None
|
|---|
| 2522 |
|
|---|
| 2523 | DataIsScaled = property(_GetDataIsScaled, doc=DynamicDocString())
|
|---|
| 2524 |
|
|---|
| 2525 | def _GetUnscaledDataType(self):
|
|---|
| 2526 | return self.GetLazyPropertyValue('UnscaledDataType')
|
|---|
| 2527 |
|
|---|
| 2528 | UnscaledDataType = property(_GetUnscaledDataType, doc=DynamicDocString())
|
|---|
| 2529 |
|
|---|
| 2530 | def _GetUnscaledNoDataValue(self):
|
|---|
| 2531 | return self.GetLazyPropertyValue('UnscaledNoDataValue')
|
|---|
| 2532 |
|
|---|
| 2533 | UnscaledNoDataValue = property(_GetUnscaledNoDataValue, doc=DynamicDocString())
|
|---|
| 2534 |
|
|---|
| 2535 | def _GetUnscaledData(self):
|
|---|
| 2536 | return self._UnscaledData
|
|---|
| 2537 |
|
|---|
| 2538 | UnscaledData = property(_GetUnscaledData, doc=DynamicDocString())
|
|---|
| 2539 |
|
|---|
| 2540 | def GetIndicesForCoords(self, coords):
|
|---|
| 2541 |
|
|---|
| 2542 | # Validate the coordinates.
|
|---|
| 2543 |
|
|---|
| 2544 | if len(coords) != len(self.Dimensions):
|
|---|
| 2545 | raise ValueError(_(u'%(dn)s has %(dim)i dimensions but %(coords)i coordinates were provided.') % {u'dn': self.DisplayName, u'dim': len(self.Dimensions), u'coords': len(coords)})
|
|---|
| 2546 |
|
|---|
| 2547 | if self.Dimensions[0] == 't':
|
|---|
| 2548 | if not isinstance(coords[0], (datetime.date, datetime.datetime)):
|
|---|
| 2549 | raise TypeError(_(u'coords[0] is an instance of %(t1)s. It must be an instance of %(t2)s or %(t3)s') % {u't1': unicode(type(coords[0])), u't2': unicode(datetime.date), u't2': unicode(datetime.datetime)})
|
|---|
| 2550 | numericIndicesStart = 1
|
|---|
| 2551 | else:
|
|---|
| 2552 | numericIndicesStart = 0
|
|---|
| 2553 |
|
|---|
| 2554 | for i in range(numericIndicesStart, len(coords)):
|
|---|
| 2555 | if not isinstance(coords[i], (int, long, float)):
|
|---|
| 2556 | raise TypeError(_(u'coords[%(i)i] is an instance of %(t1)s. It must be an instance of %(t2)s, %(t3)s, or %(t4)s.') % {u'i': i, u't1': unicode(type(coords[i])), u't2': unicode(int), u't2': unicode(long), u't2': unicode(float)})
|
|---|
| 2557 |
|
|---|
| 2558 | # First get the indices for dimensions that do not depend on
|
|---|
| 2559 | # any others.
|
|---|
| 2560 |
|
|---|
| 2561 | indices = [None] * len(coords)
|
|---|
| 2562 | done = [False] * len(coords)
|
|---|
| 2563 |
|
|---|
| 2564 | for i, d in enumerate(self.Dimensions):
|
|---|
| 2565 | if self.CoordDependencies[i] is None:
|
|---|
| 2566 | coord = coords[i]
|
|---|
| 2567 |
|
|---|
| 2568 | # If this dimension is x and the grid uses a
|
|---|
| 2569 | # geographic projection handle the "0 to 360 vs.
|
|---|
| 2570 | # -180 to 180" problem.
|
|---|
| 2571 |
|
|---|
| 2572 | if d == u'x':
|
|---|
| 2573 | sr = self.GetSpatialReference('obj')
|
|---|
| 2574 | if sr is not None and sr.IsGeographic():
|
|---|
| 2575 | coord = coord - (coord // 360) * 360 # Convert the requested x coordinate to 0 to 360, regardless of what it currently is
|
|---|
| 2576 |
|
|---|
| 2577 | # If coord is less than the min x extent, add 360
|
|---|
| 2578 | # until it is greater than or equal it, to handle
|
|---|
| 2579 | # coordinate systems such as NOAA OSCAR, which
|
|---|
| 2580 | # uses a 20 to 380 system.
|
|---|
| 2581 |
|
|---|
| 2582 | if coord < self.MinCoords[d, 0]:
|
|---|
| 2583 | while coord < self.MinCoords[d, 0]:
|
|---|
| 2584 | coord += 360.
|
|---|
| 2585 |
|
|---|
| 2586 | # Otherwise, if it is greater than or equal to the
|
|---|
| 2587 | # max x extent, subtract 360 until it is less than
|
|---|
| 2588 | # it, to handle coordinate systems such as MODIS
|
|---|
| 2589 | # L3 which uses a -180 to 180 system.
|
|---|
| 2590 |
|
|---|
| 2591 | elif coord >= self.MaxCoords[d, -1]:
|
|---|
| 2592 | while coord >= self.MaxCoords[d, -1]:
|
|---|
| 2593 | coord -= 360.
|
|---|
| 2594 |
|
|---|
| 2595 | # If this dimension is x, y, or z and has a constant
|
|---|
| 2596 | # increment, calculate the index directly.
|
|---|
| 2597 |
|
|---|
| 2598 | increment = self.CoordIncrements[i]
|
|---|
| 2599 | if d in u'xyz' and increment is not None:
|
|---|
| 2600 | index = int(math.floor((coord - (self.GetLazyPropertyValue('CornerCoords')[i] - increment/2.)) / increment))
|
|---|
| 2601 | if index >= 0 and index <= self.Shape[i] - 1:
|
|---|
| 2602 | indices[i] = index
|
|---|
| 2603 |
|
|---|
| 2604 | # Otherwise (this dimension is t or does not have a
|
|---|
| 2605 | # constant increment), find the index from the full
|
|---|
| 2606 | # list of indices using a binary search.
|
|---|
| 2607 |
|
|---|
| 2608 | else:
|
|---|
| 2609 | index = bisect.bisect_right(self.MaxCoords[d], coord)
|
|---|
| 2610 | if index > 0 and index < self.Shape[i] - 1 or index == 0 and coord >= self.MinCoords[d, 0]:
|
|---|
| 2611 | indices[i] = index
|
|---|
| 2612 |
|
|---|
| 2613 | done[i] = True
|
|---|
| 2614 |
|
|---|
| 2615 | # Now get the indices for dimensions that do depend on others.
|
|---|
| 2616 |
|
|---|
| 2617 | if False in done:
|
|---|
| 2618 | i = 0
|
|---|
| 2619 | while i < len(self.Dimensions):
|
|---|
| 2620 | if not done[i] and self.CoordDependencies[i] is not None and all([done[self.Dimensions.index(d)] for d in self.CoordDependencies[i]]):
|
|---|
| 2621 | maxCoordsKey = [self.Dimensions[i]]
|
|---|
| 2622 | minCoordKey = [self.Dimensions[i]]
|
|---|
| 2623 | for j in range(len(self.Dimensions)):
|
|---|
| 2624 | if self.Dimensions[j] == self.Dimensions[i]:
|
|---|
| 2625 | maxCoordsKey.append(slice(None))
|
|---|
| 2626 | minCoordKey.append(0)
|
|---|
| 2627 | elif self.Dimensions[j] in self.CoordDependencies[i]:
|
|---|
| 2628 | maxCoordsKey.append(indices[j])
|
|---|
| 2629 | minCoordKey.append(indices[j])
|
|---|
| 2630 |
|
|---|
| 2631 | if None not in maxCoordsKey and None not in minCoordKey:
|
|---|
| 2632 | index = bisect.bisect_right(self.MaxCoords.__getitem__(tuple(maxCoordsKey)), coords[i])
|
|---|
| 2633 | if index > 0 and index < self.Shape[i] or index == 0 and coords[i] >= self.MinCoords.__getitem__(tuple(minCoordKey)):
|
|---|
| 2634 | indices[i] = index
|
|---|
| 2635 |
|
|---|
| 2636 | done[i] = True
|
|---|
| 2637 | i = 0
|
|---|
| 2638 |
|
|---|
| 2639 | else:
|
|---|
| 2640 | i += 1
|
|---|
| 2641 |
|
|---|
| 2642 | # Return successfully.
|
|---|
| 2643 |
|
|---|
| 2644 | return indices
|
|---|
| 2645 |
|
|---|
| 2646 | # Private base class constructor. Do not invoke directly; use a
|
|---|
| 2647 | # derived class instead. If you override, be sure to call it from
|
|---|
| 2648 | # your derived class's __init__.
|
|---|
| 2649 |
|
|---|
| 2650 | def __init__(self, parentCollection=None, queryableAttributes=None, queryableAttributeValues=None, lazyPropertyValues=None):
|
|---|
| 2651 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 2652 |
|
|---|
| 2653 | # Initialize the base class.
|
|---|
| 2654 |
|
|---|
| 2655 | super(Grid, self).__init__(parentCollection, queryableAttributes, queryableAttributeValues, lazyPropertyValues)
|
|---|
| 2656 |
|
|---|
| 2657 | # Set various attributes that implement __getitem__.
|
|---|
| 2658 |
|
|---|
| 2659 | self._MinCoords = _ContainerEmulator(self, '_GetMinCoords')
|
|---|
| 2660 | self._CenterCoords = _ContainerEmulator(self, '_GetCenterCoords')
|
|---|
| 2661 | self._MaxCoords = _ContainerEmulator(self, '_GetMaxCoords')
|
|---|
| 2662 | self._ScaledData = _ContainerEmulator(self, '_GetScaledDataAsArray', '_SetScaledDataWithArray')
|
|---|
| 2663 | self._UnscaledData = _ContainerEmulator(self, '_GetUnscaledDataAsArray', '_SetUnscaledDataWithArray')
|
|---|
| 2664 |
|
|---|
| 2665 | # Private methods that the derived class generally does not
|
|---|
| 2666 | # override.
|
|---|
| 2667 |
|
|---|
| 2668 | def _GetMinCoords(self, key):
|
|---|
| 2669 | return self._GetCoordsForOffset(key, -0.5)
|
|---|
| 2670 |
|
|---|
| 2671 | def _GetCenterCoords(self, key):
|
|---|
| 2672 | return self._GetCoordsForOffset(key, 0.0)
|
|---|
| 2673 |
|
|---|
| 2674 | def _GetMaxCoords(self, key):
|
|---|
| 2675 | return self._GetCoordsForOffset(key, 0.5)
|
|---|
| 2676 |
|
|---|
| 2677 | def _GetCoordsForOffset(self, key, fixedIncrementOffset):
|
|---|
| 2678 |
|
|---|
| 2679 | # Validate the key.
|
|---|
| 2680 |
|
|---|
| 2681 | coord, coordNum, slices, sliceDims = self._GetSlicesForCoordsKey(key)
|
|---|
| 2682 |
|
|---|
| 2683 | # If the caller is asking for a coordinate that does not have
|
|---|
| 2684 | # a fixed increment, forward the call to the derived class.
|
|---|
| 2685 |
|
|---|
| 2686 | if self.CoordIncrements[coordNum] is None:
|
|---|
| 2687 | return self._GetCoords(coord, coordNum, slices, sliceDims, fixedIncrementOffset)
|
|---|
| 2688 |
|
|---|
| 2689 | # The coordinate has a fixed increment. If the coordinate is
|
|---|
| 2690 | # x, y, or z, calculate and return the requested values.
|
|---|
| 2691 |
|
|---|
| 2692 | import numpy
|
|---|
| 2693 |
|
|---|
| 2694 | if coord in 'xyz':
|
|---|
| 2695 | offset = self.CoordIncrements[coordNum] * fixedIncrementOffset
|
|---|
| 2696 | if slices is not None:
|
|---|
| 2697 | if isinstance(slices[0], types.IntType):
|
|---|
| 2698 | return slices[0] * self.CoordIncrements[coordNum] + self.GetLazyPropertyValue('CornerCoords')[coordNum] + offset
|
|---|
| 2699 | indices = slices[0].indices(self.Shape[coordNum])
|
|---|
| 2700 | return numpy.arange(indices[0], indices[1], indices[2], dtype='float64') * self.CoordIncrements[coordNum] + self.GetLazyPropertyValue('CornerCoords')[coordNum] + offset
|
|---|
| 2701 | return numpy.arange(self.Shape[coordNum], dtype='float64') * self.CoordIncrements[coordNum] + self.GetLazyPropertyValue('CornerCoords')[coordNum] + offset
|
|---|
| 2702 |
|
|---|
| 2703 | # The coordinate is t. First check whether we previously
|
|---|
| 2704 | # calculated and cached the full list of t coordinates. If
|
|---|
| 2705 | # not, do it now.
|
|---|
| 2706 |
|
|---|
| 2707 | if not hasattr(self, '_CachedTCoords'):
|
|---|
| 2708 | self._CachedTCoords = {}
|
|---|
| 2709 |
|
|---|
| 2710 | if fixedIncrementOffset not in self._CachedTCoords:
|
|---|
| 2711 | self._CachedTCoords[fixedIncrementOffset] = self._GetTCoordsList(fixedIncrementOffset, self.Shape[coordNum])
|
|---|
| 2712 |
|
|---|
| 2713 | # Return a numpy array of the requested slice of t
|
|---|
| 2714 | # coordinates (if any).
|
|---|
| 2715 |
|
|---|
| 2716 | if slices is not None:
|
|---|
| 2717 | if isinstance(slices[0], types.IntType):
|
|---|
| 2718 | return self._CachedTCoords[fixedIncrementOffset][slices[0]]
|
|---|
| 2719 | return numpy.array(self._CachedTCoords[fixedIncrementOffset][slices[0]], dtype='object')
|
|---|
| 2720 | return numpy.array(self._CachedTCoords[fixedIncrementOffset], dtype='object')
|
|---|
| 2721 |
|
|---|
| 2722 | def _GetSlicesForCoordsKey(self, key):
|
|---|
| 2723 |
|
|---|
| 2724 | # Validate the key. The first element must be a dimension
|
|---|
| 2725 | # name. The additional elements are optional, and depend on
|
|---|
| 2726 | # whether that dimension depends on any others. If not, there
|
|---|
| 2727 | # may optionally be exactly one additional element, which is
|
|---|
| 2728 | # an integer index or slice into that dimension. If the
|
|---|
| 2729 | # dimension does depend on others, there may optionaly be
|
|---|
| 2730 | # exactly n + 1 additional elements, each integer indices or
|
|---|
| 2731 | # slices into dimensions, where n is the number of
|
|---|
| 2732 | # depended-upon dimensions. In this latter case, the order of
|
|---|
| 2733 | # the indices/slices is the same as the order of the
|
|---|
| 2734 | # dimensions, regardless of which dimension is requested and
|
|---|
| 2735 | # what dimensions it depends on.
|
|---|
| 2736 | #
|
|---|
| 2737 | # Consider, for example, the 4D ROMS ocean model, in which the
|
|---|
| 2738 | # values of z depend on x, y, and t. That is, the values of
|
|---|
| 2739 | # the depth levels depend on latitude, longitude, and time
|
|---|
| 2740 | # (search the internet for "vertical s-coordinate" for more
|
|---|
| 2741 | # information). For this dataset, if the caller just requests
|
|---|
| 2742 | # 'z' and provides no additional elements, a 4D array will be
|
|---|
| 2743 | # returned with the shape of the entire dataset. That array
|
|---|
| 2744 | # will be quite large, and the caller usually won't need it,
|
|---|
| 2745 | # so he will usually supply indices or slices. In that case,
|
|---|
| 2746 | # the caller must specify exactly four indices or slices,
|
|---|
| 2747 | # ordered t, z, y, x, which is the order of the dimensions of
|
|---|
| 2748 | # a 4D Grid dataset.
|
|---|
| 2749 |
|
|---|
| 2750 | if isinstance(key, basestring):
|
|---|
| 2751 | key = (key,)
|
|---|
| 2752 |
|
|---|
| 2753 | if not isinstance(key, types.TupleType) or len(key) < 1 or not isinstance(key[0], basestring):
|
|---|
| 2754 | raise TypeError(_(u'The key must be a tuple with at least one element. The first element must be the dimension name, one of: %(dimnames)s.') % {u'dimnames': ', '.join(map(lambda s: "'" + s + "'", self.Dimensions))})
|
|---|
| 2755 | if key[0] not in self.Dimensions:
|
|---|
| 2756 | raise KeyError(_(u'The first element of the key must be an existing dimension name, one of: %(dimnames)s.') % {u'dimnames': ', '.join(map(lambda s: "'" + s + "'", self.Dimensions))})
|
|---|
| 2757 |
|
|---|
| 2758 | coord = key[0]
|
|---|
| 2759 | coordNum = self.Dimensions.index(coord)
|
|---|
| 2760 |
|
|---|
| 2761 | expectedSlices = 1
|
|---|
| 2762 | if self.CoordDependencies[coordNum] is not None:
|
|---|
| 2763 | expectedSlices += len(self.CoordDependencies[coordNum])
|
|---|
| 2764 | sliceDims = u''
|
|---|
| 2765 | for dim in self.Dimensions:
|
|---|
| 2766 | if dim == key[0] or dim in self.CoordDependencies[coordNum]:
|
|---|
| 2767 | sliceDims += dim
|
|---|
| 2768 | else:
|
|---|
| 2769 | sliceDims = coord
|
|---|
| 2770 |
|
|---|
| 2771 | if len(key) > 1:
|
|---|
| 2772 | if len(key) - 1 != expectedSlices:
|
|---|
| 2773 | raise KeyError(_(u'Invalid number of slices. When requesting %(dim)s coordinates of %(dn)s, you must either specify no slices (in which case the entire array of coordinates will be returned) or specify exactly %(slices)i slices.') % {u'dn': self.DisplayName, u'dim': coord, u'slices': expectedSlices})
|
|---|
| 2774 |
|
|---|
| 2775 | slices = list(key[1:])
|
|---|
| 2776 |
|
|---|
| 2777 | for i in range(0, len(slices)):
|
|---|
| 2778 | if isinstance (slices[i], types.SliceType):
|
|---|
| 2779 | if not isinstance(slices[i].start, (types.NoneType, types.IntType)) or not isinstance(slices[i].stop, (types.NoneType, types.IntType)) or not isinstance(slices[i].step, (types.NoneType, types.IntType)):
|
|---|
| 2780 | raise TypeError(_(u'The slice start, stop, and step must be integers, or None.'))
|
|---|
| 2781 | elif isinstance (slices[i], types.IntType):
|
|---|
| 2782 | dimNum = self.Dimensions.index(sliceDims[i])
|
|---|
| 2783 | if slices[i] >= self.Shape[dimNum] or slices[i] < 0-self.Shape[dimNum]:
|
|---|
| 2784 | raise IndexError(_(u'Index for %(dim)s dimension out of bounds.') % {u'dim': self.Dimensions[dimNum]})
|
|---|
| 2785 | if slices[i] < 0:
|
|---|
| 2786 | slices[i] += self.Shape[dimNum]
|
|---|
| 2787 | else:
|
|---|
| 2788 | raise TypeError(_(u'Element %(i)i of the key must be an integer or a slice.') % {u'i': i+1})
|
|---|
| 2789 | else:
|
|---|
| 2790 | slices = None
|
|---|
| 2791 |
|
|---|
| 2792 | # Return successfully.
|
|---|
| 2793 |
|
|---|
| 2794 | return coord, coordNum, slices, sliceDims
|
|---|
| 2795 |
|
|---|
| 2796 | def _GetTCoordsList(self, fixedIncrementOffset, listLength):
|
|---|
| 2797 | tCoords = []
|
|---|
| 2798 |
|
|---|
| 2799 | # self.GetLazyPropertyValue('CornerCoords')[coordNum] is the
|
|---|
| 2800 | # coordinate of the first time slice. Depending on the
|
|---|
| 2801 | # dataset, this coordinate may be given as the min, center, or
|
|---|
| 2802 | # max for that slice. A lot of the following complexity deals
|
|---|
| 2803 | # with the scenario where we are asked to produce a coordinate
|
|---|
| 2804 | # type (min, center, max) that is different than that
|
|---|
| 2805 | # specified for the first time slice.
|
|---|
| 2806 |
|
|---|
| 2807 | coordNum = self.Dimensions.index('t')
|
|---|
| 2808 | t0 = self.GetLazyPropertyValue('CornerCoords')[coordNum]
|
|---|
| 2809 |
|
|---|
| 2810 | # If the t increment is day, hour, minute, or second, then it
|
|---|
| 2811 | # is the same number of seconds every time step. We can use
|
|---|
| 2812 | # simple timedeltas to do the math.
|
|---|
| 2813 |
|
|---|
| 2814 | tCornerCoordType = self.GetLazyPropertyValue('TCornerCoordType')
|
|---|
| 2815 | tIncrement = self.CoordIncrements[coordNum]
|
|---|
| 2816 |
|
|---|
| 2817 | if self.TIncrementUnit in ['day', 'hour', 'minute', 'second']:
|
|---|
| 2818 |
|
|---|
| 2819 | # Create a timedelta for the increment.
|
|---|
| 2820 |
|
|---|
| 2821 | if self.TIncrementUnit == 'day':
|
|---|
| 2822 | increment = datetime.timedelta(days=tIncrement)
|
|---|
| 2823 | elif self.TIncrementUnit == 'hour':
|
|---|
| 2824 | increment = datetime.timedelta(hours=tIncrement)
|
|---|
| 2825 | elif self.TIncrementUnit == 'minute':
|
|---|
| 2826 | increment = datetime.timedelta(minutes=tIncrement)
|
|---|
| 2827 | else:
|
|---|
| 2828 | increment = datetime.timedelta(seconds=tIncrement)
|
|---|
| 2829 |
|
|---|
| 2830 | # Calculate an offset that will yield the coordinate that
|
|---|
| 2831 | # we're supposed to produce.
|
|---|
| 2832 |
|
|---|
| 2833 | if tCornerCoordType == 'min' and fixedIncrementOffset == 0.5:
|
|---|
| 2834 | offset = increment
|
|---|
| 2835 | elif tCornerCoordType == 'min' and fixedIncrementOffset == 0.0 or tCornerCoordType == 'center' and fixedIncrementOffset == 0.5:
|
|---|
| 2836 | offset = increment / 2
|
|---|
| 2837 | elif tCornerCoordType == 'min' and fixedIncrementOffset == -0.5 or tCornerCoordType == 'center' and fixedIncrementOffset == 0.0 or tCornerCoordType == 'max' and fixedIncrementOffset == 0.5:
|
|---|
| 2838 | offset = datetime.timedelta(0)
|
|---|
| 2839 | elif tCornerCoordType == 'center' and fixedIncrementOffset == -0.5 or tCornerCoordType == 'max' and fixedIncrementOffset == 0.0:
|
|---|
| 2840 | offset = datetime.timedelta(0) - increment / 2
|
|---|
| 2841 | else:
|
|---|
| 2842 | offset = datetime.timedelta(0) - increment
|
|---|
| 2843 |
|
|---|
| 2844 | # Create the full list of t coordinates. If the
|
|---|
| 2845 | # coordinates are not semi-regular, then it is easy.
|
|---|
| 2846 |
|
|---|
| 2847 | if self.TSemiRegularity is None:
|
|---|
| 2848 | tCoords.extend(map(lambda i: t0 + i * increment + offset, range(listLength)))
|
|---|
| 2849 |
|
|---|
| 2850 | # If the coordinates are semi-regular, it is more
|
|---|
| 2851 | # complicated. At the moment, only annual semi-regularity
|
|---|
| 2852 | # is supported.
|
|---|
| 2853 |
|
|---|
| 2854 | else:
|
|---|
| 2855 | if self.TSemiRegularity != 'annual':
|
|---|
| 2856 | raise NotImplementedError(_(u'Programming error in this tool: \'%(sr)s\' semi-regularity has not been implemented. Please contact the author of this tool for assistance.') % {u'sr': self.TSemiRegularity})
|
|---|
| 2857 |
|
|---|
| 2858 | # Count backwards from t0 to determine how many time
|
|---|
| 2859 | # slices precede it in the starting year.
|
|---|
| 2860 | #
|
|---|
| 2861 | # If we have a lazy property called
|
|---|
| 2862 | # TOffsetFromParsedTime, it means that t0 includes
|
|---|
| 2863 | # that offset. So to count back to the beginning of
|
|---|
| 2864 | # the year, we must remove TOffsetFromParsedTime from
|
|---|
| 2865 | # t0.
|
|---|
| 2866 |
|
|---|
| 2867 | tOffsetFromParsedTime = self.GetLazyPropertyValue('TOffsetFromParsedTime')
|
|---|
| 2868 | if tOffsetFromParsedTime is not None:
|
|---|
| 2869 | deltaFromParsedTime = datetime.timedelta(tOffsetFromParsedTime)
|
|---|
| 2870 | t0 = t0 - deltaFromParsedTime
|
|---|
| 2871 | else:
|
|---|
| 2872 | deltaFromParsedTime = datetime.timedelta(0)
|
|---|
| 2873 |
|
|---|
| 2874 | yearlyCount = 0
|
|---|
| 2875 | startDate = t0
|
|---|
| 2876 | while tCornerCoordType == 'min' and (startDate - increment).year == t0.year or tCornerCoordType == 'center' and (startDate - increment * 3 / 2).year == t0.year or tCornerCoordType == 'max' and (startDate - increment * 2).year == t0.year:
|
|---|
| 2877 | startDate -= increment
|
|---|
| 2878 | yearlyCount += 1
|
|---|
| 2879 |
|
|---|
| 2880 | # Now construct the full list of t coordinates.
|
|---|
| 2881 |
|
|---|
| 2882 | t = t0
|
|---|
| 2883 | currentYear = t0.year
|
|---|
| 2884 | for i in range(listLength):
|
|---|
| 2885 | yearlyCount += 1
|
|---|
| 2886 | if yearlyCount < self.TCountPerSemiRegularPeriod:
|
|---|
| 2887 | tCoords.append(t + offset + deltaFromParsedTime)
|
|---|
| 2888 | t += increment
|
|---|
| 2889 | else:
|
|---|
| 2890 | overrun = datetime.timedelta(0)
|
|---|
| 2891 | if tCornerCoordType == 'min':
|
|---|
| 2892 | if (t + increment).year != currentYear:
|
|---|
| 2893 | overrun = (t + increment) - datetime.datetime(currentYear + 1, 1, 1)
|
|---|
| 2894 | elif tCornerCoordType == 'center':
|
|---|
| 2895 | if (t + increment/2).year != currentYear:
|
|---|
| 2896 | overrun = (t + increment/2) - datetime.datetime(currentYear + 1, 1, 1)
|
|---|
| 2897 | else:
|
|---|
| 2898 | if t.year != currentYear:
|
|---|
| 2899 | overrun = t - datetime.datetime(currentYear + 1, 1, 1)
|
|---|
| 2900 |
|
|---|
| 2901 | if fixedIncrementOffset == -0.5:
|
|---|
| 2902 | tCoords.append(t + offset + deltaFromParsedTime)
|
|---|
| 2903 | elif fixedIncrementOffset == 0.0:
|
|---|
| 2904 | tCoords.append(t + offset - overrun/2 + deltaFromParsedTime)
|
|---|
| 2905 | else:
|
|---|
| 2906 | tCoords.append(t + offset - overrun + deltaFromParsedTime)
|
|---|
| 2907 |
|
|---|
| 2908 | yearlyCount = 0
|
|---|
| 2909 | currentYear += 1
|
|---|
| 2910 | t = datetime.datetime(currentYear, startDate.month, startDate.day, startDate.hour, startDate.minute, startDate.second, startDate.microsecond)
|
|---|
| 2911 |
|
|---|
| 2912 | # If the t increment is month, season, or year, then it may be
|
|---|
| 2913 | # a different number of seconds each time step. In these
|
|---|
| 2914 | # cases, we increment according to the fraction of the month
|
|---|
| 2915 | # or day of the year. We do not currently support
|
|---|
| 2916 | # semi-regularity in these cases.
|
|---|
| 2917 |
|
|---|
| 2918 | else:
|
|---|
| 2919 | if self.TSemiRegularity is not None:
|
|---|
| 2920 | raise NotImplementedError(_(u'Programming error in this tool: semi-regularity is not currently supported if the TIncrementUnit is \'%(unit)s\'. Please contact the author of this tool for assistance.') % {u'unit': self.TIncrementUnit})
|
|---|
| 2921 |
|
|---|
| 2922 | if self.TIncrementUnit == 'month':
|
|---|
| 2923 |
|
|---|
| 2924 | # Fail if the t increment is not an integer.
|
|---|
| 2925 | # Currently, we only support incrementing by whole
|
|---|
| 2926 | # months. If the user needs to increment by some
|
|---|
| 2927 | # fractions of a month, they should use a
|
|---|
| 2928 | # TIncrementUnit of 'day'.
|
|---|
| 2929 |
|
|---|
| 2930 | if math.modf(tIncrement)[0] != 0:
|
|---|
| 2931 | raise NotImplementedError(_(u'Programming error in this tool: when the time increment unit is \'month\', the time coordinate increment must be a whole number of months. The requested non-integer values %(value)s is not supported. Please contact the author of this tool for assistance.') % {u'value': tIncrement})
|
|---|
| 2932 | tIncrement = int(tIncrement)
|
|---|
| 2933 |
|
|---|
| 2934 | # If we have a lazy property called
|
|---|
| 2935 | # TOffsetFromParsedTime, it means that t0 includes
|
|---|
| 2936 | # that offset. But datasets that require the
|
|---|
| 2937 | # TOffsetFromParsedTime hack typically want the t
|
|---|
| 2938 | # coordinates to start on the same offset from the
|
|---|
| 2939 | # beginning of the month. For example, the MODIS
|
|---|
| 2940 | # monthly SST always starts at 00:00:00 of the first
|
|---|
| 2941 | # day of the month, minus 12 hours (i.e. 12:00:00 on
|
|---|
| 2942 | # the last day of the previous month).
|
|---|
| 2943 | #
|
|---|
| 2944 | # To make this all work out, perform the computations
|
|---|
| 2945 | # using the t0 without the offset, then add the offset
|
|---|
| 2946 | # back in when we calculate the series of coordinates.
|
|---|
| 2947 |
|
|---|
| 2948 | tOffsetFromParsedTime = self.GetLazyPropertyValue('TOffsetFromParsedTime')
|
|---|
| 2949 | if tOffsetFromParsedTime is not None:
|
|---|
| 2950 | t0 = t0 - datetime.timedelta(tOffsetFromParsedTime)
|
|---|
| 2951 | else:
|
|---|
| 2952 | tOffsetFromParsedTime = 0.
|
|---|
| 2953 |
|
|---|
| 2954 | # Fail if t0 (after removing TOffsetFromParsedTime) is
|
|---|
| 2955 | # not at midnight on the first day of the month.
|
|---|
| 2956 | # Currently, we only support having t0 at the border
|
|---|
| 2957 | # between months because the logic for handling any
|
|---|
| 2958 | # other time is very complicated and we do not know of
|
|---|
| 2959 | # any datasets that require it.
|
|---|
| 2960 |
|
|---|
| 2961 | if t0.day != 1 or t0.hour != 0 or t0.minute != 0 or t0.second != 0 or t0.microsecond != 0:
|
|---|
| 2962 | raise NotImplementedError(_(u'Programming error in this tool: when the time increment unit is \'month\', the time corner coordinate must be the first day of the month at 00:00:00. Time corner coordinates that fall sometime within the month are not supported. Please contact the author of this tool for assistance.'))
|
|---|
| 2963 |
|
|---|
| 2964 | # Construct the full list of t coordinates.
|
|---|
| 2965 |
|
|---|
| 2966 | t = t0
|
|---|
| 2967 |
|
|---|
| 2968 | tPrev = t0
|
|---|
| 2969 | for j in range(tIncrement):
|
|---|
| 2970 | if tPrev.month == 1:
|
|---|
| 2971 | tPrev = datetime.datetime(tPrev.year - 1, 12, 1)
|
|---|
| 2972 | else:
|
|---|
| 2973 | tPrev = datetime.datetime(tPrev.year, tPrev.month - 1, 1)
|
|---|
| 2974 |
|
|---|
| 2975 | for i in range(listLength):
|
|---|
| 2976 | tNext = t
|
|---|
| 2977 | for j in range(tIncrement):
|
|---|
| 2978 | if tNext.month == 12:
|
|---|
| 2979 | tNext = datetime.datetime(tNext.year + 1, 1, 1)
|
|---|
| 2980 | else:
|
|---|
| 2981 | tNext = datetime.datetime(tNext.year, tNext.month + 1, 1)
|
|---|
| 2982 |
|
|---|
| 2983 | if tCornerCoordType == 'min':
|
|---|
| 2984 | if fixedIncrementOffset == -0.5:
|
|---|
| 2985 | tCoords.append(t + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 2986 | elif fixedIncrementOffset == 0.0:
|
|---|
| 2987 | tCoords.append(t + (tNext - t) / 2 + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 2988 | else:
|
|---|
| 2989 | tCoords.append(tNext + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 2990 |
|
|---|
| 2991 | elif tCornerCoordType == 'center':
|
|---|
| 2992 | if fixedIncrementOffset == -0.5:
|
|---|
| 2993 | tCoords.append(tPrev + (t - tPrev) / 2 + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 2994 | elif fixedIncrementOffset == 0.0:
|
|---|
| 2995 | tCoords.append(t + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 2996 | else:
|
|---|
| 2997 | tCoords.append(t + (tNext - t) / 2 + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 2998 |
|
|---|
| 2999 | else:
|
|---|
| 3000 | if fixedIncrementOffset == -0.5:
|
|---|
| 3001 | tCoords.append(tPrev + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 3002 | elif fixedIncrementOffset == 0.0:
|
|---|
| 3003 | tCoords.append(tPrev + (t - tPrev) / 2 + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 3004 | else:
|
|---|
| 3005 | tCoords.append(t + datetime.timedelta(tOffsetFromParsedTime))
|
|---|
| 3006 |
|
|---|
| 3007 | tPrev = t
|
|---|
| 3008 | t = tNext
|
|---|
| 3009 |
|
|---|
| 3010 | # TODO: elif self.TIncrementUnit == 'season':
|
|---|
| 3011 |
|
|---|
| 3012 | elif self.TIncrementUnit == 'year':
|
|---|
| 3013 | tOffsetFromParsedTime = self.GetLazyPropertyValue('TOffsetFromParsedTime')
|
|---|
| 3014 | if tOffsetFromParsedTime is not None:
|
|---|
| 3015 | deltaFromParsedTime = datetime.timedelta(tOffsetFromParsedTime)
|
|---|
| 3016 | t0 = t0 - deltaFromParsedTime
|
|---|
| 3017 | else:
|
|---|
| 3018 | deltaFromParsedTime = datetime.timedelta(0)
|
|---|
| 3019 |
|
|---|
| 3020 | if tCornerCoordType == 'min' and fixedIncrementOffset == 0.5:
|
|---|
| 3021 | t = datetime.datetime(t0.year + 1, t0.month, t0.day, t0.hour, t0.minute, t0.second, t0.microsecond)
|
|---|
| 3022 | elif tCornerCoordType == 'min' and fixedIncrementOffset == 0.0 or tCornerCoordType == 'center' and fixedIncrementOffset == 0.5:
|
|---|
| 3023 | if t0.month > 6:
|
|---|
| 3024 | t = datetime.datetime(t0.year + 1, t0.month - 6, t0.day, t0.hour, t0.minute, t0.second, t0.microsecond)
|
|---|
| 3025 | else:
|
|---|
| 3026 | t = datetime.datetime(t0.year, t0.month + 6, t0.day, t0.hour, t0.minute, t0.second, t0.microsecond)
|
|---|
| 3027 | elif tCornerCoordType == 'min' and fixedIncrementOffset == -0.5 or tCornerCoordType == 'center' and fixedIncrementOffset == 0.0 or tCornerCoordType == 'max' and fixedIncrementOffset == 0.5:
|
|---|
| 3028 | t = t0
|
|---|
| 3029 | elif tCornerCoordType == 'center' and fixedIncrementOffset == -0.5 or tCornerCoordType == 'max' and fixedIncrementOffset == 0.0:
|
|---|
| 3030 | if t0.month <= 6:
|
|---|
| 3031 | t = datetime.datetime(t0.year - 1, t0.month + 6, t0.day, t0.hour, t0.minute, t0.second, t0.microsecond)
|
|---|
| 3032 | else:
|
|---|
| 3033 | t = datetime.datetime(t0.year, t0.month - 6, t0.day, t0.hour, t0.minute, t0.second, t0.microsecond)
|
|---|
| 3034 | else:
|
|---|
| 3035 | t = datetime.datetime(t0.year - 1, t0.month, t0.day, t0.hour, t0.minute, t0.second, t0.microsecond)
|
|---|
| 3036 |
|
|---|
| 3037 | for i in range(listLength):
|
|---|
| 3038 | tCoords.append(t + deltaFromParsedTime)
|
|---|
| 3039 | t = datetime.datetime(t.year + 1, t.month, t.day, t.hour, t.minute, t.second, t.microsecond)
|
|---|
| 3040 |
|
|---|
| 3041 | else:
|
|---|
| 3042 | raise NotImplementedError(_(u'Programming error in this tool: the t increment unit \'%(unit)s\' is not currently supported. Please contact the author of this tool for assistance.') % {u'unit': self.TIncrementUnit})
|
|---|
| 3043 |
|
|---|
| 3044 | # Return the list of coordinates.
|
|---|
| 3045 |
|
|---|
| 3046 | return tCoords
|
|---|
| 3047 |
|
|---|
| 3048 | def _GetScaledDataAsArray(self, key):
|
|---|
| 3049 | unscaledData = self._GetUnscaledDataAsArray(key)
|
|---|
| 3050 | data = self.GetLazyPropertyValue('ScalingFunction')(unscaledData)
|
|---|
| 3051 |
|
|---|
| 3052 | if data.dtype.name != self.DataType:
|
|---|
| 3053 | import numpy
|
|---|
| 3054 | data = numpy.cast[str(self.DataType)](data)
|
|---|
| 3055 |
|
|---|
| 3056 | if self.UnscaledNoDataValue is not None and self.NoDataValue is not None:
|
|---|
| 3057 | if data.ndim > 0:
|
|---|
| 3058 | data[unscaledData == self.UnscaledNoDataValue] = self.NoDataValue
|
|---|
| 3059 | elif unscaledData == self.UnscaledNoDataValue:
|
|---|
| 3060 | import numpy
|
|---|
| 3061 | return numpy.array(self.NoDataValue, data.dtype)
|
|---|
| 3062 |
|
|---|
| 3063 | return data
|
|---|
| 3064 |
|
|---|
| 3065 | def _SetScaledDataWithArray(self, key, value):
|
|---|
| 3066 | unscaledData = self.GetLazyPropertyValue('UnscalingFunction')(value)
|
|---|
| 3067 |
|
|---|
| 3068 | if self.UnscaledNoDataValue is not None and self.NoDataValue is not None:
|
|---|
| 3069 | if unscaledData.ndim > 0:
|
|---|
| 3070 | unscaledData[unscaledData == self.NoDataValue] = self.UnscaledNoDataValue
|
|---|
| 3071 | elif unscaledData == self.UnscaledNoDataValue:
|
|---|
| 3072 | import numpy
|
|---|
| 3073 | return numpy.array(self.UnscaledNoDataValue, unscaledData.dtype)
|
|---|
| 3074 |
|
|---|
| 3075 | self._SetUnscaledDataWithArray(key, unscaledData)
|
|---|
| 3076 |
|
|---|
| 3077 | def _GetUnscaledDataAsArray(self, key):
|
|---|
| 3078 |
|
|---|
| 3079 | # Validate the key and if any of the phyical dimensions are
|
|---|
| 3080 | # flipped (e.g. the y coordinate decreases as the y index
|
|---|
| 3081 | # increases), flip the key indices for those dimensions.
|
|---|
| 3082 |
|
|---|
| 3083 | flippedKey = self._ValidateAndFlipKey(key)
|
|---|
| 3084 |
|
|---|
| 3085 | # Convert the flipped key to a list of slices to specify to
|
|---|
| 3086 | # the derived class the hyperslab of physical data that we
|
|---|
| 3087 | # want. For the convenience of the derived class, there is a
|
|---|
| 3088 | # slice for every dimension, with non-negative start and stop
|
|---|
| 3089 | # attributes, start <= stop, and step == None.
|
|---|
| 3090 |
|
|---|
| 3091 | sliceList = self._GetSlicesForFlippedKey(flippedKey)
|
|---|
| 3092 |
|
|---|
| 3093 | # If the physical dimension order is different than our
|
|---|
| 3094 | # standard order (tzyx), reorder the slices into the physical
|
|---|
| 3095 | # order.
|
|---|
| 3096 |
|
|---|
| 3097 | physicalDimensions = self.GetLazyPropertyValue('PhysicalDimensions')
|
|---|
| 3098 | if self.Dimensions != physicalDimensions:
|
|---|
| 3099 | reorderedSliceList = []
|
|---|
| 3100 | for dim in physicalDimensions:
|
|---|
| 3101 | reorderedSliceList.append(sliceList[self.Dimensions.index(dim)])
|
|---|
| 3102 | else:
|
|---|
| 3103 | reorderedSliceList = sliceList
|
|---|
| 3104 |
|
|---|
| 3105 | # Get a numpy array for the slice list. This may take some
|
|---|
| 3106 | # time; the data could be on a remote server; it may need to
|
|---|
| 3107 | # be downloaded and/or decompressed.
|
|---|
| 3108 |
|
|---|
| 3109 | data, actualNoDataValue = self._ReadNumpyArray(reorderedSliceList)
|
|---|
| 3110 |
|
|---|
| 3111 | # If the physical dimension order is different than our
|
|---|
| 3112 | # standard order, transpose the returned numpy array to our
|
|---|
| 3113 | # standard order.
|
|---|
| 3114 |
|
|---|
| 3115 | if self.Dimensions != physicalDimensions:
|
|---|
| 3116 | transposeList = []
|
|---|
| 3117 | for dim in self.Dimensions:
|
|---|
| 3118 | transposeList.append(physicalDimensions.index(dim))
|
|---|
| 3119 |
|
|---|
| 3120 | if transposeList not in [[0,1], [0,1,2], [0,1,2,3]]:
|
|---|
| 3121 | data = data.transpose(transposeList)
|
|---|
| 3122 |
|
|---|
| 3123 | # The array that we got back has the shape described by the
|
|---|
| 3124 | # key but we cannot use the key to index into it because the
|
|---|
| 3125 | # key refers to an array with the full shape, not this reduced
|
|---|
| 3126 | # shape. Adjust the key indices to the reduced shape.
|
|---|
| 3127 |
|
|---|
| 3128 | flippedKey = self._AdjustFlippedKeyIndicesToReducedShape(flippedKey)
|
|---|
| 3129 |
|
|---|
| 3130 | # If the dataset should use a different NoData value and/or
|
|---|
| 3131 | # data type than what was returned, change the array to use
|
|---|
| 3132 | # the desired NoData value and/or recast it to use the desired
|
|---|
| 3133 | # data type.
|
|---|
| 3134 |
|
|---|
| 3135 | if self.UnscaledNoDataValue is not None and ((isinstance(self.UnscaledNoDataValue, types.IntType) and int(actualNoDataValue) != self.UnscaledNoDataValue or isinstance(self.UnscaledNoDataValue, types.FloatType) and actualNoDataValue != self.UnscaledNoDataValue)):
|
|---|
| 3136 | if data.dtype.kind == 'i':
|
|---|
| 3137 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Changing the NoData value of the returned data from %(v1)i to %(v2)i.') % {u'class': self.__class__.__name__, u'id': id(self), u'v1': int(actualNoDataValue), u'v2': self.UnscaledNoDataValue})
|
|---|
| 3138 | data[data == int(actualNoDataValue)] = self.UnscaledNoDataValue
|
|---|
| 3139 | else:
|
|---|
| 3140 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Changing the NoData value of the returned data from %(v1)g to %(v2)g.') % {u'class': self.__class__.__name__, u'id': id(self), u'v1': actualNoDataValue, u'v2': self.UnscaledNoDataValue})
|
|---|
| 3141 | data[data == actualNoDataValue] = self.UnscaledNoDataValue
|
|---|
| 3142 |
|
|---|
| 3143 | if data.dtype.name != self.UnscaledDataType:
|
|---|
| 3144 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Changing the data type of the returned data from %(t1)s to %(t2)s.') % {u'class': self.__class__.__name__, u'id': id(self), u't1': data.dtype.name, u't2': self.UnscaledDataType})
|
|---|
| 3145 | import numpy
|
|---|
| 3146 | data = numpy.cast[str(self.UnscaledDataType)](data)
|
|---|
| 3147 |
|
|---|
| 3148 | # Return the data.
|
|---|
| 3149 |
|
|---|
| 3150 | if len(flippedKey) == 1:
|
|---|
| 3151 | return data.__getitem__(flippedKey[0])
|
|---|
| 3152 |
|
|---|
| 3153 | return data.__getitem__(tuple(flippedKey))
|
|---|
| 3154 |
|
|---|
| 3155 | def _ValidateAndFlipKey(self, key):
|
|---|
| 3156 |
|
|---|
| 3157 | # Validate the key. In numpy terminology, we support single
|
|---|
| 3158 | # element indexing and slice indexing. We do not support index
|
|---|
| 3159 | # arrays (either of integers or booleans). Thus, the key must
|
|---|
| 3160 | # follow these rules:
|
|---|
| 3161 | #
|
|---|
| 3162 | # 1. It must be an integer, a slice, or a tuple.
|
|---|
| 3163 | #
|
|---|
| 3164 | # 2. If a tuple, it may only contain integers and slices.
|
|---|
| 3165 | #
|
|---|
| 3166 | # 3. The tuple may contain no more elements than the
|
|---|
| 3167 | # dimensions of the grid.
|
|---|
| 3168 |
|
|---|
| 3169 | if not isinstance(key, (int, slice, tuple)):
|
|---|
| 3170 | raise TypeError(_(u'The key must be an integer, a slice, or a tuple of integers and slices.'))
|
|---|
| 3171 |
|
|---|
| 3172 | if not isinstance(key, tuple):
|
|---|
| 3173 | key = (key,)
|
|---|
| 3174 |
|
|---|
| 3175 | if len(key) > len(self.Dimensions):
|
|---|
| 3176 | raise IndexError(_(u'Too many indices.'))
|
|---|
| 3177 |
|
|---|
| 3178 | for i in range(len(key)):
|
|---|
| 3179 | if not isinstance(key[i], (int, slice)) or isinstance(key[i], slice) and (not isinstance(key[i].start, (int, types.NoneType)) or not isinstance(key[i].stop, (int, types.NoneType)) or not isinstance(key[i].step, (int, types.NoneType))):
|
|---|
| 3180 | raise IndexError(_(u'Indices must be integers or integer slices.'))
|
|---|
| 3181 | if isinstance(key[i], int):
|
|---|
| 3182 | if key[i] >= self.Shape[i]:
|
|---|
| 3183 | raise IndexError(_(u'Index out of bounds for dimension \'%(dim)s\'; %(val)i > dimension length %(len)i.') % {u'dim': self.Dimensions[i], u'val': key[i], u'len': self.Shape[i]})
|
|---|
| 3184 | elif key[i] < 0 - self.Shape[i]:
|
|---|
| 3185 | raise IndexError(_(u'Index out of bounds for dimension \'%(dim)s\'; %(val)i < 0 - dimension length %(len)i.') % {u'dim': self.Dimensions[i], u'val': key[i], u'len': self.Shape[i]})
|
|---|
| 3186 |
|
|---|
| 3187 | # If any of the phyical dimensions are flipped (e.g. the y
|
|---|
| 3188 | # coordinate decreases as the y index increases), flip the key
|
|---|
| 3189 | # indices for those dimensions. As shown in the following
|
|---|
| 3190 | # example, we can flip an integer index by multiplying by -1
|
|---|
| 3191 | # and subtracting 1. We can flip a slice by doing the same
|
|---|
| 3192 | # operation with start and stop and multiplying step by -1.
|
|---|
| 3193 | #
|
|---|
| 3194 | # >>> x1
|
|---|
| 3195 | # [0, 1, 2, 3, 4, 5]
|
|---|
| 3196 | # >>> x2
|
|---|
| 3197 | # [5, 4, 3, 2, 1, 0]
|
|---|
| 3198 | # >>>
|
|---|
| 3199 | # >>> x1[1]
|
|---|
| 3200 | # 1
|
|---|
| 3201 | # >>> x2[-2]
|
|---|
| 3202 | # 1
|
|---|
| 3203 | # >>>
|
|---|
| 3204 | # >>> x1.__getitem__(slice(3,5,1))
|
|---|
| 3205 | # [3, 4]
|
|---|
| 3206 | # >>> x2.__getitem__(slice(-4,-6,-1))
|
|---|
| 3207 | # [3, 4]
|
|---|
| 3208 | # >>>
|
|---|
| 3209 | # >>> x1.__getitem__(slice(-5,-3,1))
|
|---|
| 3210 | # [1, 2]
|
|---|
| 3211 | # >>> x2.__getitem__(slice(4,2,-1))
|
|---|
| 3212 | # [1, 2]
|
|---|
| 3213 | # >>>
|
|---|
| 3214 | # >>> x1.__getitem__(slice(5,3,-1))
|
|---|
| 3215 | # [5, 4]
|
|---|
| 3216 | # >>> x2.__getitem__(slice(-6,-4,1))
|
|---|
| 3217 | # [5, 4]
|
|---|
| 3218 | # >>>
|
|---|
| 3219 | # >>> x1.__getitem__(slice(-3,-5,-1))
|
|---|
| 3220 | # [3, 2]
|
|---|
| 3221 | # >>> x2.__getitem__(slice(2,4,1))
|
|---|
| 3222 | # [3, 2]
|
|---|
| 3223 |
|
|---|
| 3224 | flippedKey = []
|
|---|
| 3225 | physicalDimensionsFlipped = self.GetLazyPropertyValue('PhysicalDimensionsFlipped')
|
|---|
| 3226 | for i in range(len(key)):
|
|---|
| 3227 | if physicalDimensionsFlipped[i]:
|
|---|
| 3228 | if isinstance(key[i], int):
|
|---|
| 3229 | flippedKey.append(-1*key[i] - 1)
|
|---|
| 3230 | else:
|
|---|
| 3231 | start, stop, step = key[i].start, key[i].stop, key[i].step
|
|---|
| 3232 | if start is not None:
|
|---|
| 3233 | start = -1*start -1
|
|---|
| 3234 | if stop is not None:
|
|---|
| 3235 | stop = -1*stop -1
|
|---|
| 3236 | if step is not None:
|
|---|
| 3237 | step = -1*step
|
|---|
| 3238 | else:
|
|---|
| 3239 | step = -1 # If step is None, it defaults to 1, so flipping None results in -1
|
|---|
| 3240 | flippedKey.append(slice(start, stop, step))
|
|---|
| 3241 | else:
|
|---|
| 3242 | flippedKey.append(key[i])
|
|---|
| 3243 |
|
|---|
| 3244 | return flippedKey
|
|---|
| 3245 |
|
|---|
| 3246 | def _GetSlicesForFlippedKey(self, flippedKey):
|
|---|
| 3247 | sliceList = []
|
|---|
| 3248 |
|
|---|
| 3249 | for i in range(len(self.Dimensions)):
|
|---|
| 3250 | if i < len(flippedKey):
|
|---|
| 3251 | if isinstance(flippedKey[i], slice):
|
|---|
| 3252 | indices = flippedKey[i].indices(self.Shape[i])
|
|---|
| 3253 | if indices[0] <= indices[1]:
|
|---|
| 3254 | sliceList.append(slice(indices[0], indices[1]))
|
|---|
| 3255 | else:
|
|---|
| 3256 | sliceList.append(slice(indices[1]+1, indices[0]+1))
|
|---|
| 3257 | elif flippedKey[i] >= 0:
|
|---|
| 3258 | sliceList.append(slice(flippedKey[i], flippedKey[i] + 1))
|
|---|
| 3259 | else:
|
|---|
| 3260 | sliceList.append(slice(self.Shape[i] + flippedKey[i], self.Shape[i] + flippedKey[i] + 1))
|
|---|
| 3261 | else:
|
|---|
| 3262 | sliceList.append(slice(0, self.Shape[i]))
|
|---|
| 3263 |
|
|---|
| 3264 | return sliceList
|
|---|
| 3265 |
|
|---|
| 3266 | def _AdjustFlippedKeyIndicesToReducedShape(self, flippedKey):
|
|---|
| 3267 | newFlippedKey = []
|
|---|
| 3268 |
|
|---|
| 3269 | for i in range(len(flippedKey)):
|
|---|
| 3270 | if isinstance(flippedKey[i], int):
|
|---|
| 3271 | newFlippedKey.append(0)
|
|---|
| 3272 | else:
|
|---|
| 3273 | start, stop, step = flippedKey[i].indices(self.Shape[i])
|
|---|
| 3274 | adjustment = min(start, stop)
|
|---|
| 3275 | start -= adjustment
|
|---|
| 3276 | stop -= adjustment
|
|---|
| 3277 | if start == 0:
|
|---|
| 3278 | start = None
|
|---|
| 3279 | if stop == 0:
|
|---|
| 3280 | stop = None
|
|---|
| 3281 | newFlippedKey.append(slice(start, stop, step))
|
|---|
| 3282 |
|
|---|
| 3283 | return newFlippedKey
|
|---|
| 3284 |
|
|---|
| 3285 | def _SetUnscaledDataWithArray(self, key, value):
|
|---|
| 3286 |
|
|---|
| 3287 | # TODO: Validate that this grid is writable.
|
|---|
| 3288 |
|
|---|
| 3289 | # Validate the key and if any of the phyical dimensions are
|
|---|
| 3290 | # flipped (e.g. the y coordinate decreases as the y index
|
|---|
| 3291 | # increases), flip the key indices for those dimensions
|
|---|
| 3292 |
|
|---|
| 3293 | flippedKey = self._ValidateAndFlipKey(key)
|
|---|
| 3294 |
|
|---|
| 3295 | # Validate that the value is either a numpy array, an integer,
|
|---|
| 3296 | # a float, or a complex.
|
|---|
| 3297 |
|
|---|
| 3298 | import numpy
|
|---|
| 3299 | if not isinstance(value, (numpy.ndarray, int, float, complex)):
|
|---|
| 3300 | raise TypeError(_(u'The value must be a numpy array, an int, a float, or a complex.'))
|
|---|
| 3301 |
|
|---|
| 3302 | # Validate that the value contains the expected number of
|
|---|
| 3303 | # elements.
|
|---|
| 3304 |
|
|---|
| 3305 | expectedSize = 1
|
|---|
| 3306 | expectedShape = []
|
|---|
| 3307 |
|
|---|
| 3308 | for i in range(len(self.Dimensions)):
|
|---|
| 3309 | if i >= len(key):
|
|---|
| 3310 | length = self.Shape[i]
|
|---|
| 3311 | elif isinstance(key[i], slice):
|
|---|
| 3312 | length = len(range(*key[i].indices(self.Shape[i])))
|
|---|
| 3313 | else:
|
|---|
| 3314 | length = 1
|
|---|
| 3315 | expectedSize *= length
|
|---|
| 3316 | expectedShape.append(length)
|
|---|
| 3317 |
|
|---|
| 3318 | if expectedSize == 0:
|
|---|
| 3319 | if not isinstance(value, numpy.ndarray) or value.size != 0:
|
|---|
| 3320 | raise ValueError(_(u'The key and value do not match: the key describes an array of size %(expected)i, but the value is an array of size %(actual)i.') % {u'expected': 0, u'actual': value.size})
|
|---|
| 3321 | elif expectedSize == 1:
|
|---|
| 3322 | if isinstance(value, numpy.ndarray) and value.size != 1:
|
|---|
| 3323 | raise ValueError(_(u'The key and value do not match: the key describes an array of size %(expected)i, but the value is an array of size %(actual)i.') % {u'expected': 1, u'actual': value.size})
|
|---|
| 3324 | else:
|
|---|
| 3325 | if not isinstance(value, numpy.ndarray):
|
|---|
| 3326 | raise ValueError(_(u'The key and value do not match: the key describes an array of size %(expected)i, but the value is not an array.') % {u'expected': expectedSize})
|
|---|
| 3327 | if value.size != expectedSize:
|
|---|
| 3328 | raise ValueError(_(u'The key and value do not match: the key describes an array of size %(expected)i, but the value is an array of size %(actual)i.') % {u'expected': expectedSize, u'actual': value.size})
|
|---|
| 3329 |
|
|---|
| 3330 | # If the value is not an array, make it one.
|
|---|
| 3331 |
|
|---|
| 3332 | if not isinstance(value, numpy.ndarray):
|
|---|
| 3333 | value = numpy.array(value)
|
|---|
| 3334 |
|
|---|
| 3335 | # Reshape the array to the expected shape. This will expand
|
|---|
| 3336 | # the dimensions (if needed).
|
|---|
| 3337 |
|
|---|
| 3338 | value = value.reshape(expectedShape)
|
|---|
| 3339 |
|
|---|
| 3340 | # Convert the flipped key to a list of slices to specify to
|
|---|
| 3341 | # the derived class the hyperslab of physical data that we're
|
|---|
| 3342 | # going to write. For the convenience of the derived class,
|
|---|
| 3343 | # there is a slice for every dimension, with positive start
|
|---|
| 3344 | # and stop attributes, start <= stop, and step == None.
|
|---|
| 3345 | #
|
|---|
| 3346 | # Also determine whether we need to flip any of the axes of
|
|---|
| 3347 | # the caller's array prior to passing it to the derived class,
|
|---|
| 3348 | # so the derived class does not need to worry about writing it
|
|---|
| 3349 | # in reverse order.
|
|---|
| 3350 | #
|
|---|
| 3351 | # Finally, if the caller's key included slices that have
|
|---|
| 3352 | # abs(step) != 1. If so, we save the caller the effort of
|
|---|
| 3353 | # having to stride the writes across the physical store: we
|
|---|
| 3354 | # read the hyperslab that encloses the entire range described
|
|---|
| 3355 | # by the caller's slices, apply the array in memory (allowing
|
|---|
| 3356 | # numpy to do the striding), and write the hyperslab back.
|
|---|
| 3357 |
|
|---|
| 3358 | sliceList = []
|
|---|
| 3359 | needToFlipData = []
|
|---|
| 3360 | largeStep = False
|
|---|
| 3361 | largeStepKey = []
|
|---|
| 3362 |
|
|---|
| 3363 | for i in range(len(self.Dimensions)):
|
|---|
| 3364 | if i < len(flippedKey):
|
|---|
| 3365 | if isinstance(key[i], slice):
|
|---|
| 3366 | start, stop, step = flippedKey[i].indices(self.Shape[i])
|
|---|
| 3367 | largeStep = largeStep or step is not None and abs(step) > 1
|
|---|
| 3368 | if step is not None and step < 0:
|
|---|
| 3369 | needToFlipData.append(True)
|
|---|
| 3370 | rstart = start + step*((stop-start+1) // step)
|
|---|
| 3371 | rstop = start+1
|
|---|
| 3372 | rstep = -1*step
|
|---|
| 3373 | sliceList.append(slice(rstart, rstop))
|
|---|
| 3374 | largeStepKey.append(slice(0, rstop-rstart, rstep))
|
|---|
| 3375 | else:
|
|---|
| 3376 | needToFlipData.append(False)
|
|---|
| 3377 | sliceList.append(slice(start, stop))
|
|---|
| 3378 | largeStepKey.append(slice(0, stop-start, step))
|
|---|
| 3379 | else:
|
|---|
| 3380 | needToFlipData.append(False)
|
|---|
| 3381 | if flippedKey[i] >= 0:
|
|---|
| 3382 | sliceList.append(slice(flippedKey[i], flippedKey[i] + 1))
|
|---|
| 3383 | else:
|
|---|
| 3384 | sliceList.append(slice(self.Shape[i] + flippedKey[i], self.Shape[i] + flippedKey[i] + 1))
|
|---|
| 3385 | largeStepKey.append(slice(None))
|
|---|
| 3386 | else:
|
|---|
| 3387 | needToFlipData.append(physicalDimensionsFlipped[i])
|
|---|
| 3388 | sliceList.append(slice(0, self.Shape[i]))
|
|---|
| 3389 | largeStepKey.append(slice(None))
|
|---|
| 3390 |
|
|---|
| 3391 | # If we need to flip any of the axes of the caller's array, do
|
|---|
| 3392 | # it now.
|
|---|
| 3393 |
|
|---|
| 3394 | if True in needToFlipData:
|
|---|
| 3395 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Flipping the following axes prior to writing data: %(axes)s'), {u'class': self.__class__.__name__, u'id': id(self), u'axes': ', '.join(filter(lambda d: needToFlipData[self.Dimensions.index(d)], self.Dimensions))})
|
|---|
| 3396 | value = value.__getitem__(map(lambda f: slice(None, None, {True: -1, False: None}[f]), needToFlipData))
|
|---|
| 3397 |
|
|---|
| 3398 | # If the physical dimension order is different than our
|
|---|
| 3399 | # standard order (tzyx), reorder the slices and data into the
|
|---|
| 3400 | # physical order.
|
|---|
| 3401 |
|
|---|
| 3402 | physicalDimensions = self.GetLazyPropertyValue('PhysicalDimensions')
|
|---|
| 3403 | if self.Dimensions != physicalDimensions:
|
|---|
| 3404 | reorderedSliceList = []
|
|---|
| 3405 | reorderedLargeStepKey = []
|
|---|
| 3406 | transposeList = []
|
|---|
| 3407 |
|
|---|
| 3408 | for dim in physicalDimensions:
|
|---|
| 3409 | reorderedSliceList.append(sliceList[self.Dimensions.index(dim)])
|
|---|
| 3410 | reorderedLargeStepKey.append(largeStepKey[self.Dimensions.index(dim)])
|
|---|
| 3411 | transposeList.append(physicalDimensions.index(dim))
|
|---|
| 3412 |
|
|---|
| 3413 | value = value.transpose(transposeList)
|
|---|
| 3414 | else:
|
|---|
| 3415 | reorderedSliceList = sliceList
|
|---|
| 3416 | reorderedLargeStepKey = largeStepKey
|
|---|
| 3417 |
|
|---|
| 3418 | # If the data type of the value is not the same as this
|
|---|
| 3419 | # dataset, cast the value to the correct data type.
|
|---|
| 3420 |
|
|---|
| 3421 | if value.dtype.name != self.UnscaledDataType:
|
|---|
| 3422 | if not numpy.can_cast(value.dtype, str(self.UnscaledDataType)):
|
|---|
| 3423 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Warning: casting from %(dt1)s to %(dt2)s. The loss of precision may produce unexpected results.'), {u'class': self.__class__.__name__, u'id': id(self), u'dt1': value.dtype.name, u'dt2': self.UnscaledDataType})
|
|---|
| 3424 | value = numpy.cast[str(self.UnscaledDataType)](value)
|
|---|
| 3425 |
|
|---|
| 3426 | # If the caller's key included slices that have abs(step) > 1,
|
|---|
| 3427 | # read the hyperslab that encloses the entire range described
|
|---|
| 3428 | # by the caller's slices, apply the array in memory (allowing
|
|---|
| 3429 | # numpy to do the striding), and write it back.
|
|---|
| 3430 |
|
|---|
| 3431 | if largeStep:
|
|---|
| 3432 | existingData, actualNoDataValue = self._ReadNumpyArray(reorderedSliceList) # TODO: What about actualNoDataValue here?
|
|---|
| 3433 |
|
|---|
| 3434 | if existingData.dtype.name != value.dtype.name:
|
|---|
| 3435 | self._LogDebug(_(u'%(class)s 0x%(id)08X: Changing the data type of the returned data from %(t1)s to %(t2)s.') % {u'class': self.__class__.__name__, u'id': id(self), u't1': existingData.dtype.name, u't2': value.dtype.name})
|
|---|
| 3436 | existingData = numpy.cast[str(value.dtype.name)](existingData)
|
|---|
| 3437 |
|
|---|
| 3438 | existingData.__setitem__(largeStepKey, value)
|
|---|
| 3439 |
|
|---|
| 3440 | self._WriteNumpyArray(reorderedSliceList, existingData)
|
|---|
| 3441 |
|
|---|
| 3442 | # Otherwise just write the data (no need to read the existing
|
|---|
| 3443 | # data first).
|
|---|
| 3444 |
|
|---|
| 3445 | else:
|
|---|
| 3446 | self._WriteNumpyArray(reorderedSliceList, value)
|
|---|
| 3447 |
|
|---|
| 3448 | # Private methods that the derived class must override (except
|
|---|
| 3449 | # _GetCoords when the derived class only uses fixed coordinate
|
|---|
| 3450 | # increments).
|
|---|
| 3451 |
|
|---|
| 3452 | def _GetCoords(self, coord, coordNum, slices, sliceDims, fixedIncrementOffset):
|
|---|
| 3453 | raise NotImplementedError(_(u'The _GetCoords method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 3454 |
|
|---|
| 3455 | def _ReadNumpyArray(self, sliceList):
|
|---|
| 3456 | raise NotImplementedError(_(u'The _ReadNumpyArray method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 3457 |
|
|---|
| 3458 | def _WriteNumpyArray(self, sliceList, data):
|
|---|
| 3459 | raise NotImplementedError(_(u'The _WriteNumpyArray method of class %s has not been implemented.') % self.__class__.__name__)
|
|---|
| 3460 |
|
|---|
| 3461 |
|
|---|
| 3462 | class _ContainerEmulator(object): # Private helper class for Grid
|
|---|
| 3463 | def __init__(self, grid, getMethod, setMethod=None):
|
|---|
| 3464 | self._Grid = weakref.ref(grid) # This must be a weak reference so that we do not create a reference cycle and prevent the Grid instance from being garbage collected.
|
|---|
| 3465 | self._GetMethod = getMethod
|
|---|
| 3466 | self._SetMethod = setMethod
|
|---|
| 3467 |
|
|---|
| 3468 | def __getitem__(self, key):
|
|---|
| 3469 | return getattr(self._Grid(), self._GetMethod)(key)
|
|---|
| 3470 |
|
|---|
| 3471 | def __setitem__(self, key, value):
|
|---|
| 3472 | if self._SetMethod is None:
|
|---|
| 3473 | raise TypeError('This property does not support item assignment')
|
|---|
| 3474 | return getattr(self._Grid(), self._SetMethod)(key, value)
|
|---|
| 3475 |
|
|---|
| 3476 |
|
|---|
| 3477 | class NumpyGrid(Grid):
|
|---|
| 3478 | __doc__ = DynamicDocString()
|
|---|
| 3479 |
|
|---|
| 3480 | def _GetArray(self):
|
|---|
| 3481 | return self._NumpyArray
|
|---|
| 3482 |
|
|---|
| 3483 | Array = property(_GetArray, doc=DynamicDocString())
|
|---|
| 3484 |
|
|---|
| 3485 | def __init__(self, numpyArray, displayName, spatialReference, dimensions, coordIncrements, cornerCoords, unscaledNoDataValue=None,
|
|---|
| 3486 | tIncrementUnit=None, tSemiRegularity=None, tCountPerSemiRegularPeriod=None, tCornerCoordType=None, tOffsetFromParsedTime=None, coordDependencies=None,
|
|---|
| 3487 | physicalDimensions=None, physicalDimensionsFlipped=None,
|
|---|
| 3488 | scaledDataType=None, scaledNoDataValue=None, scalingFunction=None, unscalingFunction=None,
|
|---|
| 3489 | parentCollection=None, queryableAttributes=None, queryableAttributeValues=None, lazyPropertyValues=None):
|
|---|
| 3490 | self.__class__.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 3491 |
|
|---|
| 3492 | # Perform additional validation.
|
|---|
| 3493 |
|
|---|
| 3494 | if len(numpyArray.shape) not in [2, 3, 4]:
|
|---|
| 3495 | raise ValueError(_(u'numpyArray must have 2, 3, or 4 dimensions.'))
|
|---|
| 3496 |
|
|---|
| 3497 | if len(dimensions) != len(numpyArray.shape):
|
|---|
| 3498 | raise ValueError(_(u'The length of the dimensions string must be equal to the number of dimensions of numpyArray.'))
|
|---|
| 3499 |
|
|---|
| 3500 | if unscaledNoDataValue is not None:
|
|---|
| 3501 | if numpyArray.dtype.name in ['int8', 'uint8', 'int16', 'uint16', 'int32'] and not isinstance(unscaledNoDataValue, types.IntType):
|
|---|
| 3502 | raise TypeError(_(u'When numpyArray has the %(name)s dtype, unscaledNoDataValue must be a Python int.') % {u'name': numpyArray.dtype.name})
|
|---|
| 3503 | if numpyArray.dtype.name == 'uint32' and not isinstance(unscaledNoDataValue, (types.IntType, types.LongType)):
|
|---|
| 3504 | raise TypeError(_(u'When numpyArray has the %(name)s dtype, unscaledNoDataValue must be a Python int or long.') % {u'name': numpyArray.dtype.name})
|
|---|
| 3505 | if numpyArray.dtype.name in ['float32', 'float64'] and not isinstance(unscaledNoDataValue, types.FloatType):
|
|---|
| 3506 | raise TypeError(_(u'When numpyArray has the %(name)s dtype, unscaledNoDataValue must be a Python float.') % {u'name': numpyArray.dtype.name})
|
|---|
| 3507 |
|
|---|
| 3508 | if 't' in dimensions:
|
|---|
| 3509 | if tIncrementUnit is None:
|
|---|
| 3510 | raise ValueError(_(u'tIncrementUnit must be provided when dimensions contains \'t\'.'))
|
|---|
| 3511 | if tCornerCoordType is None:
|
|---|
| 3512 | raise ValueError(_(u'tCornerCoordType must be provided when dimensions contains \'t\'.'))
|
|---|
| 3513 |
|
|---|
| 3514 | if physicalDimensions is not None:
|
|---|
| 3515 | if len(physicalDimensions) != len(dimensions):
|
|---|
| 3516 | raise ValueError(_(u'physicalDimensions must be the same length as dimensions.'))
|
|---|
| 3517 | for d in physicalDimensions:
|
|---|
| 3518 | if d not in dimensions:
|
|---|
| 3519 | raise ValueError(_(u'The physicalDimensions string must contain the same characters as the dimensions string (but they may be in a different order).'))
|
|---|
| 3520 |
|
|---|
| 3521 | if not all((scaledDataType is not None, scaledNoDataValue is not None, scalingFunction is not None, unscalingFunction is not None)) and not all((scaledDataType is None, scaledNoDataValue is None, scalingFunction is None, unscalingFunction is None)):
|
|---|
| 3522 | raise ValueError(_(u'All of (scaledDataType, scaledNoDataValue, scalingFunction, unscalingFunction) must be None, or none of them must be None.'))
|
|---|
| 3523 |
|
|---|
| 3524 | # Initialize our properties.
|
|---|
| 3525 |
|
|---|
| 3526 | self._NumpyArray = numpyArray
|
|---|
| 3527 | self._DisplayName = displayName
|
|---|
| 3528 |
|
|---|
| 3529 | # Build a dictionary of lazy property values from the caller's
|
|---|
| 3530 | # parameters.
|
|---|
| 3531 |
|
|---|
| 3532 | if coordDependencies is None:
|
|---|
| 3533 | coordDependencies = tuple([None] * len(dimensions))
|
|---|
| 3534 |
|
|---|
| 3535 | if 't' not in dimensions:
|
|---|
| 3536 | tIncrementUnit = None
|
|---|
| 3537 | tSemiRegularity = None
|
|---|
| 3538 | tCountPerSemiRegularPeriod = None
|
|---|
| 3539 | tCornerCoordType = None
|
|---|
| 3540 | tOffsetFromParsedTime = None
|
|---|
| 3541 |
|
|---|
| 3542 | if physicalDimensions is None:
|
|---|
| 3543 | physicalDimensions = dimensions
|
|---|
| 3544 |
|
|---|
| 3545 | if physicalDimensionsFlipped is None:
|
|---|
| 3546 | physicalDimensionsFlipped = tuple([False] * len(dimensions))
|
|---|
| 3547 |
|
|---|
| 3548 | lpv = {'SpatialReference': spatialReference,
|
|---|
| 3549 | 'Dimensions': dimensions,
|
|---|
| 3550 | 'Shape': numpyArray.shape,
|
|---|
| 3551 | 'CoordDependencies': coordDependencies,
|
|---|
| 3552 | 'CoordIncrements': coordIncrements,
|
|---|
| 3553 | 'TIncrementUnit': tIncrementUnit,
|
|---|
| 3554 | 'TSemiRegularity': tSemiRegularity,
|
|---|
| 3555 | 'TCountPerSemiRegularPeriod': tCountPerSemiRegularPeriod,
|
|---|
| 3556 | 'TCornerCoordType': tCornerCoordType,
|
|---|
| 3557 | 'TOffsetFromParsedTime': tOffsetFromParsedTime,
|
|---|
| 3558 | 'CornerCoords': cornerCoords,
|
|---|
| 3559 | 'PhysicalDimensions': physicalDimensions,
|
|---|
| 3560 | 'PhysicalDimensionsFlipped': physicalDimensionsFlipped,
|
|---|
| 3561 | 'UnscaledDataType': numpyArray.dtype.name,
|
|---|
| 3562 | 'UnscaledNoDataValue': unscaledNoDataValue,
|
|---|
| 3563 | 'ScaledDataType': scaledDataType,
|
|---|
| 3564 | 'ScaledNoDataValue': scaledNoDataValue,
|
|---|
| 3565 | 'ScalingFunction': scalingFunction,
|
|---|
| 3566 | 'UnscalingFunction': unscalingFunction}
|
|---|
| 3567 |
|
|---|
| 3568 | if lazyPropertyValues is not None:
|
|---|
| 3569 | for name, value in lazyPropertyValues.items():
|
|---|
| 3570 | lpv[name] = value
|
|---|
| 3571 |
|
|---|
| 3572 | # Initialize the base class.
|
|---|
| 3573 |
|
|---|
| 3574 | super(NumpyGrid, self).__init__(parentCollection=parentCollection, queryableAttributes=queryableAttributes, queryableAttributeValues=queryableAttributeValues, lazyPropertyValues=lpv)
|
|---|
| 3575 |
|
|---|
| 3576 | def _GetDisplayName(self):
|
|---|
| 3577 | return self._DisplayName
|
|---|
| 3578 |
|
|---|
| 3579 | def _GetLazyPropertyPhysicalValue(self, name):
|
|---|
| 3580 | return None
|
|---|
| 3581 |
|
|---|
| 3582 | @classmethod
|
|---|
| 3583 | def _TestCapability(cls, capability):
|
|---|
| 3584 | if capability in ['setspatialreference']:
|
|---|
| 3585 | return None
|
|---|
| 3586 | if isinstance(cls, NumpyGrid):
|
|---|
| 3587 | return RuntimeError(_(u'The %(cls)s class does not support the "%(cap)s" capability.') % {u'cls': cls.__class__.__name__, u'cap': capability})
|
|---|
| 3588 | return RuntimeError(_(u'The %(cls)s class does not support the "%(cap)s" capability.') % {u'cls': cls.__name__, u'cap': capability})
|
|---|
| 3589 |
|
|---|
| 3590 | @classmethod
|
|---|
| 3591 | def _GetSRTypeForSetting(cls):
|
|---|
| 3592 | return 'Obj'
|
|---|
| 3593 |
|
|---|
| 3594 | def _SetSpatialReference(self, sr):
|
|---|
| 3595 | self.SetLazyPropertyValue('SpatialReference', sr)
|
|---|
| 3596 |
|
|---|
| 3597 | def _ReadNumpyArray(self, sliceList):
|
|---|
| 3598 | return self._NumpyArray.__getitem__(sliceList), self.GetLazyPropertyValue('UnscaledNoDataValue')
|
|---|
| 3599 |
|
|---|
| 3600 | def _WriteNumpyArray(self, sliceList, data):
|
|---|
| 3601 | self._NumpyArray.__setitem__(sliceList, data)
|
|---|
| 3602 |
|
|---|
| 3603 | @classmethod
|
|---|
| 3604 | def CreateFromGrid(cls, grid):
|
|---|
| 3605 | cls.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 3606 |
|
|---|
| 3607 | cornerCoords = [grid.CenterCoords[d, 0] for d in grid.Dimensions]
|
|---|
| 3608 | if 't' in grid.Dimensions:
|
|---|
| 3609 | if grid.GetLazyPropertyValue('TCornerCoordType') == 'min':
|
|---|
| 3610 | cornerCoords[0] = grid.MinCoords['t', 0]
|
|---|
| 3611 | elif grid.GetLazyPropertyValue('TCornerCoordType') == 'max':
|
|---|
| 3612 | cornerCoords[0] = grid.MaxCoords['t', 0]
|
|---|
| 3613 |
|
|---|
| 3614 | qav = {}
|
|---|
| 3615 | for qa in grid.GetAllQueryableAttributes():
|
|---|
| 3616 | qav[qa.Name] = grid.GetQueryableAttributeValue(qa.Name)
|
|---|
| 3617 |
|
|---|
| 3618 | return NumpyGrid(grid.Data[:],
|
|---|
| 3619 | grid.DisplayName,
|
|---|
| 3620 | grid.GetSpatialReference('Obj'),
|
|---|
| 3621 | grid.Dimensions,
|
|---|
| 3622 | grid.CoordIncrements,
|
|---|
| 3623 | tuple(cornerCoords),
|
|---|
| 3624 | grid.UnscaledNoDataValue,
|
|---|
| 3625 | grid.TIncrementUnit,
|
|---|
| 3626 | grid.TSemiRegularity,
|
|---|
| 3627 | grid.TCountPerSemiRegularPeriod,
|
|---|
| 3628 | grid.GetLazyPropertyValue('TCornerCoordType'),
|
|---|
| 3629 | grid.GetLazyPropertyValue('TOffsetFromParsedTime'),
|
|---|
| 3630 | grid.CoordDependencies,
|
|---|
| 3631 | queryableAttributes=tuple(grid.GetAllQueryableAttributes()),
|
|---|
| 3632 | queryableAttributeValues=qav)
|
|---|
| 3633 |
|
|---|
| 3634 |
|
|---|
| 3635 | ###############################################################################
|
|---|
| 3636 | # Metadata: module
|
|---|
| 3637 | ###############################################################################
|
|---|
| 3638 |
|
|---|
| 3639 | from GeoEco.Dependencies import PythonAggregatedModuleDependency
|
|---|
| 3640 | from GeoEco.Metadata import *
|
|---|
| 3641 | from GeoEco.Types import *
|
|---|
| 3642 |
|
|---|
| 3643 | AddModuleMetadata(shortDescription=_(u'Base classes that define interfaces for accessing tabular and gridded datasets.'))
|
|---|
| 3644 |
|
|---|
| 3645 | ###############################################################################
|
|---|
| 3646 | # Metadata: CollectibleObject class
|
|---|
| 3647 | ###############################################################################
|
|---|
| 3648 |
|
|---|
| 3649 | AddClassMetadata(CollectibleObject,
|
|---|
| 3650 | shortDescription=_(u'An object that can appear in a DatasetCollection.'),
|
|---|
| 3651 | longDescription=_(
|
|---|
| 3652 | u"""The primary purpose of CollectibleObject is to provide
|
|---|
| 3653 | functionality that is common to both Dataset and DatasetCollection, to
|
|---|
| 3654 | facilitate easy reuse of that functionality by both classes.
|
|---|
| 3655 | CollectibleObject should not be instantiated directly."""))
|
|---|
| 3656 |
|
|---|
| 3657 | # Public properties
|
|---|
| 3658 |
|
|---|
| 3659 | AddPropertyMetadata(CollectibleObject.DisplayName,
|
|---|
| 3660 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 3661 | shortDescription=_(u'Informal name of this object.'),
|
|---|
| 3662 | isExposedToPythonCallers=True)
|
|---|
| 3663 |
|
|---|
| 3664 | AddPropertyMetadata(CollectibleObject.ParentCollection,
|
|---|
| 3665 | typeMetadata=ClassInstanceTypeMetadata(cls=DatasetCollection, canBeNone=True),
|
|---|
| 3666 | shortDescription=_(u'DatasetCollection that is the parent of this object (if any).'),
|
|---|
| 3667 | isExposedToPythonCallers=True)
|
|---|
| 3668 |
|
|---|
| 3669 | # Public method: CollectibleObject.GetQueryableAttribute
|
|---|
| 3670 |
|
|---|
| 3671 | AddMethodMetadata(CollectibleObject.GetQueryableAttribute,
|
|---|
| 3672 | shortDescription=_(u'Returns the queryable attribute with the specified name.'),
|
|---|
| 3673 | isExposedToPythonCallers=True)
|
|---|
| 3674 |
|
|---|
| 3675 | AddArgumentMetadata(CollectibleObject.GetQueryableAttribute, u'self',
|
|---|
| 3676 | typeMetadata=ClassInstanceTypeMetadata(cls=CollectibleObject),
|
|---|
| 3677 | description=_(u'%s instance.') % CollectibleObject.__name__)
|
|---|
| 3678 |
|
|---|
| 3679 | AddArgumentMetadata(CollectibleObject.GetQueryableAttribute, u'name',
|
|---|
| 3680 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 3681 | description=_(
|
|---|
| 3682 | u"""Name of the queryable attribute to return."""))
|
|---|
| 3683 |
|
|---|
| 3684 | AddResultMetadata(CollectibleObject.GetQueryableAttribute, u'attr',
|
|---|
| 3685 | typeMetadata=ClassInstanceTypeMetadata(cls=QueryableAttribute, canBeNone=True),
|
|---|
| 3686 | description=_(
|
|---|
| 3687 | u"""QueryableAttribute instance with the specified name. If one is not
|
|---|
| 3688 | defined for this object, the chain of parent dataset collections (if
|
|---|
| 3689 | any) will be searched, starting with the immediate parent. If one is
|
|---|
| 3690 | still not found, None will be returned."""))
|
|---|
| 3691 |
|
|---|
| 3692 | # Public method: CollectibleObject.GetQueryableAttributesWithDataType
|
|---|
| 3693 |
|
|---|
| 3694 | AddMethodMetadata(CollectibleObject.GetQueryableAttributesWithDataType,
|
|---|
| 3695 | shortDescription=_(u'Returns a list queryable attributes having the specified data type.'),
|
|---|
| 3696 | isExposedToPythonCallers=True)
|
|---|
| 3697 |
|
|---|
| 3698 | CopyArgumentMetadata(CollectibleObject.GetQueryableAttribute, u'self', CollectibleObject.GetQueryableAttributesWithDataType, u'self')
|
|---|
| 3699 |
|
|---|
| 3700 | AddArgumentMetadata(CollectibleObject.GetQueryableAttributesWithDataType, u'typeMetadata',
|
|---|
| 3701 | typeMetadata=ClassTypeMetadata(cls=TypeMetadata),
|
|---|
| 3702 | description=_(
|
|---|
| 3703 | u"""Subclass of TypeMetadata that indicates the desired data type."""))
|
|---|
| 3704 |
|
|---|
| 3705 | AddResultMetadata(CollectibleObject.GetQueryableAttributesWithDataType, u'attrList',
|
|---|
| 3706 | typeMetadata=ListTypeMetadata(elementType=ClassInstanceTypeMetadata(cls=QueryableAttribute)),
|
|---|
| 3707 | description=_(
|
|---|
| 3708 | u"""List of QueryableAttribute instances having the specified data
|
|---|
| 3709 | type. This object and all of its parent dataset collections will be
|
|---|
| 3710 | searched for matching instances. If no matching instances are found,
|
|---|
| 3711 | the list will be empty."""))
|
|---|
| 3712 |
|
|---|
| 3713 | # Public method: CollectibleObject.GetAllQueryableAttributes
|
|---|
| 3714 |
|
|---|
| 3715 | AddMethodMetadata(CollectibleObject.GetAllQueryableAttributes,
|
|---|
| 3716 | shortDescription=_(u'Returns a list of all queryable attributes.'),
|
|---|
| 3717 | isExposedToPythonCallers=True)
|
|---|
| 3718 |
|
|---|
| 3719 | CopyArgumentMetadata(CollectibleObject.GetQueryableAttribute, u'self', CollectibleObject.GetAllQueryableAttributes, u'self')
|
|---|
| 3720 |
|
|---|
| 3721 | AddResultMetadata(CollectibleObject.GetAllQueryableAttributes, u'attrList',
|
|---|
| 3722 | typeMetadata=ListTypeMetadata(elementType=ClassInstanceTypeMetadata(cls=QueryableAttribute)),
|
|---|
| 3723 | description=_(
|
|---|
| 3724 | u"""List of QueryableAttribute instances defined for this object and
|
|---|
| 3725 | all of its parent dataset collections. If no instances have been
|
|---|
| 3726 | defined for it or any of its parents, the list will be empty."""))
|
|---|
| 3727 |
|
|---|
| 3728 | # Public method: CollectibleObject.GetQueryableAttributeValue
|
|---|
| 3729 |
|
|---|
| 3730 | AddMethodMetadata(CollectibleObject.GetQueryableAttributeValue,
|
|---|
| 3731 | shortDescription=_(u'Returns the value of the queryable attribute with the specified name.'),
|
|---|
| 3732 | isExposedToPythonCallers=True)
|
|---|
| 3733 |
|
|---|
| 3734 | CopyArgumentMetadata(CollectibleObject.GetQueryableAttribute, u'self', CollectibleObject.GetQueryableAttributeValue, u'self')
|
|---|
| 3735 |
|
|---|
| 3736 | AddArgumentMetadata(CollectibleObject.GetQueryableAttributeValue, u'name',
|
|---|
| 3737 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 3738 | description=_(
|
|---|
| 3739 | u"""Name of the queryable attribute to return the value of."""))
|
|---|
| 3740 |
|
|---|
| 3741 | AddResultMetadata(CollectibleObject.GetQueryableAttributeValue, u'value',
|
|---|
| 3742 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 3743 | description=_(
|
|---|
| 3744 | u"""Value of the queryable attribute with the specified name. If one
|
|---|
| 3745 | is not defined for this object, the chain of parent dataset
|
|---|
| 3746 | collections (if any) will be searched, starting with the immediate
|
|---|
| 3747 | parent. If one is still not found, None will be returned.
|
|---|
| 3748 |
|
|---|
| 3749 | None will also be returned if a queryable attribute is found but the
|
|---|
| 3750 | value of it is None. To determine whether None was returned because
|
|---|
| 3751 | the attribute's value was None or because the attribute does not
|
|---|
| 3752 | exist, use GetQueryableAttribute() to determine if the queryable
|
|---|
| 3753 | attribute exists."""))
|
|---|
| 3754 |
|
|---|
| 3755 | # Public method: CollectibleObject.TestCapability
|
|---|
| 3756 |
|
|---|
| 3757 | AddMethodMetadata(CollectibleObject.TestCapability,
|
|---|
| 3758 | shortDescription=_(u'Tests whether a capability is supported by this class or an instance of it.'),
|
|---|
| 3759 | longDescription=_(
|
|---|
| 3760 | u"""If called on an instance, this method tests whether the underlying
|
|---|
| 3761 | object represented by the instance supports the capability.
|
|---|
| 3762 |
|
|---|
| 3763 | If called on the class, this method tests whether at least one
|
|---|
| 3764 | instance can possibly support the capability. If no instances can ever
|
|---|
| 3765 | support the capability, this method will indicate that the capability
|
|---|
| 3766 | is not supported."""),
|
|---|
| 3767 | isExposedToPythonCallers=True)
|
|---|
| 3768 |
|
|---|
| 3769 | AddArgumentMetadata(CollectibleObject.TestCapability, u'cls',
|
|---|
| 3770 | typeMetadata=ClassOrClassInstanceTypeMetadata(cls=CollectibleObject),
|
|---|
| 3771 | description=_(u'%s class or an instance of it.') % CollectibleObject.__name__)
|
|---|
| 3772 |
|
|---|
| 3773 | AddArgumentMetadata(CollectibleObject.TestCapability, u'capability',
|
|---|
| 3774 | typeMetadata=UnicodeStringTypeMetadata(makeLowercase=True),
|
|---|
| 3775 | description=_(
|
|---|
| 3776 | u"""Capability to test.
|
|---|
| 3777 |
|
|---|
| 3778 | This function does not provide a list of capabilities that may be
|
|---|
| 3779 | tested. Please see the documentation for the other methods of this
|
|---|
| 3780 | class to determine what capabilties may be tested that are relevant to
|
|---|
| 3781 | those methods."""))
|
|---|
| 3782 |
|
|---|
| 3783 | AddResultMetadata(CollectibleObject.TestCapability, u'error',
|
|---|
| 3784 | typeMetadata=ClassInstanceTypeMetadata(cls=Exception, canBeNone=True),
|
|---|
| 3785 | description=_(
|
|---|
| 3786 | u"""None if the capability is supported, or an instance of Exception
|
|---|
| 3787 | if it is not supported. The string representation of the Exception
|
|---|
| 3788 | explains why the capability is not supported (if possible) in the
|
|---|
| 3789 | context of when it might be needed."""))
|
|---|
| 3790 |
|
|---|
| 3791 | # Private constructor: CollectibleObject.__init__
|
|---|
| 3792 |
|
|---|
| 3793 | AddMethodMetadata(CollectibleObject.__init__,
|
|---|
| 3794 | shortDescription=_(u'CollectibleObject constructor. Not intended to be called directly. Only intended to be called from derived class constructors.'))
|
|---|
| 3795 |
|
|---|
| 3796 | CopyArgumentMetadata(CollectibleObject.GetQueryableAttribute, u'self', CollectibleObject.__init__, u'self')
|
|---|
| 3797 |
|
|---|
| 3798 | AddArgumentMetadata(CollectibleObject.__init__, u'parentCollection',
|
|---|
| 3799 | typeMetadata=CollectibleObject.ParentCollection.__doc__.Obj.Type,
|
|---|
| 3800 | description=CollectibleObject.ParentCollection.__doc__.Obj.ShortDescription)
|
|---|
| 3801 |
|
|---|
| 3802 | AddArgumentMetadata(CollectibleObject.__init__, u'queryableAttributes',
|
|---|
| 3803 | typeMetadata=TupleTypeMetadata(elementType=ClassInstanceTypeMetadata(cls=QueryableAttribute), canBeNone=True),
|
|---|
| 3804 | description=_(u'Tuple of QueryableAttributes defined for this object and its children.')) # TODO: Add long description?
|
|---|
| 3805 |
|
|---|
| 3806 | AddArgumentMetadata(CollectibleObject.__init__, u'queryableAttributeValues',
|
|---|
| 3807 | typeMetadata=DictionaryTypeMetadata(keyType=UnicodeStringTypeMetadata(), valueType=AnyObjectTypeMetadata(canBeNone=True), canBeNone=True),
|
|---|
| 3808 | description=_(u'Mapping of case-insensitive QueryAttribute names to values defined for this object and its children.')) # TODO: Add longer description?
|
|---|
| 3809 |
|
|---|
| 3810 | AddArgumentMetadata(CollectibleObject.__init__, u'lazyPropertyValues',
|
|---|
| 3811 | typeMetadata=DictionaryTypeMetadata(keyType=UnicodeStringTypeMetadata(), valueType=AnyObjectTypeMetadata(canBeNone=True), canBeNone=True),
|
|---|
| 3812 | description=_(u'Mapping of lazy property names to values defined for this object.')) # TODO: Add longer description?
|
|---|
| 3813 |
|
|---|
| 3814 | AddResultMetadata(CollectibleObject.__init__, u'obj',
|
|---|
| 3815 | typeMetadata=ClassInstanceTypeMetadata(cls=CollectibleObject),
|
|---|
| 3816 | description=_(u'%s instance.') % CollectibleObject.__name__)
|
|---|
| 3817 |
|
|---|
| 3818 | ###############################################################################
|
|---|
| 3819 | # Metadata: QueryableAttribute class
|
|---|
| 3820 | ###############################################################################
|
|---|
| 3821 |
|
|---|
| 3822 | AddClassMetadata(QueryableAttribute,
|
|---|
| 3823 | shortDescription=_(u'Defines the characteristics of an attribute of a CollectibleObject that may be used to retrieve it from a DatasetCollection.')) # TODO: add longDescription
|
|---|
| 3824 |
|
|---|
| 3825 | # Public properties
|
|---|
| 3826 |
|
|---|
| 3827 | AddPropertyMetadata(QueryableAttribute.Name,
|
|---|
| 3828 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 3829 | shortDescription=_(u'Case-insensitive, non-localized formal name of this this queryable attribute.'))
|
|---|
| 3830 |
|
|---|
| 3831 | AddPropertyMetadata(QueryableAttribute.DisplayName,
|
|---|
| 3832 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 3833 | shortDescription=_(u'Localized informal name of this queryable attribute, to be displayed in user interfaces, log messages, and similar places.'))
|
|---|
| 3834 |
|
|---|
| 3835 | AddPropertyMetadata(QueryableAttribute.DataType,
|
|---|
| 3836 | typeMetadata=ClassInstanceTypeMetadata(cls=TypeMetadata),
|
|---|
| 3837 | shortDescription=_(u'TypeMetadata instance describing the data type this queryable attribute.')) # TODO: add long description
|
|---|
| 3838 |
|
|---|
| 3839 | AddPropertyMetadata(QueryableAttribute.DerivedLazyDatasetProps,
|
|---|
| 3840 | typeMetadata=DictionaryTypeMetadata(keyType=AnyObjectTypeMetadata(canBeNone=True), valueType=DictionaryTypeMetadata(keyType=UnicodeStringTypeMetadata(), valueType=AnyObjectTypeMetadata(canBeNone=True)), canBeNone=True),
|
|---|
| 3841 | shortDescription=_(u'Dictionary mapping values of this queryable attribute to names and values of lazy Dataset properties to assign.')) # TODO: add long description
|
|---|
| 3842 |
|
|---|
| 3843 | AddPropertyMetadata(QueryableAttribute.DerivedFromAttr,
|
|---|
| 3844 | typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
|
|---|
| 3845 | shortDescription=_(u'Name of another queryable attribute that this one is derived from.')) # TODO: add long description
|
|---|
| 3846 |
|
|---|
| 3847 | AddPropertyMetadata(QueryableAttribute.DerivedValueMap,
|
|---|
| 3848 | typeMetadata=DictionaryTypeMetadata(keyType=AnyObjectTypeMetadata(), valueType=AnyObjectTypeMetadata(), canBeNone=True),
|
|---|
| 3849 | shortDescription=_(u'Dictionary mapping values of the attribute that this one is derived from to values to use for this attribute.')) # TODO: add long description
|
|---|
| 3850 |
|
|---|
| 3851 | AddPropertyMetadata(QueryableAttribute.DerivedValueFunc,
|
|---|
| 3852 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 3853 | shortDescription=_(u'Function (may be a lambda) or method that should be called to derive the value of this attribute from the one it is derived from.')) # TODO: add long description
|
|---|
| 3854 |
|
|---|
| 3855 | # Public constructor: QueryableAttribute.__init__
|
|---|
| 3856 |
|
|---|
| 3857 | AddMethodMetadata(QueryableAttribute.__init__,
|
|---|
| 3858 | shortDescription=_(u'QueryableAttribute constructor.'))
|
|---|
| 3859 |
|
|---|
| 3860 | AddArgumentMetadata(QueryableAttribute.__init__, u'self',
|
|---|
| 3861 | typeMetadata=ClassInstanceTypeMetadata(cls=QueryableAttribute),
|
|---|
| 3862 | description=_(u'%s instance.') % QueryableAttribute.__name__)
|
|---|
| 3863 |
|
|---|
| 3864 | AddArgumentMetadata(QueryableAttribute.__init__, u'name',
|
|---|
| 3865 | typeMetadata=QueryableAttribute.Name.__doc__.Obj.Type,
|
|---|
| 3866 | description=QueryableAttribute.Name.__doc__.Obj.ShortDescription)
|
|---|
| 3867 |
|
|---|
| 3868 | AddArgumentMetadata(QueryableAttribute.__init__, u'displayName',
|
|---|
| 3869 | typeMetadata=QueryableAttribute.DisplayName.__doc__.Obj.Type,
|
|---|
| 3870 | description=QueryableAttribute.DisplayName.__doc__.Obj.ShortDescription)
|
|---|
| 3871 |
|
|---|
| 3872 | AddArgumentMetadata(QueryableAttribute.__init__, u'dataType',
|
|---|
| 3873 | typeMetadata=QueryableAttribute.DataType.__doc__.Obj.Type,
|
|---|
| 3874 | description=QueryableAttribute.DataType.__doc__.Obj.ShortDescription)
|
|---|
| 3875 |
|
|---|
| 3876 | AddArgumentMetadata(QueryableAttribute.__init__, u'derivedLazyDatasetProps',
|
|---|
| 3877 | typeMetadata=QueryableAttribute.DerivedLazyDatasetProps.__doc__.Obj.Type,
|
|---|
| 3878 | description=QueryableAttribute.DerivedLazyDatasetProps.__doc__.Obj.ShortDescription)
|
|---|
| 3879 |
|
|---|
| 3880 | AddArgumentMetadata(QueryableAttribute.__init__, u'derivedFromAttr',
|
|---|
| 3881 | typeMetadata=QueryableAttribute.DerivedFromAttr.__doc__.Obj.Type,
|
|---|
| 3882 | description=QueryableAttribute.DerivedFromAttr.__doc__.Obj.ShortDescription)
|
|---|
| 3883 |
|
|---|
| 3884 | AddArgumentMetadata(QueryableAttribute.__init__, u'derivedValueMap',
|
|---|
| 3885 | typeMetadata=QueryableAttribute.DerivedValueMap.__doc__.Obj.Type,
|
|---|
| 3886 | description=QueryableAttribute.DerivedValueMap.__doc__.Obj.ShortDescription)
|
|---|
| 3887 |
|
|---|
| 3888 | AddArgumentMetadata(QueryableAttribute.__init__, u'derivedValueFunc',
|
|---|
| 3889 | typeMetadata=QueryableAttribute.DerivedValueFunc.__doc__.Obj.Type,
|
|---|
| 3890 | description=QueryableAttribute.DerivedValueFunc.__doc__.Obj.ShortDescription)
|
|---|
| 3891 |
|
|---|
| 3892 | AddResultMetadata(QueryableAttribute.__init__, u'obj',
|
|---|
| 3893 | typeMetadata=ClassInstanceTypeMetadata(cls=QueryableAttribute),
|
|---|
| 3894 | description=_(u'%s instance.') % QueryableAttribute.__name__)
|
|---|
| 3895 |
|
|---|
| 3896 | ###############################################################################
|
|---|
| 3897 | # Metadata: Dataset class
|
|---|
| 3898 | ###############################################################################
|
|---|
| 3899 |
|
|---|
| 3900 | AddClassMetadata(Dataset,
|
|---|
| 3901 | shortDescription=_(u'Represents tabular or gridded dataset.'),
|
|---|
| 3902 | longDescription=_(
|
|---|
| 3903 | u"""The primary purpose of this class is to provide functionality that
|
|---|
| 3904 | is common to both the Table and Grid classes, such as properties and
|
|---|
| 3905 | methods relating to georeferencing, to facilitate easy reuse of that
|
|---|
| 3906 | functionality by both classes. We do not anticipate many scenarios
|
|---|
| 3907 | where someone will want to generically manipulate both Table and Grid
|
|---|
| 3908 | instances behind the Dataset abstraction."""))
|
|---|
| 3909 |
|
|---|
| 3910 | # Public method: Dataset.ConvertSpatialReference
|
|---|
| 3911 |
|
|---|
| 3912 | AddMethodMetadata(Dataset.ConvertSpatialReference,
|
|---|
| 3913 | shortDescription=_(u'Converts a spatial reference from one format to another, such as an OGC WKT string to a Proj4 string.'),
|
|---|
| 3914 | isExposedToPythonCallers=True)
|
|---|
| 3915 |
|
|---|
| 3916 | AddArgumentMetadata(Dataset.ConvertSpatialReference, u'cls',
|
|---|
| 3917 | typeMetadata=ClassOrClassInstanceTypeMetadata(cls=Dataset),
|
|---|
| 3918 | description=_(u'%s class or an instance of it.') % Dataset.__name__)
|
|---|
| 3919 |
|
|---|
| 3920 | AddArgumentMetadata(Dataset.ConvertSpatialReference, u'srType',
|
|---|
| 3921 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'WKT', u'ArcGIS', u'Proj4', u'Obj'], makeLowercase=True),
|
|---|
| 3922 | description=_(
|
|---|
| 3923 | u"""The kind of the spatial reference to convert, i.e. the type of
|
|---|
| 3924 | object you are providing for the sr parameter:
|
|---|
| 3925 |
|
|---|
| 3926 | * WKT - a WKT string in standard OGC format.
|
|---|
| 3927 |
|
|---|
| 3928 | * ArcGIS - a WKT string in ESRI format, typically obtained from
|
|---|
| 3929 | a dataset produced by ArcGIS. (The ESRI format differs from the OGC
|
|---|
| 3930 | standard; various projections and parameters are named differently
|
|---|
| 3931 | and certain nodes are not recognized. See the OSR documentation for
|
|---|
| 3932 | more information.)
|
|---|
| 3933 |
|
|---|
| 3934 | * Proj4 - a string in the format recognized by the Proj4 library.
|
|---|
| 3935 |
|
|---|
| 3936 | * Obj - an instance of the OSR SpatialReference class.
|
|---|
| 3937 | """))
|
|---|
| 3938 |
|
|---|
| 3939 | # TODO: Talk about allocation and deallocation of OSR SpatialReference objects
|
|---|
| 3940 |
|
|---|
| 3941 | AddArgumentMetadata(Dataset.ConvertSpatialReference, u'sr',
|
|---|
| 3942 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 3943 | description=_(
|
|---|
| 3944 | u"""Spatial reference to convert. This may be None, representing an
|
|---|
| 3945 | "undefined" spatial reference, but see the documentation for the
|
|---|
| 3946 | outputSRType parameter."""))
|
|---|
| 3947 |
|
|---|
| 3948 | AddArgumentMetadata(Dataset.ConvertSpatialReference, u'outputSRType',
|
|---|
| 3949 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'WKT', u'ArcGIS', u'Proj4', u'Obj'], makeLowercase=True),
|
|---|
| 3950 | description=_(
|
|---|
| 3951 | u"""The kind of the spatial reference to return. The allowed values
|
|---|
| 3952 | are the same as for the srType parameter.
|
|---|
| 3953 |
|
|---|
| 3954 | If srType and outputSRType are the same, a copy of the input spatial
|
|---|
| 3955 | reference will be returned. If they are 'Obj', a deep copy of the
|
|---|
| 3956 | input OSR SpatialReference instance will be created by initializing a
|
|---|
| 3957 | new instance from the OGC WKT exported from the input instance.
|
|---|
| 3958 |
|
|---|
| 3959 | If sr is None, None will be returned, except if outputSRType is
|
|---|
| 3960 | 'ArcGIS', in which case the string
|
|---|
| 3961 | '{B286C06B-0879-11D2-AACA-00C04FA33C20}' will be returned. ArcGIS uses
|
|---|
| 3962 | this string to represent the "Unknown" spatial reference."""))
|
|---|
| 3963 |
|
|---|
| 3964 | AddResultMetadata(Dataset.ConvertSpatialReference, u'outputSR',
|
|---|
| 3965 | typeMetadata=AnyObjectTypeMetadata(),
|
|---|
| 3966 | description=_(
|
|---|
| 3967 | u"""Spatial reference resulting from the conversion, either a Unicode
|
|---|
| 3968 | string, an OGR SpatialReference instance, or None."""))
|
|---|
| 3969 |
|
|---|
| 3970 | # Public method: Dataset.GetSpatialReference
|
|---|
| 3971 |
|
|---|
| 3972 | AddMethodMetadata(Dataset.GetSpatialReference,
|
|---|
| 3973 | shortDescription=_(u'Returns the spatial reference of this dataset.'),
|
|---|
| 3974 | isExposedToPythonCallers=True)
|
|---|
| 3975 |
|
|---|
| 3976 | AddArgumentMetadata(Dataset.GetSpatialReference, u'self',
|
|---|
| 3977 | typeMetadata=ClassInstanceTypeMetadata(cls=Dataset),
|
|---|
| 3978 | description=_(u'%s instance.') % Dataset.__name__)
|
|---|
| 3979 |
|
|---|
| 3980 | AddArgumentMetadata(Dataset.GetSpatialReference, u'srType',
|
|---|
| 3981 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'WKT', u'ArcGIS', u'Proj4', u'Obj'], makeLowercase=True),
|
|---|
| 3982 | description=_(
|
|---|
| 3983 | u"""Type of spatial reference that should be returned:
|
|---|
| 3984 |
|
|---|
| 3985 | * WKT - a WKT string in standard OGC format.
|
|---|
| 3986 |
|
|---|
| 3987 | * ArcGIS - a WKT string in ESRI format, typically obtained from
|
|---|
| 3988 | a dataset produced by ArcGIS. (The ESRI format differs from the OGC
|
|---|
| 3989 | standard; various projections and parameters are named differently
|
|---|
| 3990 | and certain nodes are not recognized. See the OSR documentation for
|
|---|
| 3991 | more information.)
|
|---|
| 3992 |
|
|---|
| 3993 | * Proj4 - a string in the format recognized by the Proj4 library.
|
|---|
| 3994 |
|
|---|
| 3995 | * Obj - an instance of the OSR SpatialReference class.
|
|---|
| 3996 |
|
|---|
| 3997 | An OSR SpatialReference instance is stored internally. If 'Obj' is
|
|---|
| 3998 | requested, a reference to this instance is returned, not a copy of it,
|
|---|
| 3999 | allowing you to make change to the internal instance. This behavior is
|
|---|
| 4000 | by design. Take care not to make changes unintentionally. Use the
|
|---|
| 4001 | ConvertSpatialReference function to obtain a deep copy of the
|
|---|
| 4002 | instance, if needed.
|
|---|
| 4003 |
|
|---|
| 4004 | If something other than 'Obj' is requested, a string of the specified
|
|---|
| 4005 | type is exported from the internal SpatialRefenence instance and
|
|---|
| 4006 | returned."""))
|
|---|
| 4007 |
|
|---|
| 4008 | AddResultMetadata(Dataset.GetSpatialReference, u'sr',
|
|---|
| 4009 | typeMetadata=AnyObjectTypeMetadata(),
|
|---|
| 4010 | description=_(
|
|---|
| 4011 | u"""Spatial reference of the requested type, either a Unicode string,
|
|---|
| 4012 | an OGR SpatialReference instance, or None.
|
|---|
| 4013 |
|
|---|
| 4014 | If the dataset does not support a spatial reference (e.g. it is a
|
|---|
| 4015 | plain table), or it does support a spatial reference but it has never
|
|---|
| 4016 | been set, None will be returned, except if srType is 'ArcGIS', in
|
|---|
| 4017 | which case the string '{B286C06B-0879-11D2-AACA-00C04FA33C20}' will be
|
|---|
| 4018 | returned. ArcGIS uses this string to represent the "Unknown" spatial
|
|---|
| 4019 | reference."""))
|
|---|
| 4020 |
|
|---|
| 4021 | # Public method: Dataset.SetSpatialReference
|
|---|
| 4022 |
|
|---|
| 4023 | AddMethodMetadata(Dataset.SetSpatialReference,
|
|---|
| 4024 | shortDescription=_(u'Sets the spatial reference of this dataset.'),
|
|---|
| 4025 | longDescription=_(
|
|---|
| 4026 | u"""This function is similar in operation to the ArcGIS Define
|
|---|
| 4027 | Projection geoprocessing tool; it changes the spatial reference of the
|
|---|
| 4028 | dataset without changing any of the data itself. It does not
|
|---|
| 4029 | geographically project the existing data to the new spatial reference.
|
|---|
| 4030 | It is used mainly to fix datasets that do not have a spatial reference
|
|---|
| 4031 | or that are using the wrong one.
|
|---|
| 4032 |
|
|---|
| 4033 | Not all datasets support setting the spatial reference. To determine
|
|---|
| 4034 | if the spatial reference can be set, test the 'SetSpatialReference'
|
|---|
| 4035 | capability."""),
|
|---|
| 4036 | isExposedToPythonCallers=True)
|
|---|
| 4037 |
|
|---|
| 4038 | CopyArgumentMetadata(Dataset.GetSpatialReference, u'self', Dataset.SetSpatialReference, u'self')
|
|---|
| 4039 |
|
|---|
| 4040 | AddArgumentMetadata(Dataset.SetSpatialReference, u'srType',
|
|---|
| 4041 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'WKT', u'ArcGIS', u'Proj4', u'Obj'], makeLowercase=True),
|
|---|
| 4042 | description=_(
|
|---|
| 4043 | u"""Type of spatial reference you are providing for the sr parameter.
|
|---|
| 4044 |
|
|---|
| 4045 | The allowed values are:
|
|---|
| 4046 |
|
|---|
| 4047 | * WKT - sr is a WKT string in standard OGC format.
|
|---|
| 4048 |
|
|---|
| 4049 | * ArcGIS - sr is a WKT string in ESRI format, typically obtained from
|
|---|
| 4050 | a dataset produced by ArcGIS. (The ESRI format differs from the OGC
|
|---|
| 4051 | standard; various projections and parameters are named differently
|
|---|
| 4052 | and certain nodes are not recognized. See the OSR documentation for
|
|---|
| 4053 | more information.)
|
|---|
| 4054 |
|
|---|
| 4055 | * Proj4 - sr is a string suitable for passing to the Proj4 utility.
|
|---|
| 4056 |
|
|---|
| 4057 | * Obj - sr is an instance of the OSR SpatialReference class.
|
|---|
| 4058 | """))
|
|---|
| 4059 |
|
|---|
| 4060 | AddArgumentMetadata(Dataset.SetSpatialReference, u'sr',
|
|---|
| 4061 | typeMetadata=AnyObjectTypeMetadata(),
|
|---|
| 4062 | description=_(
|
|---|
| 4063 | u"""Spatial reference for the dataset."""))
|
|---|
| 4064 |
|
|---|
| 4065 | ###############################################################################
|
|---|
| 4066 | # Metadata: DatasetCollection class
|
|---|
| 4067 | ###############################################################################
|
|---|
| 4068 |
|
|---|
| 4069 | AddClassMetadata(DatasetCollection,
|
|---|
| 4070 | shortDescription=_(u'TODO: Add description.'))
|
|---|
| 4071 |
|
|---|
| 4072 | # Public properties
|
|---|
| 4073 |
|
|---|
| 4074 | AddPropertyMetadata(DatasetCollection.CacheDirectory,
|
|---|
| 4075 | typeMetadata=DirectoryTypeMetadata(canBeNone=True),
|
|---|
| 4076 | shortDescription=_(u'Directory for caching local copies of remote datasets.')) # TODO: add longDescription
|
|---|
| 4077 |
|
|---|
| 4078 | # Public method: DatasetCollection.QueryDatasets
|
|---|
| 4079 |
|
|---|
| 4080 | AddMethodMetadata(DatasetCollection.QueryDatasets,
|
|---|
| 4081 | shortDescription=_(u'Queries the collection for Datasets that match a search expression.'),
|
|---|
| 4082 | isExposedToPythonCallers=True,
|
|---|
| 4083 | dependencies=[PythonAggregatedModuleDependency('pyparsing')])
|
|---|
| 4084 |
|
|---|
| 4085 | AddArgumentMetadata(DatasetCollection.QueryDatasets, u'self',
|
|---|
| 4086 | typeMetadata=ClassInstanceTypeMetadata(cls=DatasetCollection),
|
|---|
| 4087 | description=_(u'%s instance.') % DatasetCollection.__name__)
|
|---|
| 4088 |
|
|---|
| 4089 | AddArgumentMetadata(DatasetCollection.QueryDatasets, u'expression',
|
|---|
| 4090 | typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
|
|---|
| 4091 | description=_(
|
|---|
| 4092 | u"""TODO: Write description"""))
|
|---|
| 4093 |
|
|---|
| 4094 | AddArgumentMetadata(DatasetCollection.QueryDatasets, u'reportProgress',
|
|---|
| 4095 | typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4096 | description=_(
|
|---|
| 4097 | u"""TODO: Write description"""))
|
|---|
| 4098 |
|
|---|
| 4099 | AddArgumentMetadata(DatasetCollection.QueryDatasets, u'options',
|
|---|
| 4100 | typeMetadata=DictionaryTypeMetadata(keyType=ClassInstanceTypeMetadata(cls=basestring), valueType=AnyObjectTypeMetadata(canBeNone=True)),
|
|---|
| 4101 | description=_(
|
|---|
| 4102 | u"""TODO: Write description"""))
|
|---|
| 4103 |
|
|---|
| 4104 | AddResultMetadata(DatasetCollection.QueryDatasets, u'datasets',
|
|---|
| 4105 | typeMetadata=ListTypeMetadata(elementType=ClassInstanceTypeMetadata(cls=Dataset)),
|
|---|
| 4106 | description=_(
|
|---|
| 4107 | u"""TODO: Write description"""))
|
|---|
| 4108 |
|
|---|
| 4109 | # Public method: DatasetCollection.GetOldestDataset
|
|---|
| 4110 |
|
|---|
| 4111 | AddMethodMetadata(DatasetCollection.GetOldestDataset,
|
|---|
| 4112 | shortDescription=_(u'Queries the collection and returns the oldest Dataset that matches the search expression.'),
|
|---|
| 4113 | isExposedToPythonCallers=True,
|
|---|
| 4114 | dependencies=[PythonAggregatedModuleDependency('pyparsing')])
|
|---|
| 4115 |
|
|---|
| 4116 | CopyArgumentMetadata(DatasetCollection.QueryDatasets, u'self', DatasetCollection.GetOldestDataset, u'self')
|
|---|
| 4117 | CopyArgumentMetadata(DatasetCollection.QueryDatasets, u'expression', DatasetCollection.GetOldestDataset, u'expression')
|
|---|
| 4118 | CopyArgumentMetadata(DatasetCollection.QueryDatasets, u'options', DatasetCollection.GetOldestDataset, u'options')
|
|---|
| 4119 |
|
|---|
| 4120 | AddResultMetadata(DatasetCollection.GetOldestDataset, u'dataset',
|
|---|
| 4121 | typeMetadata=ClassInstanceTypeMetadata(cls=Dataset),
|
|---|
| 4122 | description=_(
|
|---|
| 4123 | u"""TODO: Write description"""))
|
|---|
| 4124 |
|
|---|
| 4125 | # Public method: DatasetCollection.GetNewestDataset
|
|---|
| 4126 |
|
|---|
| 4127 | AddMethodMetadata(DatasetCollection.GetNewestDataset,
|
|---|
| 4128 | shortDescription=_(u'Queries the collection and returns the newest Dataset that matches the search expression.'),
|
|---|
| 4129 | isExposedToPythonCallers=True,
|
|---|
| 4130 | dependencies=[PythonAggregatedModuleDependency('pyparsing')])
|
|---|
| 4131 |
|
|---|
| 4132 | CopyArgumentMetadata(DatasetCollection.QueryDatasets, u'self', DatasetCollection.GetNewestDataset, u'self')
|
|---|
| 4133 | CopyArgumentMetadata(DatasetCollection.QueryDatasets, u'expression', DatasetCollection.GetNewestDataset, u'expression')
|
|---|
| 4134 | CopyArgumentMetadata(DatasetCollection.QueryDatasets, u'options', DatasetCollection.GetNewestDataset, u'options')
|
|---|
| 4135 |
|
|---|
| 4136 | AddResultMetadata(DatasetCollection.GetNewestDataset, u'dataset',
|
|---|
| 4137 | typeMetadata=ClassInstanceTypeMetadata(cls=Dataset),
|
|---|
| 4138 | description=_(
|
|---|
| 4139 | u"""TODO: Write description"""))
|
|---|
| 4140 |
|
|---|
| 4141 | # Private constructor: DatasetCollection.__init__
|
|---|
| 4142 |
|
|---|
| 4143 | AddMethodMetadata(DatasetCollection.__init__,
|
|---|
| 4144 | shortDescription=_(u'DatasetCollection constructor. Not intended to be called directly. Only intended to be called from derived class constructors.'))
|
|---|
| 4145 |
|
|---|
| 4146 | CopyArgumentMetadata(DatasetCollection.QueryDatasets, u'self', DatasetCollection.__init__, u'self')
|
|---|
| 4147 |
|
|---|
| 4148 | AddArgumentMetadata(DatasetCollection.__init__, u'parentCollection',
|
|---|
| 4149 | typeMetadata=DatasetCollection.ParentCollection.__doc__.Obj.Type,
|
|---|
| 4150 | description=DatasetCollection.ParentCollection.__doc__.Obj.ShortDescription)
|
|---|
| 4151 |
|
|---|
| 4152 | AddArgumentMetadata(DatasetCollection.__init__, u'queryableAttributes',
|
|---|
| 4153 | typeMetadata=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'queryableAttributes').Type,
|
|---|
| 4154 | description=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'queryableAttributes').Description)
|
|---|
| 4155 |
|
|---|
| 4156 | AddArgumentMetadata(DatasetCollection.__init__, u'queryableAttributeValues',
|
|---|
| 4157 | typeMetadata=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'queryableAttributeValues').Type,
|
|---|
| 4158 | description=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'queryableAttributeValues').Description)
|
|---|
| 4159 |
|
|---|
| 4160 | AddArgumentMetadata(DatasetCollection.__init__, u'lazyPropertyValues',
|
|---|
| 4161 | typeMetadata=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'lazyPropertyValues').Type,
|
|---|
| 4162 | description=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'lazyPropertyValues').Description)
|
|---|
| 4163 |
|
|---|
| 4164 | AddArgumentMetadata(DatasetCollection.__init__, u'cacheDirectory',
|
|---|
| 4165 | typeMetadata=DatasetCollection.CacheDirectory.__doc__.Obj.Type,
|
|---|
| 4166 | description=DatasetCollection.CacheDirectory.__doc__.Obj.ShortDescription)
|
|---|
| 4167 |
|
|---|
| 4168 | AddResultMetadata(DatasetCollection.__init__, u'obj',
|
|---|
| 4169 | typeMetadata=ClassInstanceTypeMetadata(cls=DatasetCollection),
|
|---|
| 4170 | description=_(u'%s instance.') % DatasetCollection.__name__)
|
|---|
| 4171 |
|
|---|
| 4172 | ###############################################################################
|
|---|
| 4173 | # Metadata: Table class
|
|---|
| 4174 | ###############################################################################
|
|---|
| 4175 |
|
|---|
| 4176 | AddClassMetadata(Table,
|
|---|
| 4177 | shortDescription=_(u'Represents a tabular dataset, such as a database table, shapefile, or geodatabase feature class.'))
|
|---|
| 4178 |
|
|---|
| 4179 | # Public properties
|
|---|
| 4180 |
|
|---|
| 4181 | AddPropertyMetadata(Table.HasOID,
|
|---|
| 4182 | typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4183 | shortDescription=_(u'True if rows of this dataset have object IDs (OIDs).'),
|
|---|
| 4184 | longDescription=_(
|
|---|
| 4185 | u"""An object ID is a 32-bit integer that uniquely identifies the row.
|
|---|
| 4186 | Many data formats have object IDs, including shapefiles (which have
|
|---|
| 4187 | feature IDs, or FIDs) and ArcGIS geodatabase tables and feature
|
|---|
| 4188 | classes (which have a field called OBJECTID). Object IDs are assigned
|
|---|
| 4189 | and managed by a GIS system or the data format itself.
|
|---|
| 4190 |
|
|---|
| 4191 | If this dataset does have an object ID, the HasOID property will be
|
|---|
| 4192 | True and you can retrieve the object ID through the GetOID method of
|
|---|
| 4193 | the SelectCursor and UpdateCursor classes. Because object IDs are
|
|---|
| 4194 | assigned and managed by the underlying data format or GIS system, it
|
|---|
| 4195 | is not possible to set object IDs."""))
|
|---|
| 4196 |
|
|---|
| 4197 | AddPropertyMetadata(Table.OIDFieldName,
|
|---|
| 4198 | typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
|
|---|
| 4199 | shortDescription=_(u'Name of the field of the dataset that contains the object ID, or None of no such field exists.'),
|
|---|
| 4200 | longDescription=_(
|
|---|
| 4201 | u"""Some data formats store the object ID in a field, and you can
|
|---|
| 4202 | retrieve the object ID by getting the value of that field. That method
|
|---|
| 4203 | of retrieving the object ID is generally not recommended, because some
|
|---|
| 4204 | data formats that have object IDs do not store them in a field.
|
|---|
| 4205 | Instead, you should use the GetOID method of the SelectCursor or
|
|---|
| 4206 | UpdateCursor classes, which works whether or not the object ID is
|
|---|
| 4207 | accessible through a field."""))
|
|---|
| 4208 |
|
|---|
| 4209 | AddPropertyMetadata(Table.GeometryType,
|
|---|
| 4210 | typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
|
|---|
| 4211 | shortDescription=_(u'Geometry type of the dataset, or None if the dataset does not have geometry (i.e. it is a plain table).'),
|
|---|
| 4212 | longDescription=_(
|
|---|
| 4213 | u"""The supported geometry types are a subset of those provided by the
|
|---|
| 4214 | OGR library, namely:
|
|---|
| 4215 |
|
|---|
| 4216 | * Point
|
|---|
| 4217 | * LineString
|
|---|
| 4218 | * Polygon
|
|---|
| 4219 | * MultiPoint
|
|---|
| 4220 | * MultiLineString
|
|---|
| 4221 | * MultiPolygon
|
|---|
| 4222 | * GeometryCollection
|
|---|
| 4223 | * Point25D
|
|---|
| 4224 | * LineString25D
|
|---|
| 4225 | * Polygon25D
|
|---|
| 4226 | * MultiPoint25D
|
|---|
| 4227 | * MultiLineString25D
|
|---|
| 4228 | * MultiPolygon25D
|
|---|
| 4229 | * GeometryCollection25D
|
|---|
| 4230 |
|
|---|
| 4231 | The 25D types have "two and a half dimensional" geometry, as defined
|
|---|
| 4232 | by OGR. In ArcGIS terminology, these geometry types those that have Z
|
|---|
| 4233 | coordinates.
|
|---|
| 4234 |
|
|---|
| 4235 | Not all derived classes support all of these geometry types. For
|
|---|
| 4236 | example, ArcGISTabularLayers do not support the GeometryCollection or
|
|---|
| 4237 | GeometryCollection25D geometry type. To test whether a derived class
|
|---|
| 4238 | supports a geometry type, pass the string 'GeometryType t' to the
|
|---|
| 4239 | TestCapability method, replacing t with the geometry type you want to
|
|---|
| 4240 | test.
|
|---|
| 4241 |
|
|---|
| 4242 | It is not possible to test the geometry type on a per-dataset basis;
|
|---|
| 4243 | calling TestCapability on a class instance will yield the same result
|
|---|
| 4244 | as calling it on the class."""))
|
|---|
| 4245 |
|
|---|
| 4246 | AddPropertyMetadata(Table.GeometryFieldName,
|
|---|
| 4247 | typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
|
|---|
| 4248 | shortDescription=_(u'Name of the field of the dataset that contains the geometry, or None of no such field exists.'),
|
|---|
| 4249 | longDescription=_(
|
|---|
| 4250 | u"""Some data formats store the geometry in a field, and you can
|
|---|
| 4251 | retrieve it by getting the value of that field. That method of
|
|---|
| 4252 | retrieving the geometry is generally not recommended, because some
|
|---|
| 4253 | data formats that have geometry do not store it in a field. Instead,
|
|---|
| 4254 | you should use the GetGeometry method of the SelectCursor or
|
|---|
| 4255 | UpdateCursor classes, which works whether or not the geometry is
|
|---|
| 4256 | accessible through a field."""))
|
|---|
| 4257 |
|
|---|
| 4258 | AddPropertyMetadata(Table.MaxStringLength,
|
|---|
| 4259 | typeMetadata=IntegerTypeMetadata(minValue=1, canBeNone=True),
|
|---|
| 4260 | shortDescription=_(u'Maximum length of string fields that can be created with the AddField method, or None if there is no known maximum length.'),
|
|---|
| 4261 | longDescription=_(
|
|---|
| 4262 | u"""Some data formats limit the length of string fields. For example,
|
|---|
| 4263 | shapefiles limit string fields to 254 characters. If the limit is
|
|---|
| 4264 | known, it can be obtained here.
|
|---|
| 4265 |
|
|---|
| 4266 | Note that if None is returned, it may indicate either that there is no
|
|---|
| 4267 | limit, or that one exists but it is not known. If None is returned,
|
|---|
| 4268 | the underlying API used to add the field may still fail if you request
|
|---|
| 4269 | a length that is too large."""))
|
|---|
| 4270 |
|
|---|
| 4271 | AddPropertyMetadata(Table.Fields,
|
|---|
| 4272 | typeMetadata=TupleTypeMetadata(elementType=ClassInstanceTypeMetadata(cls=Field)),
|
|---|
| 4273 | shortDescription=_(u'Tuple of Field instances representing the fields of the dataset.'),
|
|---|
| 4274 | longDescription=_(
|
|---|
| 4275 | u"""For efficiency, this property directly references the internal
|
|---|
| 4276 | tuple of Field instances maintained by the Table instance. Take care
|
|---|
| 4277 | to not modify the instances contained within it."""))
|
|---|
| 4278 |
|
|---|
| 4279 | ### Public method: Table.GetFieldByName
|
|---|
| 4280 | ##
|
|---|
| 4281 | ##AddMethodMetadata(Table.GetFieldByName,
|
|---|
| 4282 | ## shortDescription=_(u'Given the name of a field of the dataset, returns the Field instance representing the field.'),
|
|---|
| 4283 | ## longDescription=_(
|
|---|
| 4284 | ##u"""This method is mainly intended to be a convenient alternative
|
|---|
| 4285 | ##toperforming a linear probe on the Fields property."""),
|
|---|
| 4286 | ## isExposedToPythonCallers=True)
|
|---|
| 4287 | ##
|
|---|
| 4288 | ##AddArgumentMetadata(Table.GetFieldByName, u'self',
|
|---|
| 4289 | ## typeMetadata=ClassInstanceTypeMetadata(cls=Table),
|
|---|
| 4290 | ## description=_(u'%s instance.') % Table.__name__)
|
|---|
| 4291 | ##
|
|---|
| 4292 | ##AddArgumentMetadata(Table.GetFieldByName, u'name',
|
|---|
| 4293 | ## typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 4294 | ## description=_(
|
|---|
| 4295 | ##u"""Name of the field to be returned. This name is case-insensitive,
|
|---|
| 4296 | ##even if the underlying data store is case sensitive."""))
|
|---|
| 4297 | ##
|
|---|
| 4298 | ##AddResultMetadata(Table.GetFieldByName, u'field',
|
|---|
| 4299 | ## typeMetadata=ClassInstanceTypeMetadata(cls=Field, canBeNone=True),
|
|---|
| 4300 | ## description=_(
|
|---|
| 4301 | ##u"""Field instance representing the field, or None if the dataset does
|
|---|
| 4302 | ##not contain a field with the specified name."""))
|
|---|
| 4303 | ##
|
|---|
| 4304 | ### Public method: Table.AddField
|
|---|
| 4305 | ##
|
|---|
| 4306 | ##AddMethodMetadata(Table.AddField,
|
|---|
| 4307 | ## shortDescription=_(u'Adds a field to the dataset.'),
|
|---|
| 4308 | ## longDescription=_(
|
|---|
| 4309 | ##u"""If the field cannot be added, an appropriate error will be raised.
|
|---|
| 4310 | ##This can happen for a variety of reasons including but not limited to:
|
|---|
| 4311 | ##
|
|---|
| 4312 | ##* The underlying data format or programming library used to access
|
|---|
| 4313 | ## it does not support the addition of fields.
|
|---|
| 4314 | ##
|
|---|
| 4315 | ##* The table is not empty, and the format or library only allow fields
|
|---|
| 4316 | ## to be added when it is empty.
|
|---|
| 4317 | ##
|
|---|
| 4318 | ##* The format or library does not support the requested parameters. For
|
|---|
| 4319 | ## example, it may not support the requested data type.
|
|---|
| 4320 | ##
|
|---|
| 4321 | ##* The dataset is read-only, or the caller does not have sufficient
|
|---|
| 4322 | ## privileges to add fields.
|
|---|
| 4323 | ##"""),
|
|---|
| 4324 | ## isExposedToPythonCallers=True)
|
|---|
| 4325 | ##
|
|---|
| 4326 | ##CopyArgumentMetadata(Table.GetFieldByName, u'self', Table.AddField, u'self')
|
|---|
| 4327 | ##
|
|---|
| 4328 | ##AddArgumentMetadata(Table.AddField, u'name',
|
|---|
| 4329 | ## typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 4330 | ## description=_(
|
|---|
| 4331 | ##u"""Name of the field to add.
|
|---|
| 4332 | ##
|
|---|
| 4333 | ##The name must conform to all rules imposed by the underlying data
|
|---|
| 4334 | ##format and programming library used to access it. The caller is
|
|---|
| 4335 | ##expected to be aware of these rules and this function attempts to fail
|
|---|
| 4336 | ##if any rule is violated. Certain libraries are designed to
|
|---|
| 4337 | ##automatically modify the caller's illegal name to a legal name. Where
|
|---|
| 4338 | ##possible, this function overrides that behavior and tries to fail
|
|---|
| 4339 | ##anyway.
|
|---|
| 4340 | ##
|
|---|
| 4341 | ##This function treats names as case-insensitive, even if the underlying
|
|---|
| 4342 | ##format and library support case-sensitive names. This behavior should
|
|---|
| 4343 | ##be of little consequence to most callers; this function will pass the
|
|---|
| 4344 | ##name to the library without changing the case. The only callers that
|
|---|
| 4345 | ##will be affected are those who require the ability to create multiple
|
|---|
| 4346 | ##fields with the same name but different case. That scenario is not
|
|---|
| 4347 | ##supported, regardless of whether the format and library may support
|
|---|
| 4348 | ##it."""))
|
|---|
| 4349 | ##
|
|---|
| 4350 | ##AddArgumentMetadata(Table.AddField, u'dataType',
|
|---|
| 4351 | ## typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'binary', u'date', u'datetime', u'float32', u'float64', u'int16', u'int32', u'string'], makeLowercase=True),
|
|---|
| 4352 | ## description=_(
|
|---|
| 4353 | ##u"""Data type of the field to add.
|
|---|
| 4354 | ##
|
|---|
| 4355 | ##The underlying data format and programming library may only support a
|
|---|
| 4356 | ##subset of the possible data types. To test whether a data type is
|
|---|
| 4357 | ##supported, pass the string 't DataType' to the TestCapability
|
|---|
| 4358 | ##method, replacing t with the data type you want to test.
|
|---|
| 4359 | ##
|
|---|
| 4360 | ##If the allowSafeCoercions parameter is True (the default) and the
|
|---|
| 4361 | ##format or library do not support the requested data type but they do
|
|---|
| 4362 | ##support an alternative data type that can fully represent the values
|
|---|
| 4363 | ##of the requested data type, the field will be created with that
|
|---|
| 4364 | ##alternative data type. See the allowSafeCoercions parameter for more
|
|---|
| 4365 | ##information."""))
|
|---|
| 4366 | ##
|
|---|
| 4367 | ##AddArgumentMetadata(Table.AddField, u'length',
|
|---|
| 4368 | ## typeMetadata=IntegerTypeMetadata(canBeNone=True),
|
|---|
| 4369 | ## description=_(
|
|---|
| 4370 | ##u"""Length of the field to add.
|
|---|
| 4371 | ##
|
|---|
| 4372 | ##The caller is expected to be aware of the appropriate values for this
|
|---|
| 4373 | ##parameter, based on the underlying data format and programming library
|
|---|
| 4374 | ##used to access it. If this parameter is provided, it will be passed
|
|---|
| 4375 | ##without any validation to the library. Typically, this parameter
|
|---|
| 4376 | ##should only be provided when creating fields that have the 'string' or
|
|---|
| 4377 | ##'binary' data type.
|
|---|
| 4378 | ##
|
|---|
| 4379 | ##Most formats and libraries impose upper limits on the length of string
|
|---|
| 4380 | ##fields. For some of these, the MaxStringLength property will return
|
|---|
| 4381 | ##the upper limit."""))
|
|---|
| 4382 | ##
|
|---|
| 4383 | ##AddArgumentMetadata(Table.AddField, u'precision',
|
|---|
| 4384 | ## typeMetadata=IntegerTypeMetadata(canBeNone=True),
|
|---|
| 4385 | ## description=_(
|
|---|
| 4386 | ##u"""Precision of the field to add.
|
|---|
| 4387 | ##
|
|---|
| 4388 | ##The caller is expected to be aware of the appropriate values for this
|
|---|
| 4389 | ##parameter, based on the underlying data format and programming library
|
|---|
| 4390 | ##used to access it. If this parameter is provided, it will be passed
|
|---|
| 4391 | ##without any validation to the library. Typically, this parameter
|
|---|
| 4392 | ##should only be provided when creating fields that have the 'float32'
|
|---|
| 4393 | ##or 'float64' data type."""))
|
|---|
| 4394 | ##
|
|---|
| 4395 | ##AddArgumentMetadata(Table.AddField, u'isNullable',
|
|---|
| 4396 | ## typeMetadata=BooleanTypeMetadata(canBeNone=True),
|
|---|
| 4397 | ## description=_(
|
|---|
| 4398 | ##u"""Indicates whether or not the added field should be nullable.
|
|---|
| 4399 | ##
|
|---|
| 4400 | ##The default value of this parameter, None, indicates that the
|
|---|
| 4401 | ##nullability should be decided by the default behavior of the
|
|---|
| 4402 | ##underlying data format and programming library used to access it. The
|
|---|
| 4403 | ##value True indicates that the library should be instructed to create a
|
|---|
| 4404 | ##nullable field; False indicates that it should be instructed to create
|
|---|
| 4405 | ##a non-nullable field.
|
|---|
| 4406 | ##
|
|---|
| 4407 | ##If True or False is provided and the underlying format or library does
|
|---|
| 4408 | ##not support nullable fields, this function attempts recognize the
|
|---|
| 4409 | ##condition and raise an error. Some libraries will allow nullable
|
|---|
| 4410 | ##fields to be created even though the underlying format does not truly
|
|---|
| 4411 | ##support them. For example, at the time of this writing, OGR did not
|
|---|
| 4412 | ##recognize the concept of nullability and essentially treated all
|
|---|
| 4413 | ##fields as nullable. In situations like this, we try not to rely on the
|
|---|
| 4414 | ##underlying library to decide whether nullability is supported but
|
|---|
| 4415 | ##detect it independently."""))
|
|---|
| 4416 | ##
|
|---|
| 4417 | ##AddArgumentMetadata(Table.AddField, u'allowSafeCoercions',
|
|---|
| 4418 | ## typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4419 | ## description=_(
|
|---|
| 4420 | ##u"""If True and the underlying data format or programming library do
|
|---|
| 4421 | ##not support the requested data type but they do support an alternative
|
|---|
| 4422 | ##data type that can fully represent the values of the requested data
|
|---|
| 4423 | ##type, the field will be added with the alternative data type. If False
|
|---|
| 4424 | ##and the requested data type is not supported, an error will be raised.
|
|---|
| 4425 | ##
|
|---|
| 4426 | ##If True is provided, this function will try the following alternative
|
|---|
| 4427 | ##data types in the order listed and use the first one that is
|
|---|
| 4428 | ##supported:
|
|---|
| 4429 | ##
|
|---|
| 4430 | ##=================== =======================
|
|---|
| 4431 | ##Requested Data Type Alternate Data Types
|
|---|
| 4432 | ##=================== =======================
|
|---|
| 4433 | ##date datetime
|
|---|
| 4434 | ##int16 int32, float32, float64
|
|---|
| 4435 | ##int32 float64
|
|---|
| 4436 | ##float32 float64
|
|---|
| 4437 | ##=================== =======================
|
|---|
| 4438 | ##"""))
|
|---|
| 4439 | ##
|
|---|
| 4440 | ##AddArgumentMetadata(Table.AddField, u'failIfExists',
|
|---|
| 4441 | ## typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4442 | ## description=_(
|
|---|
| 4443 | ##u"""If True and a field already exists with the name requested by the
|
|---|
| 4444 | ##caller, an error will raised. If False and a field already exists with
|
|---|
| 4445 | ##the name requested by the caller, an error will not be raised as long
|
|---|
| 4446 | ##as that the field has the exact characteristics requested by the
|
|---|
| 4447 | ##caller (data type, length, and so on).
|
|---|
| 4448 | ##
|
|---|
| 4449 | ##As noted above, this function treats field names as case-insensitive,
|
|---|
| 4450 | ##even if the underlying data format or programming library treat them
|
|---|
| 4451 | ##as case-sensitive."""))
|
|---|
| 4452 | ##
|
|---|
| 4453 | ### Public method: Table.DeleteField
|
|---|
| 4454 | ##
|
|---|
| 4455 | ##AddMethodMetadata(Table.DeleteField,
|
|---|
| 4456 | ## shortDescription=_(u'Deletes a field from the dataset.'),
|
|---|
| 4457 | ## longDescription=_(
|
|---|
| 4458 | ##u"""If the field cannot be deleted, an appropriate error will be
|
|---|
| 4459 | ##raised. This can happen for a variety of reasons including but not
|
|---|
| 4460 | ##limited to:
|
|---|
| 4461 | ##
|
|---|
| 4462 | ##* The underlying data format or programming library used to access
|
|---|
| 4463 | ## it does not support the deletion of fields.
|
|---|
| 4464 | ##
|
|---|
| 4465 | ##* The table is not empty, and the format or library only allow fields
|
|---|
| 4466 | ## to be deleted when it is empty.
|
|---|
| 4467 | ##
|
|---|
| 4468 | ##* The dataset is read-only, or the caller does not have sufficient
|
|---|
| 4469 | ## privileges to delete fields.
|
|---|
| 4470 | ##"""),
|
|---|
| 4471 | ## isExposedToPythonCallers=True)
|
|---|
| 4472 | ##
|
|---|
| 4473 | ##CopyArgumentMetadata(Table.GetFieldByName, u'self', Table.DeleteField, u'self')
|
|---|
| 4474 | ##
|
|---|
| 4475 | ##AddArgumentMetadata(Table.DeleteField, u'name',
|
|---|
| 4476 | ## typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 4477 | ## description=_(
|
|---|
| 4478 | ##u"""Name of the field to delete.
|
|---|
| 4479 | ##
|
|---|
| 4480 | ##The name must conform to all rules imposed by the underlying data
|
|---|
| 4481 | ##format and programming library used to access it. The caller is
|
|---|
| 4482 | ##expected to be aware of these rules and this function attempts to fail
|
|---|
| 4483 | ##if any rule is violated. Certain libraries are designed to
|
|---|
| 4484 | ##automatically modify the caller's illegal name to a legal name. Where
|
|---|
| 4485 | ##possible, this function overrides that behavior and tries to fail
|
|---|
| 4486 | ##anyway.
|
|---|
| 4487 | ##
|
|---|
| 4488 | ##This function treats names as case-insensitive, even if the underlying
|
|---|
| 4489 | ##format and library support case-sensitive names. This behavior should
|
|---|
| 4490 | ##be of little consequence to most callers. The only callers that will
|
|---|
| 4491 | ##be affected are those who require the ability to have multiple fields
|
|---|
| 4492 | ##with the same name but different case. That scenario is not supported,
|
|---|
| 4493 | ##regardless of whether the format and library may support it, and the
|
|---|
| 4494 | ##behavior of this function in that scenario is undefined."""))
|
|---|
| 4495 | ##
|
|---|
| 4496 | ##AddArgumentMetadata(Table.DeleteField, u'failIfDoesNotExist',
|
|---|
| 4497 | ## typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4498 | ## description=_(
|
|---|
| 4499 | ##u"""If True and a field does not exist with the name requested by the
|
|---|
| 4500 | ##caller, an error will raised. If False and a field does not exist with
|
|---|
| 4501 | ##the name requested by the caller, an error will not be raised.
|
|---|
| 4502 | ##
|
|---|
| 4503 | ##As noted above, this function treats field names as case-insensitive,
|
|---|
| 4504 | ##even if the underlying data format or programming library treat them
|
|---|
| 4505 | ##as case-sensitive."""))
|
|---|
| 4506 | ##
|
|---|
| 4507 | ### Public method: Table.GetRowCount
|
|---|
| 4508 | ##
|
|---|
| 4509 | ##AddMethodMetadata(Table.GetRowCount,
|
|---|
| 4510 | ## shortDescription=_(u'Returns the number of rows in the dataset.'),
|
|---|
| 4511 | ## longDescription=_(
|
|---|
| 4512 | ##u"""For certain datasets, calling this function might require the
|
|---|
| 4513 | ##underlying programming library used to access the data to read the
|
|---|
| 4514 | ##entire table, a potentially lengthy operation. If this behavior is
|
|---|
| 4515 | ##undesirable, the caller is expected to know that it will occur and not
|
|---|
| 4516 | ##call this function."""),
|
|---|
| 4517 | ## isExposedToPythonCallers=True)
|
|---|
| 4518 | ##
|
|---|
| 4519 | ##CopyArgumentMetadata(Table.GetFieldByName, u'self', Table.GetRowCount, u'self')
|
|---|
| 4520 | ##
|
|---|
| 4521 | ##AddResultMetadata(Table.GetRowCount, u'count',
|
|---|
| 4522 | ## typeMetadata=IntegerTypeMetadata(minValue=0),
|
|---|
| 4523 | ## description=_(
|
|---|
| 4524 | ##u"""Number of rows in the dataset."""))
|
|---|
| 4525 | ##
|
|---|
| 4526 | ### Public method: Table.OpenSelectCursor
|
|---|
| 4527 | ##
|
|---|
| 4528 | ##AddMethodMetadata(Table.OpenSelectCursor,
|
|---|
| 4529 | ## shortDescription=_(u'Opens a forward-only cursor for reading rows from the dataset.'),
|
|---|
| 4530 | ## isExposedToPythonCallers=True)
|
|---|
| 4531 | ##
|
|---|
| 4532 | ##CopyArgumentMetadata(Table.GetFieldByName, u'self', Table.OpenSelectCursor, u'self')
|
|---|
| 4533 | ##
|
|---|
| 4534 | ##AddArgumentMetadata(Table.OpenSelectCursor, u'fields',
|
|---|
| 4535 | ## typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata(), canBeNone=True),
|
|---|
| 4536 | ## description=_(
|
|---|
| 4537 | ##u"""Fields to retrieve for each row (i.e., the columns specified in
|
|---|
| 4538 | ##the SELECT clause of a SQL SELECT statement). If no fields are
|
|---|
| 4539 | ##provided, all fields will be returned.
|
|---|
| 4540 | ##
|
|---|
| 4541 | ##Do not provide "\*", as would be done in a SQL SELECT statement that
|
|---|
| 4542 | ##wanted to retrieve all fields. To retrieve all fields, simply omit
|
|---|
| 4543 | ##this parameter when you call this method.
|
|---|
| 4544 | ##
|
|---|
| 4545 | ##This usual reason to suppy a list of fields is to minimize database
|
|---|
| 4546 | ##and network load. If you are not concerned about database peformance,
|
|---|
| 4547 | ##there is no reason to provide a value for this parameter.
|
|---|
| 4548 | ##
|
|---|
| 4549 | ##If you do provide a value for this parameter and the dataset has a
|
|---|
| 4550 | ##geometry field and you want to access the geometry through the
|
|---|
| 4551 | ##cursor's GetGeometry method, be sure you request the geometry field
|
|---|
| 4552 | ##with this parameter."""))
|
|---|
| 4553 | ##
|
|---|
| 4554 | ##AddArgumentMetadata(Table.OpenSelectCursor, u'where',
|
|---|
| 4555 | ## typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
|
|---|
| 4556 | ## description=_(
|
|---|
| 4557 | ##u"""SQL WHERE clause that specifies the subset of rows to retrieve. If
|
|---|
| 4558 | ##this parameter is not provided, all of the rows will be retrieved.
|
|---|
| 4559 | ##
|
|---|
| 4560 | ##The exact syntax and behavior of this parameter depends on the
|
|---|
| 4561 | ##underlying data format and programming library used to access it. For
|
|---|
| 4562 | ##more information, please see the documentation for the derived class
|
|---|
| 4563 | ##you intend to use to access the dataset.
|
|---|
| 4564 | ##
|
|---|
| 4565 | ##The underlying format and library perform the actual evaluation of
|
|---|
| 4566 | ##this parameter and determine all comparison rules, such as whether
|
|---|
| 4567 | ##string comparisons are case-sensitive or case-insensitive. At present,
|
|---|
| 4568 | ##there is no mechanism to interrogate or manipulate these rules; you
|
|---|
| 4569 | ##must live with the default behavior of the underlying format and
|
|---|
| 4570 | ##library."""))
|
|---|
| 4571 | ##
|
|---|
| 4572 | ##AddArgumentMetadata(Table.OpenSelectCursor, u'orderBy',
|
|---|
| 4573 | ## typeMetadata=UnicodeStringTypeMetadata(canBeNone=True, mustMatchRegEx=u'\s*\S+(\s+([aA][sS][cC]|[dD][eE][sS][cC]))?\s*(,\s*\S+(\s+([aA][sS][cC]|[dD][eE][sS][cC]))?\s*)*'),
|
|---|
| 4574 | ## description=_(
|
|---|
| 4575 | ##u"""SQL ORDER BY clause that specifies the order in which the rows
|
|---|
| 4576 | ##should be returned. If this parameter is not provided, the rows will
|
|---|
| 4577 | ##ordered according to the default behavior of the underlying data
|
|---|
| 4578 | ##format and the programming library used to access it.
|
|---|
| 4579 | ##
|
|---|
| 4580 | ##The ORDER BY clause must be a a comma-separated list of fields. Each
|
|---|
| 4581 | ##field can optionally be followed by a space and the word ASC to
|
|---|
| 4582 | ##indicate ascending order or DESC to indicate descending order. If
|
|---|
| 4583 | ##neither is specified, ASC is assumed.
|
|---|
| 4584 | ##
|
|---|
| 4585 | ##The underlying format and library perform the actual evaluation of
|
|---|
| 4586 | ##this parameter and determine the rules of sorting, such as whether
|
|---|
| 4587 | ##string comparisons are case-sensitive or case-insensitive. At present,
|
|---|
| 4588 | ##there is no mechanism to interrogate or manipulate these rules; you
|
|---|
| 4589 | ##must live with the default behavior of the underlying format and
|
|---|
| 4590 | ##library."""))
|
|---|
| 4591 | ##
|
|---|
| 4592 | ##AddArgumentMetadata(Table.OpenSelectCursor, u'rowCount',
|
|---|
| 4593 | ## typeMetadata=IntegerTypeMetadata(canBeNone=True, minValue=1),
|
|---|
| 4594 | ## description=_(
|
|---|
| 4595 | ##u"""Number of rows that this cursor will access, if known ahead of
|
|---|
| 4596 | ##time. If the number of rows is not known, omit this parameter.
|
|---|
| 4597 | ##
|
|---|
| 4598 | ##This parameter is only used in progress reporting and is ignored if
|
|---|
| 4599 | ##reportProgress is False. If this parameter is provided, the progress
|
|---|
| 4600 | ##reports will include the number of rows remaining and an estimated
|
|---|
| 4601 | ##time of completion. If a value is not provided, the progress reports
|
|---|
| 4602 | ##will only include the number of rows accessed so far.
|
|---|
| 4603 | ##
|
|---|
| 4604 | ##If you omit both this parameter and the WHERE clause parameter, and
|
|---|
| 4605 | ##the underlying data format and programming library support retrieval
|
|---|
| 4606 | ##of row counts, then the row count will be obtained automatically when
|
|---|
| 4607 | ##the cursor is opened."""))
|
|---|
| 4608 | ##
|
|---|
| 4609 | ##AddArgumentMetadata(Table.OpenSelectCursor, u'reportProgress',
|
|---|
| 4610 | ## typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4611 | ## description=_(
|
|---|
| 4612 | ##u"""If True, progress messages will be logged periodically. If False,
|
|---|
| 4613 | ##no messages will be logged.
|
|---|
| 4614 | ##
|
|---|
| 4615 | ##Progress messages are logged with the Python logging module, using the
|
|---|
| 4616 | ##"informational" logging level and the "GeoEco.Datasets" logger. The
|
|---|
| 4617 | ##first message will be logged after one minute has passed, and
|
|---|
| 4618 | ##subsequent messages will be logged every five minutes thereafter."""))
|
|---|
| 4619 | ##
|
|---|
| 4620 | ##AddArgumentMetadata(Table.OpenSelectCursor, u'rowDescriptionSingular',
|
|---|
| 4621 | ## typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
|
|---|
| 4622 | ## description=_(
|
|---|
| 4623 | ##u"""Localized word to use in progress and error messages for a single
|
|---|
| 4624 | ##row. If this parameter is omitted, an appropriate generic word will be
|
|---|
| 4625 | ##automatically selected based on the geometry type of the dataset, such
|
|---|
| 4626 | ##as "point", "line", "polygon", and so on. If the dataset does not have
|
|---|
| 4627 | ##geometry, "row" will be used."""))
|
|---|
| 4628 | ##
|
|---|
| 4629 | ##AddArgumentMetadata(Table.OpenSelectCursor, u'rowDescriptionPlural',
|
|---|
| 4630 | ## typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
|
|---|
| 4631 | ## description=_(
|
|---|
| 4632 | ##u"""Localized word to use in progress and error messages for plural
|
|---|
| 4633 | ##rows. If this parameter is omitted, an appropriate generic word will
|
|---|
| 4634 | ##be automatically selected based on the geometry type of the dataset,
|
|---|
| 4635 | ##such as "points", "lines", "polygons", and so on. If the dataset does not
|
|---|
| 4636 | ##have geometry, "rows" will be used."""))
|
|---|
| 4637 | ##
|
|---|
| 4638 | ##AddResultMetadata(Table.OpenSelectCursor, u'cursor',
|
|---|
| 4639 | ## typeMetadata=ClassInstanceTypeMetadata(cls=SelectCursor),
|
|---|
| 4640 | ## description=_(
|
|---|
| 4641 | ##u"""SelectCursor instance representing the open select cursor. The
|
|---|
| 4642 | ##cursor will be closed automatically when all references to the
|
|---|
| 4643 | ##instance are released. See the documentation for the SelectCursor
|
|---|
| 4644 | ##class for more information about how to use the SelectCursor
|
|---|
| 4645 | ##instance."""))
|
|---|
| 4646 | ##
|
|---|
| 4647 | ### Public method: Table.OpenUpdateCursor
|
|---|
| 4648 | ##
|
|---|
| 4649 | ##AddMethodMetadata(Table.OpenUpdateCursor,
|
|---|
| 4650 | ## shortDescription=_(u'Opens a forward-only cursor for updating and deleting rows of the dataset.'),
|
|---|
| 4651 | ## isExposedToPythonCallers=True)
|
|---|
| 4652 | ##
|
|---|
| 4653 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'self', Table.OpenUpdateCursor, u'self')
|
|---|
| 4654 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'fields', Table.OpenUpdateCursor, u'fields')
|
|---|
| 4655 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'where', Table.OpenUpdateCursor, u'where')
|
|---|
| 4656 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'orderBy', Table.OpenUpdateCursor, u'orderBy')
|
|---|
| 4657 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'rowCount', Table.OpenUpdateCursor, u'rowCount')
|
|---|
| 4658 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'reportProgress', Table.OpenUpdateCursor, u'reportProgress')
|
|---|
| 4659 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'rowDescriptionSingular', Table.OpenUpdateCursor, u'rowDescriptionSingular')
|
|---|
| 4660 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'rowDescriptionPlural', Table.OpenUpdateCursor, u'rowDescriptionPlural')
|
|---|
| 4661 | ##
|
|---|
| 4662 | ##AddResultMetadata(Table.OpenUpdateCursor, u'cursor',
|
|---|
| 4663 | ## typeMetadata=ClassInstanceTypeMetadata(cls=UpdateCursor),
|
|---|
| 4664 | ## description=_(
|
|---|
| 4665 | ##u"""UpdateCursor instance representing the open update cursor. The
|
|---|
| 4666 | ##cursor will be closed automatically when all references to the
|
|---|
| 4667 | ##instance are released. See the documentation for the UpdateCursor
|
|---|
| 4668 | ##class for more information about how to use the UpdateCursor
|
|---|
| 4669 | ##instance."""))
|
|---|
| 4670 | ##
|
|---|
| 4671 | ### Public method: Table.OpenInsertCursor
|
|---|
| 4672 | ##
|
|---|
| 4673 | ##AddMethodMetadata(Table.OpenInsertCursor,
|
|---|
| 4674 | ## shortDescription=_(u'Opens a forward-only cursor for updating and deleting rows of the dataset.'),
|
|---|
| 4675 | ## isExposedToPythonCallers=True)
|
|---|
| 4676 | ##
|
|---|
| 4677 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'self', Table.OpenInsertCursor, u'self')
|
|---|
| 4678 | ##
|
|---|
| 4679 | ##AddArgumentMetadata(Table.OpenInsertCursor, u'rowCount',
|
|---|
| 4680 | ## typeMetadata=IntegerTypeMetadata(canBeNone=True, minValue=1),
|
|---|
| 4681 | ## description=_(
|
|---|
| 4682 | ##u"""Number of rows that this cursor will insert, if known ahead of
|
|---|
| 4683 | ##time. If the number of rows is not known, omit this parameter.
|
|---|
| 4684 | ##
|
|---|
| 4685 | ##This parameter is only used in progress reporting and is ignored if
|
|---|
| 4686 | ##reportProgress is False. If this parameter is provided, the progress
|
|---|
| 4687 | ##reports will include the number of rows remaining and an estimated
|
|---|
| 4688 | ##time of completion. If a value is not provided, the progress reports
|
|---|
| 4689 | ##will only include the number of rows inserted so far."""))
|
|---|
| 4690 | ##
|
|---|
| 4691 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'reportProgress', Table.OpenInsertCursor, u'reportProgress')
|
|---|
| 4692 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'rowDescriptionSingular', Table.OpenInsertCursor, u'rowDescriptionSingular')
|
|---|
| 4693 | ##CopyArgumentMetadata(Table.OpenSelectCursor, u'rowDescriptionPlural', Table.OpenInsertCursor, u'rowDescriptionPlural')
|
|---|
| 4694 | ##
|
|---|
| 4695 | ##AddResultMetadata(Table.OpenInsertCursor, u'cursor',
|
|---|
| 4696 | ## typeMetadata=ClassInstanceTypeMetadata(cls=InsertCursor),
|
|---|
| 4697 | ## description=_(
|
|---|
| 4698 | ##u"""OpenInsertCursor instance representing the open insert cursor. The
|
|---|
| 4699 | ##cursor will be closed automatically when all references to the
|
|---|
| 4700 | ##instance are released. See the documentation for the InsertCursor
|
|---|
| 4701 | ##class for more information about how to use the InsertCursor
|
|---|
| 4702 | ##instance."""))
|
|---|
| 4703 |
|
|---|
| 4704 | ###############################################################################
|
|---|
| 4705 | # Metadata: Field class
|
|---|
| 4706 | ###############################################################################
|
|---|
| 4707 |
|
|---|
| 4708 | AddClassMetadata(Field,
|
|---|
| 4709 | shortDescription=_(u'Represents a field of a tabular dataset.'),
|
|---|
| 4710 | longDescription=_(
|
|---|
| 4711 | u"""The Field class is not intended to be instantiated explicitly by
|
|---|
| 4712 | external callers. To obtain an instance, call GetFieldByName or
|
|---|
| 4713 | examine the Fields list of a Table instance."""))
|
|---|
| 4714 |
|
|---|
| 4715 | # Public properties
|
|---|
| 4716 |
|
|---|
| 4717 | AddPropertyMetadata(Field.Name,
|
|---|
| 4718 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 4719 | shortDescription=_(u'Name of the field.'))
|
|---|
| 4720 |
|
|---|
| 4721 | AddPropertyMetadata(Field.DataType,
|
|---|
| 4722 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'binary', u'date', u'datetime', u'float32', u'float64', u'geometry', u'int16', u'int32', u'oid', u'string']),
|
|---|
| 4723 | shortDescription=_(u'Data type of the field.'))
|
|---|
| 4724 |
|
|---|
| 4725 | AddPropertyMetadata(Field.Length,
|
|---|
| 4726 | typeMetadata=IntegerTypeMetadata(canBeNone=True),
|
|---|
| 4727 | shortDescription=_(u'Length of the field.'),
|
|---|
| 4728 | longDescription=_(
|
|---|
| 4729 | u"""The underlying data format and programming library used to access
|
|---|
| 4730 | it determine the exact meaning of this property. It is generally only
|
|---|
| 4731 | relevant if the field's data type is 'string' or 'binary', in which
|
|---|
| 4732 | case it is the maximum number of characters or bytes that may be
|
|---|
| 4733 | stored in the field. The value 0 or a Python None typically indicates
|
|---|
| 4734 | that the maximum limit is not known or depends on available disk
|
|---|
| 4735 | space."""))
|
|---|
| 4736 |
|
|---|
| 4737 | AddPropertyMetadata(Field.Precision,
|
|---|
| 4738 | typeMetadata=IntegerTypeMetadata(canBeNone=True),
|
|---|
| 4739 | shortDescription=_(u'Precision of the field.'),
|
|---|
| 4740 | longDescription=_(
|
|---|
| 4741 | u"""The underlying data format and programming library used to access
|
|---|
| 4742 | it determine the exact meaning of this property. It is generally only
|
|---|
| 4743 | relevant if the field's data type is 'float32' or 'float64', in which
|
|---|
| 4744 | case it is typically either the maximum number of digits that can be
|
|---|
| 4745 | stored in the field or the maximum number of decimal places. """))
|
|---|
| 4746 |
|
|---|
| 4747 | AddPropertyMetadata(Field.IsNullable,
|
|---|
| 4748 | typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4749 | shortDescription=_(u'True if the field may be set to a database null value, or False if it may only be set to a non-null value.'),
|
|---|
| 4750 | longDescription=_(
|
|---|
| 4751 | u"""Some underlying programming libraries, such as OGR, do not provide
|
|---|
| 4752 | a mechanism for determining whether a field is nullable. In these
|
|---|
| 4753 | cases, True is always returned, and it will be up to the underlying
|
|---|
| 4754 | library to succeed or fail when a field is actually set to null."""))
|
|---|
| 4755 |
|
|---|
| 4756 | AddPropertyMetadata(Field.IsSettable,
|
|---|
| 4757 | typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4758 | shortDescription=_(u'True if the field may be set, or False if it is read-only.'),
|
|---|
| 4759 | longDescription=_(
|
|---|
| 4760 | u"""Certain fields, such as the Shape_Length and Shape_Area fields of
|
|---|
| 4761 | feature classes in ArcGIS geodatabases, are read-only and managed by
|
|---|
| 4762 | the underlying data format or programming library used to access
|
|---|
| 4763 | it."""))
|
|---|
| 4764 |
|
|---|
| 4765 | ###############################################################################
|
|---|
| 4766 | # Metadata: _Cursor class
|
|---|
| 4767 | ###############################################################################
|
|---|
| 4768 |
|
|---|
| 4769 | AddClassMetadata(_Cursor,
|
|---|
| 4770 | shortDescription=_(u'Base class for other cursor classes.'),
|
|---|
| 4771 | longDescription=_(
|
|---|
| 4772 | u"""This base class provides functionality common to the other cursor
|
|---|
| 4773 | classes. It is mainly intended to be a container for common methods
|
|---|
| 4774 | and is not intended to be instantiated explicitly by external callers.
|
|---|
| 4775 | To obtain an instance, call Table.OpenSelectCursor,
|
|---|
| 4776 | Table.OpenUpdateCursor, or Table.OpenInsertCursor."""))
|
|---|
| 4777 |
|
|---|
| 4778 | # Public properties
|
|---|
| 4779 |
|
|---|
| 4780 | AddPropertyMetadata(_Cursor.Table,
|
|---|
| 4781 | typeMetadata=ClassInstanceTypeMetadata(cls=Table),
|
|---|
| 4782 | shortDescription=_(u'Table to which this cursor is opened.'))
|
|---|
| 4783 |
|
|---|
| 4784 | # Public method: _Cursor.SetRowCount
|
|---|
| 4785 |
|
|---|
| 4786 | AddMethodMetadata(_Cursor.SetRowCount,
|
|---|
| 4787 | shortDescription=_(u'Sets the number of rows that this cursor is expected to process.'),
|
|---|
| 4788 | longDescription=_(
|
|---|
| 4789 | u"""The row count is only used in progress reporting and is ignored if
|
|---|
| 4790 | the reportProgress parameter was False when the cursor was opened. If
|
|---|
| 4791 | a row count has been provided, the progress reports will include the
|
|---|
| 4792 | number of rows remaining and an estimated time of completion. If a row
|
|---|
| 4793 | count has not been provided, the progress reports will only include
|
|---|
| 4794 | the number of rows processed so far.
|
|---|
| 4795 |
|
|---|
| 4796 | Typically, if the row count is known ahead of time, you should provide
|
|---|
| 4797 | it to the method used to open the cursor. Use SetRowCount when you
|
|---|
| 4798 | want to revise the row count after opening the cursor. Do not decrease
|
|---|
| 4799 | the row count to a value smaller than the number of rows processed so
|
|---|
| 4800 | far."""),
|
|---|
| 4801 | isExposedToPythonCallers=True)
|
|---|
| 4802 |
|
|---|
| 4803 | AddArgumentMetadata(_Cursor.SetRowCount, u'self',
|
|---|
| 4804 | typeMetadata=ClassInstanceTypeMetadata(cls=_Cursor),
|
|---|
| 4805 | description=_(u'%s instance.') % _Cursor.__name__)
|
|---|
| 4806 |
|
|---|
| 4807 | AddArgumentMetadata(_Cursor.SetRowCount, u'rowCount',
|
|---|
| 4808 | typeMetadata=IntegerTypeMetadata(minValue=1),
|
|---|
| 4809 | description=_(u"""New row count for this cursor."""))
|
|---|
| 4810 |
|
|---|
| 4811 | ###############################################################################
|
|---|
| 4812 | # Metadata: SelectCursor class
|
|---|
| 4813 | ###############################################################################
|
|---|
| 4814 |
|
|---|
| 4815 | AddClassMetadata(SelectCursor,
|
|---|
| 4816 | shortDescription=_(u'Represents a forward-only cursor used to read rows from a tabular dataset.'),
|
|---|
| 4817 | longDescription=_(
|
|---|
| 4818 | u"""The SelectCursor class is not intended to be instantiated
|
|---|
| 4819 | explicitly by external callers. To obtain an instance, call
|
|---|
| 4820 | Table.OpenSelectCursor.
|
|---|
| 4821 |
|
|---|
| 4822 | After obtaining a SelectCursor instance, call NextRow to advance the
|
|---|
| 4823 | cursor to the first row. If NextRow returns True, use GetValue and
|
|---|
| 4824 | GetGeometry to access fields of the row and its geometry. Call NextRow
|
|---|
| 4825 | again to advance to the next row. When NextRow returns False, no rows
|
|---|
| 4826 | remain. To close the cursor, release all references to the
|
|---|
| 4827 | SelectCursor instance.
|
|---|
| 4828 |
|
|---|
| 4829 | The typical Python code looks like this::
|
|---|
| 4830 |
|
|---|
| 4831 | cursor = dataset.OpenSelectCursor(...)
|
|---|
| 4832 | try:
|
|---|
| 4833 | while cursor.NextRow():
|
|---|
| 4834 | value = cursor.GetValue(...)
|
|---|
| 4835 | ...
|
|---|
| 4836 | finally:
|
|---|
| 4837 | del cursor
|
|---|
| 4838 |
|
|---|
| 4839 | To ensure that the cursor is closed in the event of an error, be sure
|
|---|
| 4840 | to use a ``try...finally`` statement, as shown above."""))
|
|---|
| 4841 |
|
|---|
| 4842 | # Public properties
|
|---|
| 4843 |
|
|---|
| 4844 | AddPropertyMetadata(SelectCursor.AtEnd,
|
|---|
| 4845 | typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4846 | shortDescription=_(u'True if the last row of this cursor has been processed and none remain.'))
|
|---|
| 4847 |
|
|---|
| 4848 | # Public method: SelectCursor.NextRow
|
|---|
| 4849 |
|
|---|
| 4850 | AddMethodMetadata(SelectCursor.NextRow,
|
|---|
| 4851 | shortDescription=_(u'Advances the cursor to the next row.'),
|
|---|
| 4852 | isExposedToPythonCallers=True)
|
|---|
| 4853 |
|
|---|
| 4854 | AddArgumentMetadata(SelectCursor.NextRow, u'self',
|
|---|
| 4855 | typeMetadata=ClassInstanceTypeMetadata(cls=SelectCursor),
|
|---|
| 4856 | description=_(u'%s instance.') % SelectCursor.__name__)
|
|---|
| 4857 |
|
|---|
| 4858 | AddResultMetadata(SelectCursor.NextRow, u'rowAvailable',
|
|---|
| 4859 | typeMetadata=BooleanTypeMetadata(),
|
|---|
| 4860 | description=_(
|
|---|
| 4861 | u"""True if a row is available. False if no more rows are available.
|
|---|
| 4862 |
|
|---|
| 4863 | After opening the cursor, you must call NextRow prior to accessing the
|
|---|
| 4864 | first row, and call it again prior to accessing each subsequent row.
|
|---|
| 4865 | Once NextRow returns False, no more rows are avaiable and row-access
|
|---|
| 4866 | functions such as GetValue will fail.
|
|---|
| 4867 |
|
|---|
| 4868 | If NextRow has not been called yet, or the last time it was called it
|
|---|
| 4869 | returned True, the AtEnd property will be False. Once NextRow returns
|
|---|
| 4870 | False, AtEnd will be True."""))
|
|---|
| 4871 |
|
|---|
| 4872 | # Public method: SelectCursor.GetValue
|
|---|
| 4873 |
|
|---|
| 4874 | AddMethodMetadata(SelectCursor.GetValue,
|
|---|
| 4875 | shortDescription=_(u'Retrieves the value of a field of the current row, given the name of the field.'),
|
|---|
| 4876 | isExposedToPythonCallers=True)
|
|---|
| 4877 |
|
|---|
| 4878 | CopyArgumentMetadata(SelectCursor.NextRow, u'self', SelectCursor.GetValue, u'self')
|
|---|
| 4879 |
|
|---|
| 4880 | AddArgumentMetadata(SelectCursor.GetValue, u'field',
|
|---|
| 4881 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 4882 | description=_(
|
|---|
| 4883 | u"""Name of the field to get the value of.
|
|---|
| 4884 |
|
|---|
| 4885 | If you specified a list of fields to retrieve when you opened the
|
|---|
| 4886 | cursor, you will only be able to retrieve the values of those fields.
|
|---|
| 4887 | If you did not specify such a list, then you will be able to retrieve
|
|---|
| 4888 | all of the fields of the dataset.
|
|---|
| 4889 |
|
|---|
| 4890 | This method cannot be used to get the geometry of the row, even if the
|
|---|
| 4891 | underlying data format stores the geometry in a named field. To get
|
|---|
| 4892 | the geometry, use the GetGeometry method."""))
|
|---|
| 4893 |
|
|---|
| 4894 | AddResultMetadata(SelectCursor.GetValue, u'value',
|
|---|
| 4895 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 4896 | description=_(
|
|---|
| 4897 | u"""Value of the field.
|
|---|
| 4898 |
|
|---|
| 4899 | If the value of the field is a database null, a Python None will be
|
|---|
| 4900 | returned. Otherwise the Python data type of the returned value will
|
|---|
| 4901 | depend on the data type of the field:
|
|---|
| 4902 |
|
|---|
| 4903 | ================= ====================
|
|---|
| 4904 | Field Data Type Returned Python Type
|
|---|
| 4905 | ================= ====================
|
|---|
| 4906 | binary str
|
|---|
| 4907 | date, datetime datetime.datetime
|
|---|
| 4908 | float32, float64 float
|
|---|
| 4909 | int16, int32, oid int
|
|---|
| 4910 | string unicode
|
|---|
| 4911 | ================= ====================
|
|---|
| 4912 |
|
|---|
| 4913 | For fields with the date data type, the time of the returned
|
|---|
| 4914 | ``datetime.datetime`` instance will be 00:00:00."""))
|
|---|
| 4915 |
|
|---|
| 4916 | # Public method: SelectCursor.GetGeometry
|
|---|
| 4917 |
|
|---|
| 4918 | AddMethodMetadata(SelectCursor.GetGeometry,
|
|---|
| 4919 | shortDescription=_(u'Retrieves the geometry of the current row.'),
|
|---|
| 4920 | longDescription=_(
|
|---|
| 4921 | u"""This method will fail if the dataset does not have geometry. To
|
|---|
| 4922 | determine if it has geometry, check the GeometryType property of the
|
|---|
| 4923 | cursor's Dataset."""),
|
|---|
| 4924 | isExposedToPythonCallers=True)
|
|---|
| 4925 |
|
|---|
| 4926 | CopyArgumentMetadata(SelectCursor.NextRow, u'self', SelectCursor.GetGeometry, u'self')
|
|---|
| 4927 |
|
|---|
| 4928 | AddResultMetadata(SelectCursor.GetGeometry, u'geometry',
|
|---|
| 4929 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 4930 | description=_(
|
|---|
| 4931 | u"""Instance of the OGR Geometry class representing the geometry of
|
|---|
| 4932 | the row. If the row has "null geometry", a Python None will be
|
|---|
| 4933 | returned.
|
|---|
| 4934 |
|
|---|
| 4935 | OGR utilizes its own memory management scheme that requires explicit
|
|---|
| 4936 | management of certain kinds of objects, including Geometry instances.
|
|---|
| 4937 | The Geometry instance returned here is owned by you (the caller of
|
|---|
| 4938 | GetGeometry). Unless you transfer ownership of the instance to someone
|
|---|
| 4939 | else, you are responsible for calling the Destroy method of the
|
|---|
| 4940 | instance to explicitly deallocate its internal memory.
|
|---|
| 4941 |
|
|---|
| 4942 | The Geometry instance is allocated from MGET's internal copy of OGR
|
|---|
| 4943 | (the GeoEco.AssimilatedModules.osgeo.ogr module). Although MGET does
|
|---|
| 4944 | not alter OGR in any way, the returned instance is not really intended
|
|---|
| 4945 | to be used with other copies of OGR. Thus, if you install your own
|
|---|
| 4946 | copy of OGR, the Geometry instances returned by this method may not be
|
|---|
| 4947 | compatible with your copy, due to how OGR is implemented. To work
|
|---|
| 4948 | around this, you could export the Geometry instance returned here to
|
|---|
| 4949 | WKT and instantiate a Geometry instance from it using your own copy of
|
|---|
| 4950 | OGR. Feel free to contact the MGET development team for help with this
|
|---|
| 4951 | problem."""))
|
|---|
| 4952 |
|
|---|
| 4953 | ###############################################################################
|
|---|
| 4954 | # Metadata: UpdateCursor class
|
|---|
| 4955 | ###############################################################################
|
|---|
| 4956 |
|
|---|
| 4957 | AddClassMetadata(UpdateCursor,
|
|---|
| 4958 | shortDescription=_(u'Represents a forward-only cursor used to update or delete rows in a tabular dataset.'),
|
|---|
| 4959 | longDescription=_(
|
|---|
| 4960 | u"""Not all datasets support update cursors. To determine if a dataset
|
|---|
| 4961 | supports update cursors, call TestCapability('UpdateCursor') on the
|
|---|
| 4962 | dataset. Some datasets that support update cursors only support
|
|---|
| 4963 | updating rows, not deleting them, or visa versa. To check this, call
|
|---|
| 4964 | TestCapability('UpdateRow') and TestCapability('DeleteRow') on the
|
|---|
| 4965 | dataset.
|
|---|
| 4966 |
|
|---|
| 4967 | The UpdateCursor class is not intended to be instantiated explicitly
|
|---|
| 4968 | by external callers. To obtain an instance, call
|
|---|
| 4969 | Table.OpenUpdateCursor.
|
|---|
| 4970 |
|
|---|
| 4971 | After obtaining an UpdateCursor instance, call NextRow to advance the
|
|---|
| 4972 | cursor to the first row. If NextRow returns True, use GetValue and
|
|---|
| 4973 | GetGeometry to access fields of the row and its geometry. To update
|
|---|
| 4974 | the row, use SetValue and SetGeometry followed by UpdateRow. Use
|
|---|
| 4975 | DeleteRow to delete the row. Call NextRow again to advance to the next
|
|---|
| 4976 | row. When NextRow returns False, no rows remain. To close the cursor,
|
|---|
| 4977 | release all references to the UpdateCursor instance.
|
|---|
| 4978 |
|
|---|
| 4979 | The typical Python code looks like this::
|
|---|
| 4980 |
|
|---|
| 4981 | cursor = dataset.OpenUpdateCursor(...)
|
|---|
| 4982 | try:
|
|---|
| 4983 | while cursor.NextRow():
|
|---|
| 4984 | value = cursor.GetValue(...)
|
|---|
| 4985 | ...
|
|---|
| 4986 | if wantToUpdateRow:
|
|---|
| 4987 | cursor.SetValue(...)
|
|---|
| 4988 | ...
|
|---|
| 4989 | cursor.UpdateRow()
|
|---|
| 4990 | elif wantToDeleteRow:
|
|---|
| 4991 | cursor.DeleteRow()
|
|---|
| 4992 | finally:
|
|---|
| 4993 | del cursor
|
|---|
| 4994 |
|
|---|
| 4995 | To ensure that the cursor is closed in the event of an error, be sure
|
|---|
| 4996 | to use a ``try...finally`` statement, as shown above."""))
|
|---|
| 4997 |
|
|---|
| 4998 | # Public method: UpdateCursor.SetValue
|
|---|
| 4999 |
|
|---|
| 5000 | AddMethodMetadata(UpdateCursor.SetValue,
|
|---|
| 5001 | shortDescription=_(u'Sets the value of a field of the current row, given the name of the field and its new value.'),
|
|---|
| 5002 | longDescription=_(
|
|---|
| 5003 | u"""Changes to the row are not actually submitted through the
|
|---|
| 5004 | underlying programming library to the underlying data store until
|
|---|
| 5005 | UpdateRow is called. If you call SetValue but then neglect to call
|
|---|
| 5006 | UpdateRow before calling NextRow, your changes will be lost."""),
|
|---|
| 5007 | isExposedToPythonCallers=True)
|
|---|
| 5008 |
|
|---|
| 5009 | AddArgumentMetadata(UpdateCursor.SetValue, u'self',
|
|---|
| 5010 | typeMetadata=ClassInstanceTypeMetadata(cls=UpdateCursor),
|
|---|
| 5011 | description=_(u'%s instance.') % UpdateCursor.__name__)
|
|---|
| 5012 |
|
|---|
| 5013 | AddArgumentMetadata(UpdateCursor.SetValue, u'field',
|
|---|
| 5014 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 5015 | description=_(
|
|---|
| 5016 | u"""Name of the field to set the value of.
|
|---|
| 5017 |
|
|---|
| 5018 | If you specified a list of fields to retrieve when you opened the
|
|---|
| 5019 | cursor, you will only be able to set the values of those fields. If
|
|---|
| 5020 | you did not specify such a list, then you will be able to set all of
|
|---|
| 5021 | the fields of the dataset.
|
|---|
| 5022 |
|
|---|
| 5023 | This method cannot be used to set the geometry of the row, even if the
|
|---|
| 5024 | underlying data format stores the geometry in a named field. To set
|
|---|
| 5025 | the geometry, use the SetGeometry method.
|
|---|
| 5026 |
|
|---|
| 5027 | This method cannot be used to set the object ID (OID) field (sometimes
|
|---|
| 5028 | called feature ID, or FID). That field is read-only and managed by the
|
|---|
| 5029 | underlying data format or programming library used to access it.
|
|---|
| 5030 |
|
|---|
| 5031 | The underlying data format or programming library may expose other
|
|---|
| 5032 | read-only fields. For example, some versions of ArcGIS maintain fields
|
|---|
| 5033 | called Shape_Length and Shape_Area in feature classes in ArcGIS
|
|---|
| 5034 | geodatabases. These may not be set either. To determine if a field may
|
|---|
| 5035 | be set, examine the IsSettable property of the Field instances
|
|---|
| 5036 | contained in the Field list of the cursor's Dataset."""))
|
|---|
| 5037 |
|
|---|
| 5038 | AddArgumentMetadata(UpdateCursor.SetValue, u'value',
|
|---|
| 5039 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 5040 | description=_(
|
|---|
| 5041 | u"""Value of the field.
|
|---|
| 5042 |
|
|---|
| 5043 | To set the field to a database null, use Python's None. Otherwise, you
|
|---|
| 5044 | must provide an instance of the Python type that is appropriate for
|
|---|
| 5045 | the data type of the field:
|
|---|
| 5046 |
|
|---|
| 5047 | ================= =======================
|
|---|
| 5048 | Field Data Type Appropriate Python Type
|
|---|
| 5049 | ================= =======================
|
|---|
| 5050 | binary str
|
|---|
| 5051 | date, datetime datetime.datetime
|
|---|
| 5052 | float32, float64 float
|
|---|
| 5053 | int16, int32 int
|
|---|
| 5054 | string unicode
|
|---|
| 5055 | ================= =======================
|
|---|
| 5056 |
|
|---|
| 5057 | To determine the data type of a field, call GetFieldByName on the
|
|---|
| 5058 | Dataset and examine the DataType property. """))
|
|---|
| 5059 |
|
|---|
| 5060 | # Public method: UpdateCursor.SetGeometry
|
|---|
| 5061 |
|
|---|
| 5062 | AddMethodMetadata(UpdateCursor.SetGeometry,
|
|---|
| 5063 | shortDescription=_(u'Sets the geometry of the current row.'),
|
|---|
| 5064 | longDescription=_(
|
|---|
| 5065 | u"""This method will fail if the dataset does not have geometry. To
|
|---|
| 5066 | determine if it has geometry, check the GeometryType property of the
|
|---|
| 5067 | cursor's Dataset.
|
|---|
| 5068 |
|
|---|
| 5069 | Changes to the row are not actually submitted through the underlying
|
|---|
| 5070 | programming library to the underlying data store until UpdateRow is
|
|---|
| 5071 | called. If you call SetGeometry but then neglect to call UpdateRow
|
|---|
| 5072 | before calling NextRow, your changes will be lost."""),
|
|---|
| 5073 | isExposedToPythonCallers=True)
|
|---|
| 5074 |
|
|---|
| 5075 | CopyArgumentMetadata(UpdateCursor.SetValue, u'self', UpdateCursor.SetGeometry, u'self')
|
|---|
| 5076 |
|
|---|
| 5077 | AddArgumentMetadata(UpdateCursor.SetGeometry, u'geometry',
|
|---|
| 5078 | typeMetadata=AnyObjectTypeMetadata(),
|
|---|
| 5079 | description=_(
|
|---|
| 5080 | u"""Instance of the OGR Geometry class representing the geometry of
|
|---|
| 5081 | the row.
|
|---|
| 5082 |
|
|---|
| 5083 | MGET includes an internal copy of OGR (the
|
|---|
| 5084 | GeoEco.AssimilatedModules.osgeo.ogr module) and it is expected that
|
|---|
| 5085 | you will allocate the Geometry instance from there. The typical Python
|
|---|
| 5086 | code looks like this::
|
|---|
| 5087 |
|
|---|
| 5088 | from GeoEco.Dependencies import ImportGDALModule
|
|---|
| 5089 | ogr = ImportGDALModule('osgeo.ogr')
|
|---|
| 5090 | geometry = ogr.Geometry(...) # Can also use other functions to create Geometry instances
|
|---|
| 5091 | try:
|
|---|
| 5092 | ...
|
|---|
| 5093 | cursor.SetGeometry(geometry)
|
|---|
| 5094 | finally:
|
|---|
| 5095 | geometry.Destroy()
|
|---|
| 5096 |
|
|---|
| 5097 | OGR utilizes its own memory management scheme that requires explicit
|
|---|
| 5098 | management of certain kinds of objects, including Geometry instances.
|
|---|
| 5099 | Ownership of the Geometry instance that you provide remains with you
|
|---|
| 5100 | (the caller of SetGeometry). Unless you subsequently transfer
|
|---|
| 5101 | ownership of the instance to someone else, you are responsible for
|
|---|
| 5102 | calling the Destroy method of the instance to explicitly deallocate
|
|---|
| 5103 | its internal memory, as shown above. To ensure that the deallocation
|
|---|
| 5104 | occurs in the event of an error, be sure to use a ``try...finally``
|
|---|
| 5105 | statement, as shown."""))
|
|---|
| 5106 |
|
|---|
| 5107 | # Public method: UpdateCursor.UpdateRow
|
|---|
| 5108 |
|
|---|
| 5109 | AddMethodMetadata(UpdateCursor.UpdateRow,
|
|---|
| 5110 | shortDescription=_(u'Submits any changes made to the current row to the underlying data store.'),
|
|---|
| 5111 | longDescription=_(
|
|---|
| 5112 | u"""You cannot access a row after calling UpdateRow; GetValue,
|
|---|
| 5113 | SetValue, and so on will not work. You cannot delete it. You must call
|
|---|
| 5114 | NextRow to advance the cursor to the next row.
|
|---|
| 5115 |
|
|---|
| 5116 | Certain datasets may implement a transactional updating scheme in
|
|---|
| 5117 | which the change will not be committed to the underlying data store
|
|---|
| 5118 | until the cursor has been closed. For more information, please see the
|
|---|
| 5119 | documentation for the derived class you are using to access the
|
|---|
| 5120 | dataset."""),
|
|---|
| 5121 | isExposedToPythonCallers=True)
|
|---|
| 5122 |
|
|---|
| 5123 | CopyArgumentMetadata(UpdateCursor.SetValue, u'self', UpdateCursor.UpdateRow, u'self')
|
|---|
| 5124 |
|
|---|
| 5125 | # Public method: UpdateCursor.DeleteRow
|
|---|
| 5126 |
|
|---|
| 5127 | AddMethodMetadata(UpdateCursor.DeleteRow,
|
|---|
| 5128 | shortDescription=_(u'Deletes the current row.'),
|
|---|
| 5129 | longDescription=_(
|
|---|
| 5130 | u"""You cannot access a row after calling DeleteRow; GetValue,
|
|---|
| 5131 | SetValue, and so on will not work. You cannot update it. You must call
|
|---|
| 5132 | NextRow to advance the cursor to the next row.
|
|---|
| 5133 |
|
|---|
| 5134 | Certain datasets may implement a transactional updating scheme in
|
|---|
| 5135 | which the delete will not be committed to the underlying data store
|
|---|
| 5136 | until the cursor has been closed. For more information, please see the
|
|---|
| 5137 | documentation for the derived class you are using to access the
|
|---|
| 5138 | dataset."""),
|
|---|
| 5139 | isExposedToPythonCallers=True)
|
|---|
| 5140 |
|
|---|
| 5141 | CopyArgumentMetadata(UpdateCursor.SetValue, u'self', UpdateCursor.DeleteRow, u'self')
|
|---|
| 5142 |
|
|---|
| 5143 | ###############################################################################
|
|---|
| 5144 | # Metadata: InsertCursor class
|
|---|
| 5145 | ###############################################################################
|
|---|
| 5146 |
|
|---|
| 5147 | AddClassMetadata(InsertCursor,
|
|---|
| 5148 | shortDescription=_(u'Represents a cursor used to insert rows into a tabular dataset.'),
|
|---|
| 5149 | longDescription=_(
|
|---|
| 5150 | u"""Not all datasets support insert cursors. To determine if a dataset
|
|---|
| 5151 | supports insert cursors, call TestCapability('InsertCursor') on the
|
|---|
| 5152 | dataset.
|
|---|
| 5153 |
|
|---|
| 5154 | The InsertCursor class is not intended to be instantiated explicitly
|
|---|
| 5155 | by external callers. To obtain an instance, call
|
|---|
| 5156 | Table.OpenInsertCursor.
|
|---|
| 5157 |
|
|---|
| 5158 | After obtaining an InsertCursor instance, use SetValue and SetGeometry
|
|---|
| 5159 | to set the values of the fields and the geometry of a new row. Call
|
|---|
| 5160 | InsertRow to submit the new row to the underlying data store. Repeat
|
|---|
| 5161 | this pattern until you are finished inserting rows. Then close the
|
|---|
| 5162 | cursor by releasing all references to the InsertCursor instance.
|
|---|
| 5163 |
|
|---|
| 5164 | The typical Python code looks like this::
|
|---|
| 5165 |
|
|---|
| 5166 | cursor = dataset.OpenInsertCursor(...)
|
|---|
| 5167 | try:
|
|---|
| 5168 | for ...: # Loop over rows, inserting one at a time
|
|---|
| 5169 | cursor.SetValue(...)
|
|---|
| 5170 | ...
|
|---|
| 5171 | cursor.InsertRow()
|
|---|
| 5172 | finally:
|
|---|
| 5173 | del cursor
|
|---|
| 5174 |
|
|---|
| 5175 | To ensure that the cursor is closed in the event of an error, be sure
|
|---|
| 5176 | to use a ``try...finally`` statement, as shown above."""))
|
|---|
| 5177 |
|
|---|
| 5178 | # Public method: InsertCursor.SetValue
|
|---|
| 5179 |
|
|---|
| 5180 | AddMethodMetadata(InsertCursor.SetValue,
|
|---|
| 5181 | shortDescription=_(u'Sets the value of a field of the current row, given the name of the field and its new value.'),
|
|---|
| 5182 | longDescription=_(
|
|---|
| 5183 | u"""The row is not actually submitted through the underlying
|
|---|
| 5184 | programming library to the underlying data store until InsertRow is
|
|---|
| 5185 | called. If you call SetValue but then neglect to call InsertRow before
|
|---|
| 5186 | closing the cursor, your new row will be lost."""),
|
|---|
| 5187 | isExposedToPythonCallers=True)
|
|---|
| 5188 |
|
|---|
| 5189 | AddArgumentMetadata(InsertCursor.SetValue, u'self',
|
|---|
| 5190 | typeMetadata=ClassInstanceTypeMetadata(cls=InsertCursor),
|
|---|
| 5191 | description=_(u'%s instance.') % InsertCursor.__name__)
|
|---|
| 5192 |
|
|---|
| 5193 | AddArgumentMetadata(InsertCursor.SetValue, u'field',
|
|---|
| 5194 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 5195 | description=_(
|
|---|
| 5196 | u"""Name of the field to set the value of.
|
|---|
| 5197 |
|
|---|
| 5198 | This method cannot be used to set the geometry of the row, even if the
|
|---|
| 5199 | underlying data format stores the geometry in a named field. To set
|
|---|
| 5200 | the geometry, use the SetGeometry method.
|
|---|
| 5201 |
|
|---|
| 5202 | This method cannot be used to set the object ID (OID) field (sometimes
|
|---|
| 5203 | called feature ID, or FID). That field is read-only and managed by the
|
|---|
| 5204 | underlying data format or programming library used to access it.
|
|---|
| 5205 |
|
|---|
| 5206 | The underlying data format or programming library may expose other
|
|---|
| 5207 | read-only fields. For example, some versions of ArcGIS maintain fields
|
|---|
| 5208 | called Shape_Length and Shape_Area in feature classes in ArcGIS
|
|---|
| 5209 | geodatabases. These may not be set either. To determine if a field may
|
|---|
| 5210 | be set, examine the IsSettable property of the Field instances
|
|---|
| 5211 | contained in the Field list of the cursor's Dataset."""))
|
|---|
| 5212 |
|
|---|
| 5213 | CopyArgumentMetadata(UpdateCursor.SetValue, u'value', InsertCursor.SetValue, u'value')
|
|---|
| 5214 |
|
|---|
| 5215 | # Public method: InsertCursor.SetGeometry
|
|---|
| 5216 |
|
|---|
| 5217 | AddMethodMetadata(InsertCursor.SetGeometry,
|
|---|
| 5218 | shortDescription=_(u'Sets the geometry of the current row.'),
|
|---|
| 5219 | longDescription=_(
|
|---|
| 5220 | u"""This method will fail if the dataset does not have geometry. To
|
|---|
| 5221 | determine if it has geometry, check the GeometryType property of the
|
|---|
| 5222 | cursor's Dataset.
|
|---|
| 5223 |
|
|---|
| 5224 | The row is not actually submitted through the underlying programming
|
|---|
| 5225 | library to the underlying data store until InsertRow is called. If you
|
|---|
| 5226 | call SetGeometry but then neglect to call InsertRow before closing the
|
|---|
| 5227 | cursor, your new row will be lost."""),
|
|---|
| 5228 | isExposedToPythonCallers=True)
|
|---|
| 5229 |
|
|---|
| 5230 | CopyArgumentMetadata(InsertCursor.SetValue, u'self', InsertCursor.SetGeometry, u'self')
|
|---|
| 5231 | CopyArgumentMetadata(UpdateCursor.SetGeometry, u'geometry', InsertCursor.SetGeometry, u'geometry')
|
|---|
| 5232 |
|
|---|
| 5233 | # Public method: InsertCursor.InsertRow
|
|---|
| 5234 |
|
|---|
| 5235 | AddMethodMetadata(InsertCursor.InsertRow,
|
|---|
| 5236 | shortDescription=_(u'Submits the new row to the underlying data store.'),
|
|---|
| 5237 | longDescription=_(
|
|---|
| 5238 | u"""If you do not explicitly set values of all of the row's fields by
|
|---|
| 5239 | calling SetValue prior to calling InsertRow, InsertRow will set those
|
|---|
| 5240 | fields to database null (if they are not read-only). If a field that
|
|---|
| 5241 | has not been set is not nullable, InsertRow will report an error. To
|
|---|
| 5242 | determine if a field is nullable, call GetFieldByName on the Datset
|
|---|
| 5243 | and examine the IsNullable property.
|
|---|
| 5244 |
|
|---|
| 5245 | Certain datasets may implement a transactional updating scheme in
|
|---|
| 5246 | which the new row will not be committed to the underlying data store
|
|---|
| 5247 | until the cursor has been closed. For more information, please see the
|
|---|
| 5248 | documentation for the derived class you are using to access the
|
|---|
| 5249 | dataset."""),
|
|---|
| 5250 | isExposedToPythonCallers=True)
|
|---|
| 5251 |
|
|---|
| 5252 | CopyArgumentMetadata(InsertCursor.SetValue, u'self', InsertCursor.InsertRow, u'self')
|
|---|
| 5253 |
|
|---|
| 5254 | ###############################################################################
|
|---|
| 5255 | # Metadata: Grid class
|
|---|
| 5256 | ###############################################################################
|
|---|
| 5257 |
|
|---|
| 5258 | AddClassMetadata(Grid,
|
|---|
| 5259 | shortDescription=_(u'Represents a 2D, 3D, or 4D gridded dataset, such as a Scientific Data Set from an HDF file or Grid variable from an OPeNDAP URL.')),
|
|---|
| 5260 |
|
|---|
| 5261 | # Private constructor: Grid.__init__
|
|---|
| 5262 |
|
|---|
| 5263 | AddMethodMetadata(Grid.__init__,
|
|---|
| 5264 | shortDescription=_(u'Grid constructor. Not intended to be called directly. Only intended to be called from derived class constructors.'),
|
|---|
| 5265 | dependencies=[PythonAggregatedModuleDependency('numpy')])
|
|---|
| 5266 |
|
|---|
| 5267 | AddArgumentMetadata(Grid.__init__, u'self',
|
|---|
| 5268 | typeMetadata=ClassInstanceTypeMetadata(cls=Grid),
|
|---|
| 5269 | description=_(u'%s instance.') % Grid.__name__)
|
|---|
| 5270 |
|
|---|
| 5271 | AddArgumentMetadata(Grid.__init__, u'parentCollection',
|
|---|
| 5272 | typeMetadata=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'parentCollection').Type,
|
|---|
| 5273 | description=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'parentCollection').Description)
|
|---|
| 5274 |
|
|---|
| 5275 | AddArgumentMetadata(Grid.__init__, u'queryableAttributes',
|
|---|
| 5276 | typeMetadata=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'queryableAttributes').Type,
|
|---|
| 5277 | description=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'queryableAttributes').Description)
|
|---|
| 5278 |
|
|---|
| 5279 | AddArgumentMetadata(Grid.__init__, u'queryableAttributeValues',
|
|---|
| 5280 | typeMetadata=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'queryableAttributeValues').Type,
|
|---|
| 5281 | description=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'queryableAttributeValues').Description)
|
|---|
| 5282 |
|
|---|
| 5283 | AddArgumentMetadata(Grid.__init__, u'lazyPropertyValues',
|
|---|
| 5284 | typeMetadata=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'lazyPropertyValues').Type,
|
|---|
| 5285 | description=CollectibleObject.__init__.__doc__.Obj.GetArgumentByName(u'lazyPropertyValues').Description)
|
|---|
| 5286 |
|
|---|
| 5287 | AddResultMetadata(Grid.__init__, u'grid',
|
|---|
| 5288 | typeMetadata=ClassInstanceTypeMetadata(cls=Grid),
|
|---|
| 5289 | description=_(u'%s instance.') % Grid.__name__)
|
|---|
| 5290 |
|
|---|
| 5291 | # TODO: Add metadata
|
|---|
| 5292 |
|
|---|
| 5293 | ###############################################################################
|
|---|
| 5294 | # Metadata: NumpyGrid class
|
|---|
| 5295 | ###############################################################################
|
|---|
| 5296 |
|
|---|
| 5297 | AddClassMetadata(NumpyGrid,
|
|---|
| 5298 | shortDescription=_(u'Wraps a numpy array in the Grid interface.'),
|
|---|
| 5299 | longDescription=_(
|
|---|
| 5300 | u"""NumpyGrid provides a convenient mechanism for modifying Grids. The
|
|---|
| 5301 | typical usage pattern is:
|
|---|
| 5302 |
|
|---|
| 5303 | 1. Obtain a Grid instance from somewhere (e.g. an ArcGISRasterBand
|
|---|
| 5304 | instance representing a band of an ArcGIS raster).
|
|---|
| 5305 |
|
|---|
| 5306 | 2. Call NumpyGrid.CreateFromGrid to wrap the Grid in a NumpyGrid.
|
|---|
| 5307 |
|
|---|
| 5308 | 3. Get and set slices of the Data property of the NumpyGrid.
|
|---|
| 5309 |
|
|---|
| 5310 | 4. Import the NumpyGrid into the desired output DatasetCollection.
|
|---|
| 5311 | """))
|
|---|
| 5312 |
|
|---|
| 5313 | # Constructor: NumpyGrid.__init__
|
|---|
| 5314 |
|
|---|
| 5315 | AddMethodMetadata(NumpyGrid.__init__,
|
|---|
| 5316 | shortDescription=_(u'NumpyGrid constructor.'),
|
|---|
| 5317 | dependencies=[PythonAggregatedModuleDependency('numpy')])
|
|---|
| 5318 |
|
|---|
| 5319 | AddArgumentMetadata(NumpyGrid.__init__, u'self',
|
|---|
| 5320 | typeMetadata=ClassInstanceTypeMetadata(cls=NumpyGrid),
|
|---|
| 5321 | description=_(u'%s instance.') % NumpyGrid.__name__)
|
|---|
| 5322 |
|
|---|
| 5323 | AddArgumentMetadata(NumpyGrid.__init__, u'numpyArray',
|
|---|
| 5324 | typeMetadata=NumPyArrayTypeMetadata(allowedDTypes=[u'int8', u'uint8', u'int16', u'uint16', u'int32', u'uint32', u'float32', u'float64']),
|
|---|
| 5325 | description=_(u'TODO: Add description'))
|
|---|
| 5326 |
|
|---|
| 5327 | AddArgumentMetadata(NumpyGrid.__init__, u'displayName',
|
|---|
| 5328 | typeMetadata=UnicodeStringTypeMetadata(),
|
|---|
| 5329 | description=_(u'TODO: Add description'))
|
|---|
| 5330 |
|
|---|
| 5331 | AddArgumentMetadata(NumpyGrid.__init__, u'spatialReference',
|
|---|
| 5332 | typeMetadata=AnyObjectTypeMetadata(),
|
|---|
| 5333 | description=_(u'TODO: Add description'))
|
|---|
| 5334 |
|
|---|
| 5335 | AddArgumentMetadata(NumpyGrid.__init__, u'dimensions',
|
|---|
| 5336 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'yx', u'zyx', u'tyx', u'tzyx']),
|
|---|
| 5337 | description=_(u'TODO: Add description'))
|
|---|
| 5338 |
|
|---|
| 5339 | AddArgumentMetadata(NumpyGrid.__init__, u'coordIncrements',
|
|---|
| 5340 | typeMetadata=TupleTypeMetadata(elementType=FloatTypeMetadata(mustBeGreaterThan=0., canBeNone=True), mustBeSameLengthAsArgument=u'dimensions'),
|
|---|
| 5341 | description=_(u'TODO: Add description'))
|
|---|
| 5342 |
|
|---|
| 5343 | AddArgumentMetadata(NumpyGrid.__init__, u'cornerCoords',
|
|---|
| 5344 | typeMetadata=TupleTypeMetadata(elementType=FloatTypeMetadata(), mustBeSameLengthAsArgument=u'dimensions'),
|
|---|
| 5345 | description=_(u'TODO: Add description'))
|
|---|
| 5346 |
|
|---|
| 5347 | AddArgumentMetadata(NumpyGrid.__init__, u'unscaledNoDataValue',
|
|---|
| 5348 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 5349 | description=_(u'TODO: Add description'))
|
|---|
| 5350 |
|
|---|
| 5351 | AddArgumentMetadata(NumpyGrid.__init__, u'tIncrementUnit',
|
|---|
| 5352 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'second', u'minute', u'hour', u'day', u'month', u'year'], canBeNone=True),
|
|---|
| 5353 | description=_(u'TODO: Add description'))
|
|---|
| 5354 |
|
|---|
| 5355 | AddArgumentMetadata(NumpyGrid.__init__, u'tSemiRegularity',
|
|---|
| 5356 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'annual'], canBeNone=True),
|
|---|
| 5357 | description=_(u'TODO: Add description'))
|
|---|
| 5358 |
|
|---|
| 5359 | AddArgumentMetadata(NumpyGrid.__init__, u'tCountPerSemiRegularPeriod',
|
|---|
| 5360 | typeMetadata=IntegerTypeMetadata(mustBeGreaterThan=0, canBeNone=True),
|
|---|
| 5361 | description=_(u'TODO: Add description'))
|
|---|
| 5362 |
|
|---|
| 5363 | AddArgumentMetadata(NumpyGrid.__init__, u'tCornerCoordType',
|
|---|
| 5364 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'min', u'center', u'max'], canBeNone=True),
|
|---|
| 5365 | description=_(u'TODO: Add description'))
|
|---|
| 5366 |
|
|---|
| 5367 | AddArgumentMetadata(NumpyGrid.__init__, u'tOffsetFromParsedTime',
|
|---|
| 5368 | typeMetadata=FloatTypeMetadata(canBeNone=True),
|
|---|
| 5369 | description=_(u'TODO: Add description'))
|
|---|
| 5370 |
|
|---|
| 5371 | AddArgumentMetadata(NumpyGrid.__init__, u'coordDependencies',
|
|---|
| 5372 | typeMetadata=TupleTypeMetadata(elementType=UnicodeStringTypeMetadata(allowedValues=[u'x', u'y', u'z', u't', u'yx', u'zx', u'tx', u'ty', u'zy', u'tz', u'zyx', u'tyx', u'tzy'], canBeNone=True), mustBeSameLengthAsArgument=u'dimensions', canBeNone=True),
|
|---|
| 5373 | description=_(u'TODO: Add description'))
|
|---|
| 5374 |
|
|---|
| 5375 | AddArgumentMetadata(NumpyGrid.__init__, u'physicalDimensions',
|
|---|
| 5376 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'yx', u'xy', u'zyx', u'zxy', u'yzx', u'yxz', u'xzy', u'xyz', u'tyx', u'txy', u'ytx', u'yxt', u'xty', u'xyt', u'tzyx', u'tzxy', u'tyzx', u'tyxz', u'txzy', u'txyz', u'ztyx', u'ztxy', u'zytx', u'zyxt', u'zxty', u'zxyt', u'ytzx', u'ytxz', u'yztx', u'yzxt', u'yxtz', u'yxzt', u'xtzy', u'xtyz', u'xzty', u'xzyt', u'xytz', u'xyzt'], canBeNone=True),
|
|---|
| 5377 | description=_(u'TODO: Add description'))
|
|---|
| 5378 |
|
|---|
| 5379 | AddArgumentMetadata(NumpyGrid.__init__, u'physicalDimensionsFlipped',
|
|---|
| 5380 | typeMetadata=TupleTypeMetadata(elementType=BooleanTypeMetadata(), mustBeSameLengthAsArgument=u'dimensions', canBeNone=True),
|
|---|
| 5381 | description=_(u'TODO: Add description'))
|
|---|
| 5382 |
|
|---|
| 5383 | AddArgumentMetadata(NumpyGrid.__init__, u'scaledDataType',
|
|---|
| 5384 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'int8', u'uint8', u'int16', u'uint16', u'int32', u'uint32', u'float32', u'float64'], canBeNone=True),
|
|---|
| 5385 | description=_(u'TODO: Add description'))
|
|---|
| 5386 |
|
|---|
| 5387 | AddArgumentMetadata(NumpyGrid.__init__, u'scaledNoDataValue',
|
|---|
| 5388 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 5389 | description=_(u'TODO: Add description'))
|
|---|
| 5390 |
|
|---|
| 5391 | AddArgumentMetadata(NumpyGrid.__init__, u'scalingFunction',
|
|---|
| 5392 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 5393 | description=_(u'TODO: Add description'))
|
|---|
| 5394 |
|
|---|
| 5395 | AddArgumentMetadata(NumpyGrid.__init__, u'unscalingFunction',
|
|---|
| 5396 | typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
|
|---|
| 5397 | description=_(u'TODO: Add description'))
|
|---|
| 5398 |
|
|---|
| 5399 | CopyArgumentMetadata(Grid.__init__, u'parentCollection', NumpyGrid.__init__, u'parentCollection')
|
|---|
| 5400 | CopyArgumentMetadata(Grid.__init__, u'queryableAttributes', NumpyGrid.__init__, u'queryableAttributes')
|
|---|
| 5401 | CopyArgumentMetadata(Grid.__init__, u'queryableAttributeValues', NumpyGrid.__init__, u'queryableAttributeValues')
|
|---|
| 5402 | CopyArgumentMetadata(Grid.__init__, u'lazyPropertyValues', NumpyGrid.__init__, u'lazyPropertyValues')
|
|---|
| 5403 |
|
|---|
| 5404 | AddResultMetadata(NumpyGrid.__init__, u'numpyGrid',
|
|---|
| 5405 | typeMetadata=ClassInstanceTypeMetadata(cls=NumpyGrid),
|
|---|
| 5406 | description=_(u'%s instance.') % NumpyGrid.__name__)
|
|---|
| 5407 |
|
|---|
| 5408 | # Public method: NumpyGrid.CreateFromGrid
|
|---|
| 5409 |
|
|---|
| 5410 | AddMethodMetadata(NumpyGrid.CreateFromGrid,
|
|---|
| 5411 | shortDescription=_(u'Reads an entire Grid into a numpy array and wraps it in a NumpyGrid instance.'),
|
|---|
| 5412 | dependencies=[PythonAggregatedModuleDependency('numpy')])
|
|---|
| 5413 |
|
|---|
| 5414 | AddArgumentMetadata(NumpyGrid.CreateFromGrid, u'cls',
|
|---|
| 5415 | typeMetadata=ClassOrClassInstanceTypeMetadata(cls=NumpyGrid),
|
|---|
| 5416 | description=_(u'%s class or an instance of it.') % NumpyGrid.__name__)
|
|---|
| 5417 |
|
|---|
| 5418 | AddArgumentMetadata(NumpyGrid.CreateFromGrid, u'grid',
|
|---|
| 5419 | typeMetadata=ClassInstanceTypeMetadata(cls=Grid),
|
|---|
| 5420 | description=_(
|
|---|
| 5421 | u"""Grid instance to read."""))
|
|---|
| 5422 |
|
|---|
| 5423 | AddResultMetadata(NumpyGrid.CreateFromGrid, u'numpyGrid',
|
|---|
| 5424 | typeMetadata=ClassInstanceTypeMetadata(cls=NumpyGrid),
|
|---|
| 5425 | description=_(u'%s instance.') % NumpyGrid.__name__)
|
|---|
| 5426 |
|
|---|
| 5427 |
|
|---|
| 5428 | ###############################################################################
|
|---|
| 5429 | # Names exported by this module
|
|---|
| 5430 | ###############################################################################
|
|---|
| 5431 |
|
|---|
| 5432 | __all__ = ['Dataset', 'Table', 'Field', 'SelectCursor', 'UpdateCursor', 'InsertCursor', 'Grid', 'NumpyGrid']
|
|---|