Changeset 903
- Timestamp:
- 01/25/12 17:57:40 (16 months ago)
- Location:
- MGET/Branches/Jason/PythonPackage/src/GeoEco
- Files:
-
- 3 added
- 7 modified
-
AggregatedModules/pyspatialite/dbapi2.py (modified) (1 diff)
-
DataProducts/OSU (added)
-
DataProducts/OSU/MesoscaleEddies.py (added)
-
DataProducts/OSU/__init__.py (added)
-
Datasets/ArcGIS.py (modified) (9 diffs)
-
Datasets/Collections.py (modified) (1 diff)
-
Datasets/SpatiaLite.py (modified) (31 diffs)
-
Datasets/Virtual.py (modified) (1 diff)
-
Datasets/__init__.py (modified) (13 diffs)
-
__init__.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
MGET/Branches/Jason/PythonPackage/src/GeoEco/AggregatedModules/pyspatialite/dbapi2.py
r894 r903 61 61 62 62 def convert_date(val): 63 return datetime.date(*map(int, val.split(" -")))63 return datetime.date(*map(int, val.split(" ")[0].split("-"))) 64 64 65 65 def convert_timestamp(val): -
MGET/Branches/Jason/PythonPackage/src/GeoEco/Datasets/ArcGIS.py
r895 r903 23 23 24 24 from GeoEco.ArcGIS import GeoprocessorManager 25 from GeoEco.Datasets import CollectibleObject, Dataset, DatasetCollection, QueryableAttribute, Grid, Table, Field, SelectCursor, UpdateCursor, InsertCursor25 from GeoEco.Datasets import CollectibleObject, Dataset, DatasetCollection, QueryableAttribute, Grid, Database, Table, Field, SelectCursor, UpdateCursor, InsertCursor 26 26 from GeoEco.Datasets.Collections import DatasetCollectionTree 27 27 from GeoEco.Datasets.GDAL import GDALDataset, GDALRasterBand … … 377 377 378 378 379 class ArcGISWorkspace(DatasetCollectionTree ):379 class ArcGISWorkspace(DatasetCollectionTree, Database): 380 380 __doc__ = DynamicDocString() 381 381 … … 435 435 def _GetDisplayName(self): 436 436 return self._DisplayName 437 438 @classmethod 439 def _TestCapability(cls, capability): 440 if capability in ['createtable', 'deletetable']: 441 return None 442 443 capList = capability.split(' ', 2) 444 if len(capList) == 3 and capList[0] == 'geometrytype': 445 if capList[1] in ['point', 'point25d', 'linestring', 'linestring25d', 'polygon', 'polygon25d', 'multipoint', 'multipoint25d', 'multilinestring', 'multilinestring25d', 'multipolygon', 'multipolygon25d']: 446 return None 447 return RuntimeError(_(u'Cannot create table %(table)s with "%(geom)s" geometry in %(dn)s. ArcGIS does not support that geometry type.') % {u'tableName': capList[2], u'geom': capList[1], u'dn': cls._DisplayName}) 448 449 if isinstance(cls, ArcGISWorkspace): 450 return RuntimeError(_(u'The %(cls)s class does not support the "%(cap)s" capability.') % {u'cls': cls.__class__.__name__, u'cap': capability}) 451 return RuntimeError(_(u'The %(cls)s class does not support the "%(cap)s" capability.') % {u'cls': cls.__name__, u'cap': capability}) 437 452 438 453 def _ListContents(self, pathComponents): … … 601 616 def _ImportDatasetsToPath(self, pathComponents, sourceDatasets, mode, progressReporter, options): 602 617 self.DatasetType._ImportDatasetsToPath(os.path.join(self.Path, *pathComponents), sourceDatasets, mode, progressReporter, options) 618 619 # Overridden methods of Database 620 621 def ImportTable(self, destTableName, sourceTable, fields=None, where=None, orderBy=None, rowCount=None, reportProgress=True, rowDescriptionSingular=None, rowDescriptionPlural=None, copiedOIDFieldName=None, allowSafeCoercions=True): 622 623 # First call the base class method to actually do the import. 624 625 table = super(ArcGISWorkspace, self).ImportTable(destTableName, sourceTable, fields, where, orderBy, rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural, copiedOIDFieldName, allowSafeCoercions) 626 627 # Now, if the resulting table has a geometry column, check 628 # whether it has a spatial index. If not, create one. We do 629 # this specifically because I have noticed that sometimes for 630 # shapefiles, ArcGIS appears to discard the spatial index that 631 # was requested in the call to CreateFeatureClass_management. 632 # I have not determined whether it is caused by subsequently 633 # adding fields, by adding records, or what. 634 635 if table.GeometryType is not None: 636 gp = GeoprocessorManager.GetWrappedGeoprocessor() 637 d = gp.Describe(table._GetFullPath()) 638 639 if hasattr(d, 'HasSpatialIndex') and not d.HasSpatialIndex: 640 if reportProgress: 641 self._LogInfo(_(u'Adding a spatial index to %(dn)s.') % {u'dn': table.DisplayName}) 642 else: 643 self._LogDebug(_(u'Adding a spatial index to %(dn)s.') % {u'dn': table.DisplayName}) 644 645 gp.AddSpatialIndex(table._GetFullPath(), 0, 0, 0) 646 647 # Return successfully. 648 649 return table 650 651 def _TableExists(self, tableName): 652 gp = GeoprocessorManager.GetWrappedGeoprocessor() 653 return gp.Exists(os.path.join(self._Path, tableName)) 654 655 def _CreateTable(self, tableName, geometryType, spatialReference, geometryFieldName): 656 657 # If the caller did not specify a geometryType, create a 658 # regular table. 659 660 gp = GeoprocessorManager.GetWrappedGeoprocessor() 661 if geometryType is None: 662 gp.CreateTable_management(self._Path, tableName) 663 664 # Otherwise create a feature class. 665 666 else: 667 geometryType = geometryType.upper() 668 669 hasZ = {False: 'DISABLED', True: 'ENABLED'}[geometryType[-3:] == u'25D'] 670 671 if geometryType in [u'POINT', u'POINT25D']: 672 geometryType = u'POINT' 673 elif geometryType in [u'MULTIPOINT', u'MULTIPOINT25D']: 674 geometryType = u'MULTIPOINT' 675 elif geometryType in [u'LINESTRING', u'MULTILINESTRING', u'LINESTRING25D', u'MULTILINESTRING25D']: 676 geometryType = u'POLYLINE' 677 elif geometryType in [u'POLYGON', u'MULTIPOLYGON', u'POLYGON25D', u'MULTIPOLYGON25D']: 678 geometryType = u'POLYGON' 679 680 srString = Dataset.ConvertSpatialReference('Obj', spatialReference, 'ArcGIS') 681 682 gp.CreateFeatureClass_management(self._Path, tableName, geometryType, None, 'DISABLED', hasZ, srString, None, 0, 0, 0) 683 684 # Return an ArcGISTable instance for the new table. 685 686 return ArcGISTable(os.path.join(self._Path, tableName)) 687 688 def _DeleteTable(self, tableName): 689 gp = GeoprocessorManager.GetWrappedGeoprocessor() 690 return gp.Delete_management(os.path.join(self._Path, tableName)) 603 691 604 692 … … 1535 1623 1536 1624 1537 class ArcGISTable(Table ):1625 class ArcGISTable(Table, ArcGISCopyableTable): 1538 1626 __doc__ = DynamicDocString() 1539 1627 … … 1792 1880 GeoprocessorManager.GetWrappedGeoprocessor().DefineProjection_management(self._GetFullPath(), sr) 1793 1881 1882 def GetArcGISCopyablePath(self): 1883 return self._GetFullPath() 1884 1794 1885 def _AddField(self, name, dataType, length, precision, isNullable): 1795 1886 if dataType == 'int16': … … 1866 1957 raise ValueError(_(u'Cannot import %(count)i datasets into ArcGIS table or feature class "%(path)s". Importing of multiple datasets into a single table or feature class is not currently supported. If you are receiving this error from a tool that has a parameter that is a list of expressions that define the output dataset namen, you may have made a mistake in your expressions that caused the same output dataset name to be generated for multiple input datasets. If that is the problem, you can fix it by modifying the expressions to generate a unique output dataset name for each input dataset.') % {u'count': len(sourceDatasets), u'path': path}) 1867 1958 1868 # Validate that the source dataset is importable.1869 #1870 # TODO: Implement support for Table instances that are not1871 # ArcGISCopyableTable instances. (That is a lot of work1872 # because we have to create the destination table and its1873 # fields and then copy each row one at a time.)1874 1875 if not isinstance(sourceDatasets[0], ArcGISCopyableTable):1876 raise TypeError(_(u'Cannot import %(dn)s into ArcGIS table or feature class "%(path)s" because it is a %(type)s, which is not an ArcGISCopyableTable. At this time, only ArcGISCopyableTable can be imported.') % {u'dn': sourceDatasets[0].DisplayName, u'path': path, u'type': dataset.__class__.__name__})1877 1878 1959 # If the mode is 'replace' and the destination dataset exists, 1879 1960 # delete it. … … 1965 2046 raise NotImplementedError(_(u'Cannot import %(dn)s into destination ArcGIS table or feature class "%(path)s" because that destination is not a folder, personal geodatabase, or file geodatabase. Other destinations (e.g. ArcSDE geodatabases) are not fully supported. Please contact the author of this tool for assistance.') % {u'dn': sourceDatasets[0].DisplayName, u'path': path}) 1966 2047 1967 # Import the dataset. 2048 # At this point, the parent workspace of the destination 2049 # dataset exists, and the destination dataset does not exist. 2050 # If the source dataset is copyable with ArcGIS's 2051 # Copy_management tool, use it because it will be much faster 2052 # than manually copying each row. 1968 2053 1969 2054 if isinstance(sourceDatasets[0], ArcGISCopyableTable): … … 1974 2059 finally: 1975 2060 sourceDatasets[0].Close() # This will make sure it deletes temporary files, if it had to create any in order to make itself ArcGIS-copyable. 2061 2062 # Otherwise copy the rows manually. This will work with any 2063 # Table instance. 2064 2065 else: 2066 workspace = ArcGISWorkspace(os.path.dirname(path), ArcGISTable, pathParsingExpressions=[r'(?P<TableName>.+)'], queryableAttributes=(QueryableAttribute(u'TableName', _(u'Table name'), UnicodeStringTypeMetadata()),)) 2067 workspace.ImportTable(os.path.basename(path), sourceDatasets[0], reportProgress=False) 2068 2069 # Report progress. 1976 2070 1977 if progressReporter is not None: 1978 progressReporter.ReportProgress() 1979 1980 else: 1981 raise TypeError(_(u'Cannot import %(dn)s into ArcGIS table or feature class "%(path)s" because it is a %(type)s, which is not an ArcGISCopyableTable. At this time, only ArcGISCopyableTable can be imported.') % {u'dn': sourceDatasets[0].DisplayName, u'path': path, u'type': dataset.__class__.__name__}) 2071 if progressReporter is not None: 2072 progressReporter.ReportProgress() 1982 2073 1983 2074 -
MGET/Branches/Jason/PythonPackage/src/GeoEco/Datasets/Collections.py
r836 r903 809 809 localPath = None 810 810 811 if localPath is not None and not os.path.splitext(localPath)[1]in [u'.bz2', u'.gz', u'.tar', u'.z', u'.zip'] and os.path.exists(localPath):811 if localPath is not None and os.path.splitext(localPath)[1] not in [u'.bz2', u'.gz', u'.tar', u'.z', u'.zip'] and os.path.exists(localPath): 812 812 return localPath, True 813 813 -
MGET/Branches/Jason/PythonPackage/src/GeoEco/Datasets/SpatiaLite.py
r897 r903 65 65 super(PySpatiaLiteDependency, self).Initialize() 66 66 67 # Log a message giving version numbers. 68 69 from GeoEco.Logging import Logger 70 from pyspatialite import dbapi2 as spatialite 71 72 conn = spatialite.connect(':memory:') 73 try: 74 row = conn.execute('SELECT sqlite_version(), spatialite_version();').fetchone() 75 Logger.Debug(_(u'Initialized SQLite version %(v1)s and SpatiaLite version %(v2)s.') % {u'v1': row[0], u'v2': row[1]}) 76 finally: 77 conn.close() 78 67 79 68 80 class SpatiaLiteDatabase(FileDatasetCollection, Database): 69 81 __doc__ = DynamicDocString() 82 83 def _GetConnection(self): 84 self._Open() 85 return self._Connection 86 87 Connection = property(_GetConnection, doc=DynamicDocString()) 70 88 71 89 def __init__(self, path, timeout=5., isolation_level=None, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES, decompressedFileToReturn=None, displayName=None, parentCollection=None, queryableAttributes=None, queryableAttributeValues=None, lazyPropertyValues=None, cacheDirectory=None): … … 162 180 163 181 self._Open() 164 tableNames = [row['name'] for row in self._Connection.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT IN ('spatial_ref_sys', 'spatialite_history', 'sqlite_sequence', 'geometry_columns', 'views_geometry_columns', 'virts_geometry_columns', 'geometry_columns_auth', 'SpatialIndex')")]182 tableNames = [row['name'] for row in self._Connection.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT GLOB 'idx_?*_?*' AND name NOT IN ('spatial_ref_sys', 'spatialite_history', 'sqlite_sequence', 'geometry_columns', 'views_geometry_columns', 'virts_geometry_columns', 'geometry_columns_auth', 'SpatialIndex')")] 165 183 datasetsFound = [] 166 184 … … 180 198 181 199 if result: 182 datasetsFound.append(SpatiaLiteTable(self, tableName [i]))200 datasetsFound.append(SpatiaLiteTable(self, tableNames[i])) 183 201 if progressReporter is not None: 184 202 progressReporter.ReportProgress() … … 192 210 return self._Connection.execute("SELECT COUNT(*) FROM sqlite_master WHERE name=?;", (tableName,)).fetchone()[0] > 0 193 211 194 def _CreateTable(self, tableName, geometryType =None, spatialReference=None, geometryFieldName=u'geometry'):212 def _CreateTable(self, tableName, geometryType, spatialReference, geometryFieldName): 195 213 196 214 # Create the table. The CREATE TABLE statement requires at … … 316 334 317 335 def _DeleteTable(self, tableName): 336 337 # Disable the SpatiaLite spatial index and geometry columns, 338 # if they exist. We have to do this explicitly first because 339 # the DROP TABLE statement does not accomplish it. 340 318 341 self._Open() 342 343 for row in self._Connection.execute("SELECT f_geometry_column, spatial_index_enabled FROM geometry_columns WHERE f_table_name = '%s';" % tableName): 344 if bool(row['spatial_index_enabled']): 345 sql = "SELECT DisableSpatialIndex('%s', '%s');" % (tableName, row['f_geometry_column']) 346 self._LogDebug(_(u'%(class)s 0x%(id)08X: Executing: %(sql)s'), {u'class': self.__class__.__name__, u'id': id(self), u'sql': sql}) 347 self._Connection.execute(sql) 348 349 sql = "DROP TABLE idx_%s_%s;" % (tableName, row['f_geometry_column']) 350 self._LogDebug(_(u'%(class)s 0x%(id)08X: Executing: %(sql)s'), {u'class': self.__class__.__name__, u'id': id(self), u'sql': sql}) 351 self._Connection.execute(sql) 352 353 sql = "SELECT DiscardGeometryColumn('%s', '%s');" % (tableName, row['f_geometry_column']) 354 self._LogDebug(_(u'%(class)s 0x%(id)08X: Executing: %(sql)s'), {u'class': self.__class__.__name__, u'id': id(self), u'sql': sql}) 355 self._Connection.execute(sql) 356 357 # Drop the table. 358 319 359 sql = "DROP TABLE %s;" % tableName 320 360 self._LogDebug(_(u'%(class)s 0x%(id)08X: Executing: %(sql)s'), {u'class': self.__class__.__name__, u'id': id(self), u'sql': sql}) … … 333 373 # downloaded and/or decompressed. 334 374 335 if self.Path == u':memory:' :375 if self.Path == u':memory:' or not os.path.exists(self.Path): 336 376 path = self.Path 337 377 isOriginalFile = True … … 364 404 365 405 if self.Path == u':memory:': 366 self._DisplayName = _(u'SpatiaLite in-memory database 0x%(id)08X') % {u'path': path, u'oldpath': self.Path, u'id': id(self._Connection)} 367 self._LogDebug(_(u'%(class)s 0x%(id)08X: Created new %(dn)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dn': self._DisplayName}) 406 if not self._CallerProvidedDisplayName: 407 self._DisplayName = _(u'SpatiaLite in-memory database 0x%(id)08X') % {u'id': id(self._Connection)} 408 self._LogDebug(_(u'%(class)s 0x%(id)08X: Created new %(dn)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'dn': self._DisplayName}) 409 else: 410 self._LogDebug(_(u'%(class)s 0x%(id)08X: Created new SpatiaLite in-memory database 0x%(id2)08X, hereafter referred to as "%(dn)s".'), {u'class': self.__class__.__name__, u'id': id(self), u'id2': id(self._Connection), u'dn': self._DisplayName}) 368 411 369 412 # If this database does not have a table named … … 387 430 ######################### TODO: All methods below here need to be checked ######################### 388 431 432 ## @classmethod 433 ## def _RemoveExistingDatasetsFromList(cls, path, datasets, progressReporter): 434 ## numDatasets = len(datasets) 435 ## 436 ## if path != ':memory:' and not os.path.exists(path): 437 ## cls._LogDebug(_(u'%(class)s: SpatiaLite database "%(path)s" does not exist.'), {u'class': cls.__name__, u'path': path}) 438 ## while len(datasets) > 0: 439 ## del datasets[0] 440 ## else: 441 ## from pyspatialite import dbapi2 as spatialite 442 ## 443 ## try: 444 ## conn = pyspatialite.connect(path) 445 ## except Exception, e: 446 ## raise RuntimeError(_(u'The file %(path)s exists but it could not be opened as a SpatiaLite database. Detailed error information: pyspatialite.connect failed with %(e)s: %(msg)s.') % {u'path': path, u'e': e.__class__.__name__, u'msg': self._Str(e)}) 447 ## 448 ## try: 449 ## i = 0 450 ## while i < len(datasets): 451 ## tableName = datasets[i].GetQueryableAttributeValue(u'TableName') 452 ## if tableName is None: 453 ## if path == ':memory:': 454 ## raise RuntimeError(_(u'Cannot import %(dn)s into a SpatiaLite in-memory database because that dataset does not have a value for the TableName queryable attribute. In order to import a dataset into a SpatiaLite database, the dataset must have a value for that queryable attribute.') % {u'dn': datasets[i].DisplayName}) 455 ## raise RuntimeError(_(u'Cannot import %(dn)s into SpatiaLite database %(path)s because that dataset does not have a value for the TableName queryable attribute. In order to import a dataset into a SpatiaLite database, the dataset must have a value for that queryable attribute.') % {u'dn': datasets[i].DisplayName, u'path': path}) 456 ## 457 ## if conn.execute("SELECT COUNT(*) FROM sqlite_master WHERE name=?;", (tableName,)).fetchone()[0] > 0: 458 ## if path != ':memory:': 459 ## cls._LogDebug(_(u'%(class)s: Table %(table)s exists in SpatiaLite database %(path)s.'), {u'class': cls.__name__, u'table': tableName, u'path': path}) 460 ## del datasets[i] 461 ## else: 462 ## i += 1 463 ## finally: 464 ## conn.close() 465 ## 466 ## if progressReporter is not None: 467 ## progressReporter.ReportProgress(numDatasets) 468 ## 469 ## @classmethod 470 ## def _ImportDatasetsToPath(cls, path, sourceDatasets, mode, progressReporter, options): 471 ## 472 ## # If path is not ":memory:" it is a file. If that file does 473 ## # not exist, create the parent directories, if they do not 474 ## # exist already. 475 ## 476 ## if path != ':memory:' and not os.path.isfile(path) and (path[0] in ['/', '\\'] or hasattr(os.path, 'splitdrive') and os.path.splitdrive(path)[0] != '' or hasattr(os.path, 'splitunc') and os.path.splitunc(path)[0] != '') and not os.path.isdir(os.path.dirname(path)): 477 ## cls._LogDebug(_(u'%(class)s: Creating directory "%(path)s".'), {u'class': cls.__name__, u'path': os.path.dirname(path)}) 478 ## try: 479 ## os.makedirs(os.path.dirname(path)) 480 ## except Exception, e: 481 ## raise RuntimeError(_(u'Failed to create directory "%(path)s". Python\'s os.makedirs function failed and reported %(e)s: %(msg)s') % {u'path': os.path.dirname(path), u'e': e.__class__.__name__, u'msg': cls._Unicode(e)}) 482 ## 483 ## # Open the SpatiaLite database. This will create it if it doesn't 484 ## # exist already. Then import each dataset into it. 485 ## 486 ## database = SpatiaLiteDatabase(path) 487 ## try: 488 ## for dataset in sourceDatasets: 489 ## cls._ImportTableToDatabase(dataset, database, mode, progressReporter) 490 ## finally: 491 ## db.Close() 492 ## 493 ## @classmethod 494 ## def _ImportTableToDatabase(cls, dataset, database, mode, progressReporter): 495 ## 496 ## # Perform additional validation. 497 ## 498 ## if not isinstance(dataset, Table): 499 ## raise ValueError(_(u'Cannot import %(dn1)s into %(dn2)s because the former is not a Table instance. Only Tables can be imported into SpatiaLite databases.') % {u'dn1': dataset.DisplayName, u'dn2': database.DisplayName}) 500 ## 501 ## tableName = dataset.GetQueryableAttributeValue(u'TableName') 502 ## if tableName is None: 503 ## raise RuntimeError(_(u'Cannot import %(dn1)s into %(dn2)s because the former does not have a value for the TableName queryable attribute. In order to import a dataset into a SpatiaLite database, the dataset must have a value for that queryable attribute.') % {u'dn1': dataset.DisplayName, u'dn2': database.DisplayName}) 504 ## 505 ## # If the table already exists and the mode is 'replace', 506 ## # delete it (otherwise raise an error). 507 ## 508 ## if database._Connection.execute("SELECT COUNT(*) FROM sqlite_master WHERE name=?;", (tableName,)).fetchone()[0] > 0: 509 ## if mode != u'replace': 510 ## raise RuntimeError(_(u'Cannot import %(dn1)s into %(dn2)s because that database already has a table named %(table)s.') % {u'dn1': dataset.DisplayName, u'dn2': database.DisplayName, u'table': tableName}) 511 ## 512 ## cls._LogDebug(_(u'%(class)s: Deleting existing table %(table)s from %(dn)s.'), {u'class': cls.__name__, u'table': tableName, u'dn': database.DisplayName}) 513 ## try: 514 ## database._Connection.execute("DROP TABLE %s;" % tableName) 515 ## except Exception, e: 516 ## raise RuntimeError(_(u'Failed to delete existing table %(table)s from %(dn)s. SpatiaLite reported %(e)s: %(msg)s') % {u'table': tableName, u'dn': database.DisplayName, u'e': e.__class__.__name__, u'msg': cls._Unicode(e)}) 517 ## 518 ## # Create the table. 519 ## 520 ## if dataset.GeometryType is not None: 521 ## self._LogWarning(_(u'When %(dn1)s is imported to %(dn2)s as table %(table)s, the geometry field will be lost because SpatiaLite does not support geometry ')) 522 523 ######################### TODO: All methods above here need to be checked ######################### 524 389 525 @classmethod 390 def _RemoveExistingDatasetsFromList(cls, path, datasets, progressReporter): 391 numDatasets = len(datasets) 392 393 if path != ':memory:' and not os.path.exists(path): 394 cls._LogDebug(_(u'%(class)s: SpatiaLite database "%(path)s" does not exist.'), {u'class': cls.__name__, u'path': path}) 395 while len(datasets) > 0: 396 del datasets[0] 526 def ExportToArcGISWorkspace(cls, spatiaLiteDB, arcGISWorkspace, tableNames=None, skipExisting=False, overwriteExisting=False): 527 cls.__doc__.Obj.ValidateMethodInvocation() 528 529 # Create the ArcGIS workspace, if it does not exist already. 530 # The validation code above should have already created the 531 # parent directories, if they did not exist. 532 533 from GeoEco.ArcGIS import GeoprocessorManager, ArcGISDependency 534 gp = GeoprocessorManager.GetWrappedGeoprocessor() 535 outputTypeSingular = _(u'feature class') 536 outputTypePlural = _(u'feature classes') 537 538 if not gp.Exists(arcGISWorkspace): 539 if os.path.splitext(arcGISWorkspace)[1].lower() == u'.mdb': 540 cls._LogInfo(_(u'Creating personal geodatabase %s.') % arcGISWorkspace) 541 gp.CreatePersonalGDB_management(os.path.dirname(arcGISWorkspace), os.path.basename(arcGISWorkspace)) 542 543 elif os.path.splitext(arcGISWorkspace)[1].lower() == u'.gdb': 544 cls._LogInfo(_(u'Creating file geodatabase %s.') % arcGISWorkspace) 545 d = ArcGISDependency(9,2) 546 d.Initialize() 547 gp.CreateFileGDB_management(os.path.dirname(arcGISWorkspace), os.path.basename(arcGISWorkspace)) 548 549 else: 550 cls._LogInfo(_(u'Creating directory %s.') % arcGISWorkspace) 551 gp.CreateFolder_management(os.path.dirname(arcGISWorkspace), os.path.basename(arcGISWorkspace)) 552 outputTypeSingular = _(u'shapefile') 553 outputTypePlural = _(u'shapefiles') 554 555 elif os.path.isdir(arcGISWorkspace) and os.path.splitext(arcGISWorkspace)[1].lower() != '.gdb': 556 outputTypeSingular = _(u'shapefile') 557 outputTypePlural = _(u'shapefiles') 558 559 # Enumerate the SpatiaLite tables we will copy, and if the 560 # caller has requested that we skip existing outputs or not 561 # overwrite them, check whether they exist. 562 563 from GeoEco.Datasets.ArcGIS import ArcGISWorkspace, ArcGISTable 564 565 db = SpatiaLiteDatabase(spatiaLiteDB) 566 workspace = ArcGISWorkspace(arcGISWorkspace, ArcGISTable, pathParsingExpressions=[u'(?P<TableName>.+)'], queryableAttributes=(QueryableAttribute(u'TableName', _(u'Table name'), UnicodeStringTypeMetadata()),)) 567 568 if tableNames is None: 569 tables = db.QueryDatasets(reportProgress=False) 397 570 else: 398 from pyspatialite import dbapi2 as spatialite 399 400 try: 401 conn = pyspatialite.connect(path) 402 except Exception, e: 403 raise RuntimeError(_(u'The file %(path)s exists but it could not be opened as a SpatiaLite database. Detailed error information: pyspatialite.connect failed with %(e)s: %(msg)s.') % {u'path': path, u'e': e.__class__.__name__, u'msg': self._Str(e)}) 404 405 try: 406 i = 0 407 while i < len(datasets): 408 tableName = datasets[i].GetQueryableAttributeValue(u'TableName') 409 if tableName is None: 410 if path == ':memory:': 411 raise RuntimeError(_(u'Cannot import %(dn)s into a SpatiaLite in-memory database because that dataset does not have a value for the TableName queryable attribute. In order to import a dataset into a SpatiaLite database, the dataset must have a value for that queryable attribute.') % {u'dn': datasets[i].DisplayName}) 412 raise RuntimeError(_(u'Cannot import %(dn)s into SpatiaLite database %(path)s because that dataset does not have a value for the TableName queryable attribute. In order to import a dataset into a SpatiaLite database, the dataset must have a value for that queryable attribute.') % {u'dn': datasets[i].DisplayName, u'path': path}) 571 tables = db.QueryDatasets(expression='TableName IN (%s)' % ', '.join(["'" + name.replace("'", "''") + "'" for name in tableNames]), reportProgress=False) 572 573 if len(tables) <= 0: 574 if tableNames is None: 575 cls._LogInfo(_(u'There are no tables in %(spatiaLiteDB)s to copy.') % {u'spatiaLiteDB': db.DisplayName}) 576 else: 577 cls._LogInfo(_(u'None of the requested tables exist in %(spatiaLiteDB)s.') % {u'spatiaLiteDB': db.DisplayName}) 578 return 579 580 outputTableNames = [] 581 for table in tables: 582 tableName = table.GetQueryableAttributeValue(u'TableName') 583 if outputTypeSingular == _(u'shapefile'): 584 if table.GeometryType is not None: 585 outputTableNames.append(tableName + '.shp') 586 else: 587 outputTableNames.append(tableName + '.dbf') 588 else: 589 outputTableNames.append(tableName) 590 591 numSkipped = 0 592 if skipExisting or not overwriteExisting: 593 cls._LogInfo(_(u'Checking %(arcGISWorkspace)s for existing tables and %(outputTypePlural)s...') % {u'arcGISWorkspace': arcGISWorkspace, u'outputTypePlural': outputTypePlural}) 594 i = 0 595 while i < len(tables): 596 if gp.Exists(os.path.join(arcGISWorkspace, outputTableNames[i])): 597 if not overwriteExisting: 598 raise ValueError(_(u'Cannot copy %(input)s to %(outputTypeSingular)s %(output)s. The %(outputTypeSingular)s already exists.') % {u'input': table.DisplayName, u'outputTypeSingular': outputTypeSingular, u'output': os.path.join(arcGISWorkspace, outputTableNames[i])}) 599 600 cls._LogDebug(_(u'Skipping %(input)s; the %(outputTypeSingular)s %(output)s already exists.') % {u'input': table.DisplayName, u'outputTypeSingular': outputTypeSingular, u'output': os.path.join(arcGISWorkspace, outputTableNames[i])}) 413 601 414 if conn.execute("SELECT COUNT(*) FROM sqlite_master WHERE name=?;", (tableName,)).fetchone()[0] > 0: 415 if path != ':memory:': 416 cls._LogDebug(_(u'%(class)s: Table %(table)s exists in SpatiaLite database %(path)s.'), {u'class': cls.__name__, u'table': tableName, u'path': path}) 417 del datasets[i] 418 else: 419 i += 1 420 finally: 421 conn.close() 422 423 if progressReporter is not None: 424 progressReporter.ReportProgress(numDatasets) 602 del tables[i] 603 del outputTableNames [i] 604 numSkipped += 1 605 else: 606 i += 1 607 608 if numSkipped > 0: 609 if len(tables) <= 0: 610 cls._LogInfo(_(u'Skipping all %(numSkipped)i tables in %(spatiaLiteDB)s. All of the corresponding tables and %(outputTypePlural)s already exist.') % {u'numSkipped': numSkipped, u'spatiaLiteDB': db.DisplayName, u'outputTypePlural': outputTypePlural}) 611 return 612 else: 613 cls._LogInfo(_(u'Skipping %(numSkipped)i tables in %(spatiaLiteDB)s because the corresponding tables and %(outputTypePlural)s already exist.') % {u'numSkipped': numSkipped, u'spatiaLiteDB': db.DisplayName, u'outputTypePlural': outputTypePlural}) 614 615 # Copy the tables. 616 617 cls._LogInfo(_(u'Copying %(num)i tables from %(spatiaLiteDB)s to %(arcGISWorkspace)s.') % {u'num': len(tables), u'spatiaLiteDB': db.DisplayName, u'arcGISWorkspace': arcGISWorkspace}) 618 619 for i in range(len(tables)): 620 if overwriteExisting and workspace.TableExists(outputTableNames[i]): 621 workspace.DeleteTable(outputTableNames[i]) 622 workspace.ImportTable(outputTableNames[i], tables[i]) 623 624 # Explicitly add a spatial index. 625 # CreateFeatureClass_management is supposed to do that 626 # automatically if you pass 0, 0, 0 for the Spatial Grid 627 # parameters, but that does not seem to work, at least for 628 # shapfiles on ArcGIS 10 SP2. 629 630 #gp.AddSpatialIndex_Management(os.path.join(arcGISWorkspace, outputTableNames[i]), 0, 0, 0) 631 632 # Return successfully. 633 634 return arcGISWorkspace 425 635 426 636 @classmethod 427 def _ImportDatasetsToPath(cls, path, sourceDatasets, mode, progressReporter, options): 428 429 # If path is not ":memory:" it is a file. If that file does 430 # not exist, create the parent directories, if they do not 431 # exist already. 432 433 if path != ':memory:' and not os.path.isfile(path) and (path[0] in ['/', '\\'] or hasattr(os.path, 'splitdrive') and os.path.splitdrive(path)[0] != '' or hasattr(os.path, 'splitunc') and os.path.splitunc(path)[0] != '') and not os.path.isdir(os.path.dirname(path)): 434 cls._LogDebug(_(u'%(class)s: Creating directory "%(path)s".'), {u'class': cls.__name__, u'path': os.path.dirname(path)}) 435 try: 436 os.makedirs(os.path.dirname(path)) 437 except Exception, e: 438 raise RuntimeError(_(u'Failed to create directory "%(path)s". Python\'s os.makedirs function failed and reported %(e)s: %(msg)s') % {u'path': os.path.dirname(path), u'e': e.__class__.__name__, u'msg': cls._Unicode(e)}) 439 440 # Open the SpatiaLite database. This will create it if it doesn't 441 # exist already. Then import each dataset into it. 442 443 database = SpatiaLiteDatabase(path) 444 try: 445 for dataset in sourceDatasets: 446 cls._ImportTableToDatabase(dataset, database, mode, progressReporter) 447 finally: 448 db.Close() 449 450 @classmethod 451 def _ImportTableToDatabase(cls, dataset, database, mode, progressReporter): 452 453 # Perform additional validation. 454 455 if not isinstance(dataset, Table): 456 raise ValueError(_(u'Cannot import %(dn1)s into %(dn2)s because the former is not a Table instance. Only Tables can be imported into SpatiaLite databases.') % {u'dn1': dataset.DisplayName, u'dn2': database.DisplayName}) 457 458 tableName = dataset.GetQueryableAttributeValue(u'TableName') 459 if tableName is None: 460 raise RuntimeError(_(u'Cannot import %(dn1)s into %(dn2)s because the former does not have a value for the TableName queryable attribute. In order to import a dataset into a SpatiaLite database, the dataset must have a value for that queryable attribute.') % {u'dn1': dataset.DisplayName, u'dn2': database.DisplayName}) 461 462 # If the table already exists and the mode is 'replace', 463 # delete it (otherwise raise an error). 464 465 if database._Connection.execute("SELECT COUNT(*) FROM sqlite_master WHERE name=?;", (tableName,)).fetchone()[0] > 0: 466 if mode != u'replace': 467 raise RuntimeError(_(u'Cannot import %(dn1)s into %(dn2)s because that database already has a table named %(table)s.') % {u'dn1': dataset.DisplayName, u'dn2': database.DisplayName, u'table': tableName}) 468 469 cls._LogDebug(_(u'%(class)s: Deleting existing table %(table)s from %(dn)s.'), {u'class': cls.__name__, u'table': tableName, u'dn': database.DisplayName}) 470 try: 471 database._Connection.execute("DROP TABLE %s;" % tableName) 472 except Exception, e: 473 raise RuntimeError(_(u'Failed to delete existing table %(table)s from %(dn)s. SpatiaLite reported %(e)s: %(msg)s') % {u'table': tableName, u'dn': database.DisplayName, u'e': e.__class__.__name__, u'msg': cls._Unicode(e)}) 474 475 # Create the table. 476 477 if dataset.GeometryType is not None: 478 self._LogWarning(_(u'When %(dn1)s is imported to %(dn2)s as table %(table)s, the geometry field will be lost because SpatiaLite does not support geometry ')) 637 def ImportFromArcGISWorkspace(cls, arcGISWorkspace, spatiaLiteDB, tableNames=None, skipExisting=False, overwriteExisting=False): 638 cls.__doc__.Obj.ValidateMethodInvocation() 639 640 # Create the SpatialLite database, if it does not exist 641 # already. The validation code above should have already 642 # created the parent directories, if they did not exist. 643 # Calling _Open creates the database if it does not exist 644 # already. 645 646 if not os.path.exists(spatiaLiteDB): 647 cls._LogInfo(_(u'Creating SpatiaLite database %s.') % spatiaLiteDB) 648 649 db = SpatiaLiteDatabase(spatiaLiteDB, isolation_level='DEFERRED') 650 db._Open() 651 652 # Enumerate the ArcGIS tables and features classes we will 653 # copy, and if the caller has requested that we skip existing 654 # outputs or not overwrite them, check whether they exist. 655 656 from GeoEco.Datasets.ArcGIS import ArcGISWorkspace, ArcGISTable 657 658 workspace = ArcGISWorkspace(arcGISWorkspace, ArcGISTable, pathParsingExpressions=[u'(?P<TableName>.+)'], queryableAttributes=(QueryableAttribute(u'TableName', _(u'Table name'), UnicodeStringTypeMetadata()),)) 659 660 if tableNames is None: 661 tables = workspace.QueryDatasets(reportProgress=False) 662 else: 663 tables = workspace.QueryDatasets(expression='TableName IN (%s)' % ', '.join(["'" + name.replace("'", "''") + "'" for name in tableNames]), reportProgress=False) 664 665 if os.path.isdir(arcGISWorkspace) and os.path.splitext(arcGISWorkspace)[1].lower() != '.gdb': 666 inputTypePlural = _(u'shapefiles') 667 else: 668 inputTypePlural = _(u'feature classes') 669 670 if len(tables) <= 0: 671 if tableNames is None: 672 cls._LogInfo(_(u'There are no tables or %(inputTypePlural)s in %(arcGISWorkspace)s to copy.') % {u'inputTypePlural': inputTypePlural, u'arcGISWorkspace': arcGISWorkspace}) 673 else: 674 cls._LogInfo(_(u'None of the requested tables or %(inputTypePlural)s exist in %(arcGISWorkspace)s.') % {u'inputTypePlural': inputTypePlural, u'arcGISWorkspace': arcGISWorkspace}) 675 return 676 677 outputTableNames = [] 678 for table in tables: 679 tableName = table.GetQueryableAttributeValue(u'TableName') 680 if inputTypePlural == _(u'shapefiles'): 681 outputTableNames.append(os.path.splitext(tableName)[0]) 682 else: 683 outputTableNames.append(tableName) 684 685 numSkipped = 0 686 if skipExisting or not overwriteExisting: 687 cls._LogInfo(_(u'Checking %(spatiaLiteDB)s for existing tables...') % {u'spatiaLiteDB': db.DisplayName}) 688 i = 0 689 while i < len(tables): 690 if db.TableExists(outputTableNames[i]): 691 if not overwriteExisting: 692 raise ValueError(_(u'Cannot copy %(input)s to table %(output)s in %(spatiaLiteDB)s. The SpatiaLite table already exists.') % {u'input': table.DisplayName, u'output': outputTableNames[i], u'spatiaLiteDB': db.DisplayName}) 693 694 cls._LogDebug(_(u'Skipping %(input)s; the table %(output)s already exists in %(spatiaLiteDB)s.') % {u'input': table.DisplayName, u'output': outputTableNames[i], u'spatiaLiteDB': db.DisplayName}) 695 696 del tables[i] 697 del outputTableNames [i] 698 numSkipped += 1 699 else: 700 i += 1 701 702 if numSkipped > 0: 703 if len(tables) <= 0: 704 cls._LogInfo(_(u'Skipping all %(numSkipped)i tables and %(inputTypePlural)s in %(arcGISWorkspace)s. All of the corresponding tables already exist.') % {u'numSkipped': numSkipped, u'inputTypePlural': inputTypePlural, u'arcGISWorkspace': arcGISWorkspace}) 705 return 706 else: 707 cls._LogInfo(_(u'Skipping %(numSkipped)i tables and %(inputTypePlural)s in %(arcGISWorkspace)s because the corresponding tables already exist.') % {u'numSkipped': numSkipped, u'inputTypePlural': inputTypePlural, u'arcGISWorkspace': arcGISWorkspace}) 708 709 # Copy the tables. 710 711 cls._LogInfo(_(u'Copying %(num)i tables and %(inputTypePlural)s from %(arcGISWorkspace)s to %(spatiaLiteDB)s.') % {u'num': len(tables), u'inputTypePlural': inputTypePlural, u'arcGISWorkspace': arcGISWorkspace, u'spatiaLiteDB': db.DisplayName}) 712 713 for i in range(len(tables)): 714 if overwriteExisting and db.TableExists(outputTableNames[i]): 715 db.DeleteTable(outputTableNames[i]) 716 db.ImportTable(outputTableNames[i], tables[i]) 479 717 480 718 … … 514 752 # If it is not a known lazy property, return None. 515 753 516 if name not in ['SpatialReference', 'HasOID', 'OIDFieldName', 'GeometryType', 'GeometryFieldName', ' Fields']:754 if name not in ['SpatialReference', 'HasOID', 'OIDFieldName', 'GeometryType', 'GeometryFieldName', 'SpatiaLiteSRID', 'Fields']: 517 755 return None 518 756 … … 569 807 570 808 if geometryType is not None: 571 wkt = self.ParentCollection._Connection.execute("SELECT srs_wkt FROM spatial_ref_sys WHERE srid IN (SELECT srid FROM geometry_columns WHERE f_table_name=? AND f_geometry_column=?);", (self._TableName, field.Name)).fetchone()[0] 809 self.SetLazyPropertyValue('SpatiaLiteSRID', self.ParentCollection._Connection.execute("SELECT srid FROM geometry_columns WHERE f_table_name=? AND f_geometry_column=?;", (self._TableName, geometryFieldName)).fetchone()[0]) 810 811 wkt = self.ParentCollection._Connection.execute("SELECT srs_wkt FROM spatial_ref_sys WHERE srid IN (SELECT srid FROM geometry_columns WHERE f_table_name=? AND f_geometry_column=?);", (self._TableName, geometryFieldName)).fetchone()[0] 572 812 if isinstance(wkt, basestring) and len(wkt) > 0: 573 813 self.SetLazyPropertyValue('SpatialReference', Dataset.ConvertSpatialReference('WKT', wkt, 'Obj')) … … 575 815 self.SetLazyPropertyValue('SpatialReference', None) 576 816 else: 817 self.SetLazyPropertyValue('SpatiaLiteSRID', None) 577 818 self.SetLazyPropertyValue('SpatialReference', None) 578 819 … … 633 874 @classmethod 634 875 def _TestCapability(cls, capability): 635 if capability in ['addfield', ' selectcursor', 'updatecursor', 'insertcursor', 'updaterow', 'deleterow']:876 if capability in ['addfield', 'createindex', 'deleteindex', 'selectcursor', 'updatecursor', 'insertcursor', 'updaterow', 'deleterow']: 636 877 return None 637 878 … … 686 927 return Field(name, dataType, None, None, isNullable, True) 687 928 929 def _CreateIndex(self, fields, indexName, unique, ascending): 930 931 # Make sure the caller specified an index name. 932 933 if indexName is None: 934 raise ValueError(_(u'The index name must be provided.')) 935 936 # Drop the existing index, if it exists. 937 938 self.ParentCollection._Open() 939 self.ParentCollection._Connection.execute("DROP INDEX IF EXISTS %s;" % (indexName)) 940 941 # Create the new index. 942 943 self.ParentCollection._Connection.execute("CREATE %s INDEX %s ON %s (%s);" % ({False: '', True: 'UNIQUE'}[unique], indexName, self._TableName, ', '.join([field + {False: ' DESC', True: ' ASC'}[ascending] for field in fields]))) 944 945 def _DeleteIndex(self, indexName): 946 947 # Make sure the caller specified an index name. 948 949 if indexName is None: 950 raise ValueError(_(u'The index name must be provided.')) 951 952 # Drop the existing index, if it exists. 953 954 self.ParentCollection._Open() 955 self.ParentCollection._Connection.execute("DROP INDEX IF EXISTS %s;" % (indexName)) 956 688 957 def _GetRowCount(self): 689 958 self.ParentCollection._Open() … … 712 981 def _GetValue(self, field): 713 982 if field not in self._RowValues: 714 self._RowValues[field] = self._Row[field] 983 value = self._Row[str(field)] 984 if isinstance(value, datetime.date): 985 value = datetime.datetime(value.year, value.month, value.day, 0, 0, 0) 986 self._RowValues[field] = value 715 987 return self._RowValues[field] 716 988 … … 720 992 def _GetGeometry(self): 721 993 if self._Table.GeometryFieldName not in self._RowValues: 722 geometry = self._Row[s elf._Table.GeometryFieldName + '_WKB']994 geometry = self._Row[str(self._Table.GeometryFieldName + '_WKB')] 723 995 if geometry is not None: 724 996 ogr = self._Table._ogr() … … 738 1010 if geometry is not None and geometry.IsEmpty(): 739 1011 geometry = None 1012 elif geometry.GetGeometryName() == 'POINT' and self._Table.GeometryType == 'MultiPoint': 1013 geometry = self._Table._ogr().ForceToMultiPoint(geometry) 1014 elif geometry.GetGeometryName() == 'LINESTRING' and self._Table.GeometryType == 'MultiLineString': 1015 geometry = self._Table._ogr().ForceToMultiLineString(geometry) 1016 elif geometry.GetGeometryName() == 'POLYGON' and self._Table.GeometryType == 'MultiPolygon': 1017 geometry = self._Table._ogr().ForceToMultiPolygon(geometry) 1018 740 1019 self._RowValues[self._Table.GeometryFieldName] = geometry 741 1020 self._SetFields.add(self._Table.GeometryFieldName) … … 759 1038 if fields is None: 760 1039 if self._Table.GeometryType is not None: 761 sql += 'SELECT *, ST_AsBinary(%(field)s) AS %(field)s_WKB ' % {'field': self._Table.GeometryFieldName}1040 sql = 'SELECT *, ST_AsBinary(%(field)s) AS %(field)s_WKB ' % {'field': self._Table.GeometryFieldName} 762 1041 else: 763 sql += 'SELECT *'1042 sql = 'SELECT *' 764 1043 else: 765 1044 if self._Table.GeometryType is not None and self._Table.GeometryFieldName in fields: … … 768 1047 fields[i] = 'ST_AsBinary(%(field)s) AS %(field)s_WKB' % {'field': self._Table.GeometryFieldName} 769 1048 break 770 sql += 'SELECT %s' % ', '.join(fields)1049 sql = 'SELECT %s' % ', '.join(fields) 771 1050 772 1051 sql += ' FROM %s' % self._Table.TableName … … 799 1078 def _Open(self, fields, where, orderBy): 800 1079 self._Cursor = None 1080 self._InTransaction = False 801 1081 self._Row = None 802 1082 self._RowValues = None 803 self._SetFields = set()1083 self._SetFields = None 804 1084 805 1085 # Build the SQL SELECT statement from the caller's parameters. … … 818 1098 if fields is None: 819 1099 if self._Table.GeometryType is not None: 820 sql += 'SELECT *, ST_AsBinary(%(field)s) AS %(field)s_WKB ' % {'field': self._Table.GeometryFieldName}1100 sql = 'SELECT *, ST_AsBinary(%(field)s) AS %(field)s_WKB ' % {'field': self._Table.GeometryFieldName} 821 1101 else: 822 sql += 'SELECT *'1102 sql = 'SELECT *' 823 1103 else: 824 1104 if self._Table.OIDFieldName not in fields: … … 831 1111 break 832 1112 833 sql += 'SELECT %s' % ', '.join(fields)1113 sql = 'SELECT %s' % ', '.join(fields) 834 1114 835 1115 sql += ' FROM %s' % self._Table.TableName … … 843 1123 # Open the cursor. 844 1124 845 self._Cursor = self._Table.ParentCollection._Connection.execute(sql) 1125 try: 1126 self._Cursor = self._Table.ParentCollection._Connection.execute(sql) 1127 except: 1128 self._Table.ParentCollection._Connection.rollback() 1129 self._InTransaction = False 1130 raise 1131 1132 self._InTransaction = True 846 1133 847 1134 def _Close(self): … … 850 1137 self._SetFields = None 851 1138 if hasattr(self, '_Cursor') and self._Cursor is not None: 1139 if self._InTransaction: 1140 try: 1141 self._Table.ParentCollection._Connection.commit() 1142 except: 1143 pass 852 1144 try: 853 1145 self._Cursor.close() … … 859 1151 def _UpdateRow(self): 860 1152 1153 # Fail if we are not in a transaction. The only way this can 1154 # happen is if an error occurred with a previous call to this 1155 # cursor. That will cause the transaction to be rolled back. 1156 # The cursor can no longer be used after that point. 1157 1158 if not self._InTransaction: 1159 raise RuntimeError(_(u'Due to the previous error, no more updates can be performed with this cursor. To perform updates, close this cursor and open a new one.')) 1160 861 1161 # Only execute the UPDATE statement some fields have been set. 862 1162 … … 866 1166 # instance that is currently in self._RowValues with a buffer 867 1167 # containing the WKB representation of it. 1168 # 1169 # Note that the Spatialite documentation contains the 1170 # note: 1171 # 1172 # both ST_GeomFromText() and ST_GeomFromWKB() accept 1173 # an optional SRID argument. If the SRID is 1174 # unspecified (not at all a good practice), then -1 is 1175 # assumed. 1176 # 1177 # It looks like if the SRID argument is not provided (and 1178 # -1 is presumably used) then INSERTs or UPDATEs of the 1179 # geometry column will consistently fail with: 1180 # 1181 # IntegrityError: ... violates Geometry constraint 1182 # [geom-type or SRID not allowed] 1183 # 1184 # To work around that, we always specify the SRID. 868 1185 869 1186 fieldsToSet = list(self._SetFields) … … 874 1191 for i in range(len(fieldsToSet)): 875 1192 if fieldsToSet[i] == self._Table.GeometryFieldName: 876 valueStrings[i] = 'ST_GeomFromWKB(?)' 1193 srid = self._Table.GetLazyPropertyValue('SpatiaLiteSRID') 1194 if srid is not None: 1195 valueStrings[i] = 'ST_GeomFromWKB(?, %i)' % srid 1196 else: 1197 valueStrings[i] = 'ST_GeomFromWKB(?)' 877 1198 break 878 1199 … … 883 1204 # Update the row. 884 1205 885 self._Table.ParentCollection._Connection.execute(sql, [self._RowValues[field] for field in fieldsToSet]) 1206 try: 1207 self._Table.ParentCollection._Connection.execute(sql, [self._RowValues[field] for field in fieldsToSet]) 1208 except: 1209 self._Table.ParentCollection._Connection.rollback() 1210 self._InTransaction = False 1211 raise 886 1212 887 1213 self._Row = None 888 1214 889 1215 def _DeleteRow(self): 890 self._Table.ParentCollection._Connection.execute('DELETE %s WHERE ObjectID = %s' % (self._Table.TableName, self._GetValue(self._Table.OIDFieldName))) 1216 if not self._InTransaction: 1217 raise RuntimeError(_(u'Due to the previous error, no more deletes can be performed with this cursor. To perform deletes, close this cursor and open a new one.')) 1218 try: 1219 self._Table.ParentCollection._Connection.execute('DELETE %s WHERE ObjectID = %s' % (self._Table.TableName, self._GetValue(self._Table.OIDFieldName))) 1220 except: 1221 self._Table.ParentCollection._Connection.rollback() 1222 self._InTransaction = False 1223 raise 891 1224 self._Row = None 892 1225 … … 895 1228 __doc__ = DynamicDocString() 896 1229 897 def _Open(self , fields, where, orderBy):898 self._RowValues = None1230 def _Open(self): 1231 self._RowValues = {} 899 1232 self._SetFields = set() 1233 self._InTransaction = None 900 1234 901 1235 def _Close(self): 902 1236 self._RowValues = None 903 1237 self._SetFields = None 904 super(SpatiaLiteSelectCursor, self)._Close() 905 906 def _UpdateRow(self): 1238 if self._InTransaction: 1239 try: 1240 self._Table.ParentCollection._Connection.commit() 1241 except: 1242 pass 1243 super(SpatiaLiteInsertCursor, self)._Close() 1244 1245 def _InsertRow(self): 1246 1247 # Fail if we are not in a transaction. The only way this can 1248 # happen is if an error occurred with a previous call to this 1249 # cursor. That will cause the transaction to be rolled back. 1250 # The cursor can no longer be used after that point. 1251 1252 if self._InTransaction is not None and not self._InTransaction: 1253 raise RuntimeError(_(u'Due to the previous error, no more inserts can be performed with this cursor. To perform inserts, close this cursor and open a new one.')) 907 1254 908 1255 # Build the SQL INSERT statement. If no fields have been set, 909 1256 # try the DEFAULT VALUES syntax. This will succeed if all of 910 1257 # the fields are nullable. 911 1258 912 1259 if len(self._SetFields) <= 0: 913 1260 sql = 'INSERT INTO %s DEFAULT VALUES' % self._Table.TableName … … 924 1271 valueStrings = ['?'] * len(self._SetFields) 925 1272 926 if self._Table.GeometryType is not None and self._Table.GeometryFieldName in self._SetFields and self._RowValues[self._Table.Geometry Type] is not None:927 self._RowValues[self._Table.Geometry Type] = buffer(self._RowValues[self._Table.GeometryType].ExportToWKB)1273 if self._Table.GeometryType is not None and self._Table.GeometryFieldName in self._SetFields and self._RowValues[self._Table.GeometryFieldName] is not None: 1274 self._RowValues[self._Table.GeometryFieldName] = buffer(self._RowValues[self._Table.GeometryFieldName].ExportToWkb()) 928 1275 for i in range(len(fieldsToSet)): 929 1276 if fieldsToSet[i] == self._Table.GeometryFieldName: 930 valueStrings[i] = 'ST_GeomFromWKB(?)' 1277 srid = self._Table.GetLazyPropertyValue('SpatiaLiteSRID') 1278 if srid is not None: 1279 valueStrings[i] = 'ST_GeomFromWKB(?, %i)' % srid 1280 else: 1281 valueStrings[i] = 'ST_GeomFromWKB(?)' 931 1282 break 932 1283 933 # Build the SQL INSERT statement. 934 935 sql = 'INSERT INTO %s (%s) VALUES %s' % (self._Table.TableName, ', '.join(fieldsToSet), ', '.join(valueStrings[i])) 936 937 # Insert the row. 938 1284 # Build the SQL INSERT statement. 1285 1286 sql = 'INSERT INTO %s (%s) VALUES (%s)' % (self._Table.TableName, ', '.join(fieldsToSet), ', '.join(valueStrings)) 1287 1288 # Insert the row. 1289 1290 try: 939 1291 self._Table.ParentCollection._Connection.execute(sql, [self._RowValues[field] for field in fieldsToSet]) 940 941 self._RowValues = None 1292 except: 1293 self._Table.ParentCollection._Connection.rollback() 1294 self._InTransaction = False 1295 raise 1296 1297 self._InTransaction = True 1298 self._RowValues = {} 942 1299 self._SetFields = set() 943 1300 … … 947 1304 ############################################################################### 948 1305 1306 from GeoEco.ArcGIS import ArcGISDependency 949 1307 from GeoEco.Dependencies import PythonDependency 950 1308 from GeoEco.Metadata import * … … 1050 1408 description=_(u'%s instance.') % SpatiaLiteDatabase.__name__) 1051 1409 1410 # Public method: SpatiaLiteDatabase.ExportToArcGISWorkspace 1411 1412 AddMethodMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, 1413 shortDescription=_(u'Converts tables in a SpatiaLite database to ArcGIS tables, shapefiles, and feature classes.'), 1414 isExposedToPythonCallers=True, 1415 isExposedByCOM=True, 1416 isExposedAsArcGISTool=True, 1417 arcGISDisplayName=_(u'Convert SpatiaLite Tables to ArcGIS Geodatasets'), 1418 arcGISToolCategory=_(u'Conversion\\To Table, Shapefile, or Feature Class'), 1419 dependencies=[ArcGISDependency(9, 1), PySpatiaLiteDependency()]) 1420 1421 AddArgumentMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, u'cls', 1422 typeMetadata=ClassOrClassInstanceTypeMetadata(cls=SpatiaLiteDatabase), 1423 description=_(u'SpatiaLiteDatabase class or instance.')) 1424 1425 AddArgumentMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, u'spatiaLiteDB', 1426 typeMetadata=FileTypeMetadata(mustExist=True), 1427 description=_( 1428 u"""SpatiaLite database containing the tables to convert. 1429 1430 The tables may have, at most, one geometry column."""), 1431 arcGISDisplayName=_(u'SpatiaLite database')) 1432 1433 AddArgumentMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, u'arcGISWorkspace', 1434 typeMetadata=ArcGISWorkspaceTypeMetadata(createParentDirectories=True, mustBeDifferentThanArguments=[u'spatiaLiteDB']), 1435 description=_( 1436 u"""Directory or geodatabase to receive the geodatasets. 1437 1438 If a directory is specified, SpatiaLite tables without geometry will 1439 be converted to dBASE tables (.dbf files) and SpatiaLite tables with 1440 geometry will be converted to shapefiles. 1441 1442 If a geodatabase is specified, SpatiaLite tables without geometry will 1443 be converted to geodatabase tables and SpatiaLite tables with geometry 1444 will be converted to feature classes."""), 1445 arcGISDisplayName=_(u'Workspace')) 1446 1447 AddArgumentMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, u'tableNames', 1448 typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata(), canBeNone=True), 1449 description=_( 1450 u"""Names of the SpatiaLite tables to convert. 1451 1452 Table names are case-sensitive. If this parameter is omitted, all 1453 tables in the database will be converted."""), 1454 arcGISDisplayName=_(u'Tables to convert')) 1455 1456 AddArgumentMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, u'skipExisting', 1457 typeMetadata=BooleanTypeMetadata(), 1458 description=_( 1459 u"""If True, existing geodatasets will be skipped."""), 1460 arcGISDisplayName=_(u'Skip existing geodatasets')) 1461 1462 AddArgumentMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, u'overwriteExisting', 1463 typeMetadata=BooleanTypeMetadata(), 1464 description=_( 1465 u"""If True, existing geodatasets will be overwritten. If False, a 1466 ValueError will be raised if a geodataset already exists."""), 1467 initializeToArcGISGeoprocessorVariable=u'OverwriteOutput') 1468 1469 AddResultMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, u'updatedArcGISWorkspace', 1470 typeMetadata=ArcGISWorkspaceTypeMetadata(), 1471 description=_(u'Updated workspace.'), 1472 arcGISDisplayName=_(u'Updated workspace'), 1473 arcGISParameterDependencies=[u'ArcGISWorkspace']) 1474 1475 # Public method: SpatiaLiteDatabase.ImportFromArcGISWorkspace 1476 1477 AddMethodMetadata(SpatiaLiteDatabase.ImportFromArcGISWorkspace, 1478 shortDescription=_(u'Converts ArcGIS tables, shapefiles, and feature classes to tables in a SpatiaLite database.'), 1479 isExposedToPythonCallers=True, 1480 isExposedByCOM=True, 1481 isExposedAsArcGISTool=True, 1482 arcGISDisplayName=_(u'Convert ArcGIS Geodatasets to SpatiaLite Tables'), 1483 arcGISToolCategory=_(u'Conversion\\To SpatiaLite Database'), 1484 dependencies=[ArcGISDependency(9, 1), PySpatiaLiteDependency()]) 1485 1486 CopyArgumentMetadata(SpatiaLiteDatabase.ExportToArcGISWorkspace, u'cls', SpatiaLiteDatabase.ImportFromArcGISWorkspace, u'cls') 1487 1488 AddArgumentMetadata(SpatiaLiteDatabase.ImportFromArcGISWorkspace, u'arcGISWorkspace', 1489 typeMetadata=ArcGISWorkspaceTypeMetadata(mustExist=True), 1490 description=_( 1491 u"""ArcGIS database containing tables, shapefiles, and feature classes 1492 to convert."""), 1493 arcGISDisplayName=_(u'Workspace')) 1494 1495 AddArgumentMetadata(SpatiaLiteDatabase.ImportFromArcGISWorkspace, u'spatiaLiteDB', 1496 typeMetadata=FileTypeMetadata(createParentDirectories=True, mustBeDifferentThanArguments=[u'arcGISWorkspace']), 1497 description=_( 1498 u"""SpatiaLite database to receive the geodatasets."""), 1499 direction=u'Output', 1500 arcGISDisplayName=_(u'SpatiaLite database')) 1501 1502 AddArgumentMetadata(SpatiaLiteDatabase.ImportFromArcGISWorkspace, u'tableNames', 1503 typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata(), canBeNone=True), 1504 description=_( 1505 u"""Names of the tables, shapefiles, and feature classes to convert. 1506 1507 The names may be case-sensitive, depending on the type of workspace. 1508 dBASE tables and shapefiles should be specified with their file 1509 extensions (.dbf and .shp, respectively). 1510 1511 If this parameter is omitted, all vector geodatasets in the workspace 1512 will be converted."""), 1513 arcGISDisplayName=_(u'Tables to convert')) 1514 1515 AddArgumentMetadata(SpatiaLiteDatabase.ImportFromArcGISWorkspace, u'skipExisting', 1516 typeMetadata=BooleanTypeMetadata(), 1517 description=_( 1518 u"""If True, existing tables will be skipped.""")) 1519 1520 AddArgumentMetadata(SpatiaLiteDatabase.ImportFromArcGISWorkspace, u'overwriteExisting', 1521 typeMetadata=BooleanTypeMetadata(), 1522 description=_( 1523 u"""If True, existing tables will be overwritten. If False, a 1524 ValueError will be raised if a table already exists."""), 1525 initializeToArcGISGeoprocessorVariable=u'OverwriteOutput') 1526 1052 1527 ############################################################################### 1053 1528 # Metadata: SpatiaLiteTable class -
MGET/Branches/Jason/PythonPackage/src/GeoEco/Datasets/Virtual.py
r873 r903 1606 1606 regionToRead.append(remainingRegion[i]) 1607 1607 else: 1608 regionToRead.append(slice(max(0, remainingRegion[i].start - int(math.floor((self._MinBlockSize[i] - cellsRemaining) / 2.))), min(self.Shape[i], int(math.ceil(remainingRegion[i].stop + (self._MinBlockSize[i] - cellsRemaining) / 2.))))) 1609 1608 maxIndex = self.Shape[self.Dimensions.index(self.GetLazyPropertyValue('PhysicalDimensions')[i])] 1609 regionToRead.append(slice(max(0, remainingRegion[i].start - int(math.floor((self._MinBlockSize[i] - cellsRemaining) / 2.))), min(maxIndex, int(math.ceil(remainingRegion[i].stop + (self._MinBlockSize[i] - cellsRemaining) / 2.))))) 1610 1610 1611 self._Cache.insert(0, [regionToRead, self._Grid._ReadNumpyArray(regionToRead)[0]]) 1611 1612 -
MGET/Branches/Jason/PythonPackage/src/GeoEco/Datasets/__init__.py
r897 r903 1182 1182 if geometryType is not None: 1183 1183 self._RequireCapability('GeometryType %s %s' % (geometryType, tableName)) 1184 if geometry Type is not None:1184 if geometryFieldName is not None: 1185 1185 self._RequireCapability('GeometryFieldName') 1186 1186 … … 1242 1242 1243 1243 if createGeometryField: 1244 table = self.CreateTable(tableName, templateTable.GeometryType, templateTable.GetSpatialReference('Obj'), templateTable.GeometryFieldName) 1244 1245 # If we support assigning the name of the geometry field, 1246 # try to use the same name as the template table. If not, 1247 # do not try to assign the geometry field name (it will 1248 # likely fail). 1249 1250 if self._TestCapability('GeometryFieldName') is None: 1251 geometryFieldName = templateTable.GeometryFieldName 1252 else: 1253 geometryFieldName = None 1254 1255 table = self.CreateTable(tableName, templateTable.GeometryType, templateTable.GetSpatialReference('Obj'), geometryFieldName) 1245 1256 else: 1246 1257 table = self.CreateTable(tableName) … … 1284 1295 else: 1285 1296 fields = [field.Name for field in sourceTable.Fields] 1286 if copiedOIDFieldName is None :1297 if copiedOIDFieldName is None and sourceTable.OIDFieldName is not None: 1287 1298 fields.remove(sourceTable.OIDFieldName) 1288 if destTable.GeometryType is None :1299 if destTable.GeometryType is None and sourceTable.GeometryFieldName is not None: 1289 1300 fields.remove(sourceTable.GeometryFieldName) 1290 1301 … … 1296 1307 insertCursor = destTable.OpenInsertCursor(rowCount, reportProgress, rowDescriptionSingular, rowDescriptionPlural) 1297 1308 try: 1309 if rowCount is not None: 1310 message = _(u'Copying %(rowCount)i %(desc)s from %(dn1)s to %(dn2)s.') % {u'rowCount': rowCount, u'desc': selectCursor.RowDescriptionPlural, u'dn1': sourceTable.DisplayName, u'dn2': destTable.DisplayName} 1311 else: 1312 message = _(u'Copying %(desc)s from %(dn1)s to %(dn2)s.') % {u'desc': selectCursor.RowDescriptionPlural, u'dn1': sourceTable.DisplayName, u'dn2': destTable.DisplayName} 1313 if reportProgress: 1314 self._LogInfo(message) 1315 else: 1316 self._LogDebug(message) 1317 1298 1318 while selectCursor.NextRow(): 1299 1319 for field in fields: … … 1303 1323 insertCursor.SetGeometry(selectCursor.GetGeometry()) 1304 1324 else: 1305 insertCursor.SetValue(field, selectCursor.GetValue(value)) 1325 insertCursor.SetValue(field, selectCursor.GetValue(field)) 1326 insertCursor.InsertRow() 1306 1327 finally: 1307 1328 del insertCursor … … 1309 1330 del selectCursor 1310 1331 1332 # Return successfully. 1333 1334 return destTable 1311 1335 1312 1336 def DeleteTable(self, tableName, failIfNotExists=False): … … 1327 1351 except Exception, e: 1328 1352 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 1353 1331 1354 # Private members that the derived class should override. … … 1337 1360 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 1361 1339 def _CreateTable(self, tableName, geometryType =None, spatialReference=None, geometryFieldName=u'geometry'):1362 def _CreateTable(self, tableName, geometryType, spatialReference, geometryFieldName): 1340 1363 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 1364 … … 1426 1449 self._RequireCapability(dataType + ' IsNullable') 1427 1450 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}) 1451 # If the data type is 'string' and length was supplied, verify 1452 # that it does not exceed the maximum allowed length. 1453 1454 if dataType == 'string' and length is not None and self.MaxStringLength is not None and length > self.MaxStringLength: 1455 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 1456 1438 1457 # If the field already exists with the exact parameters … … 1462 1481 # dictionary of fields. 1463 1482 1464 self.Fields.append(field) 1483 fields = list(self.GetLazyPropertyValue('Fields')) 1484 fields.append(field) 1485 self.SetLazyPropertyValue('Fields', tuple(fields)) 1486 1465 1487 self._FieldsDict[name.upper()] = field 1466 1488 … … 1480 1502 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 1503 return 1482 raise ValueError(_(u'Cannot delete field %(name)s from %(dn)s because a field with that namedoes not exist.') % {u'name': name, u'dn': self.DisplayName})1504 raise ValueError(_(u'Cannot delete field %(name)s from %(dn)s because that field does not exist.') % {u'name': name, u'dn': self.DisplayName}) 1483 1505 1484 1506 # Call the derived class to delete the field. … … 1499 1521 # fields. 1500 1522 1501 del self.Fields[i] 1523 fields = list(self.GetLazyPropertyValue('Fields')) 1524 del fields[i] 1525 self.SetLazyPropertyValue('Fields', tuple(fields)) 1526 1502 1527 del self._FieldsDict[existingField.Name.upper()] 1528 1529 def CreateIndex(self, fields, indexName, unique=False, ascending=True): 1530 # TODO: self.__class__.__doc__.Obj.ValidateMethodInvocation() 1531 1532 # Verify that we have the required capabilities. 1533 1534 self._RequireCapability('CreateIndex') 1535 1536 # Verify that all of the fields exist and that they are not 1537 # trying to create an index on the geometry field. 1538 1539 for name in fields: 1540 field = self.GetFieldByName(name) 1541 if field is None: 1542 raise ValueError(_(u'Cannot create an index on field %(name)s of %(dn)s because that field does not exist.') % {u'name': name, u'dn': self.DisplayName}) 1543 if field.DataType == u'geometry': 1544 raise ValueError(_(u'Cannot create a non-spatial index on field %(name)s of %(dn)s because that is the geometry field. Only spatial indexes can be created on the geometry field.') % {u'name': name, u'dn': self.DisplayName}) 1545 1546 # Call the derived class to create the index. 1547 1548 if indexName is None: 1549 name = '' 1550 else: 1551 name = ' ' + indexName 1552 1553 self._LogDebug(_(u'%(class)s 0x%(id)08X: Creating %(unique)s %(ascending)s index%(name)s on fields [%(fields)s] of %(dn)s.'), 1554 {u'class': self.__class__.__name__, u'id': id(self), u'unique': {False: _(u'non-unique'), True: _(u'unique')}[unique], u'ascending': {False: _(u'descending'), True: _(u'ascending')}[ascending], u'name': name, u'fields': u', '.join(fields), u'dn': self.DisplayName}) 1555 1556 try: 1557 self._CreateIndex(fields, indexName, unique, ascending) 1558 except Exception, e: 1559 raise RuntimeError(_(u'Failed to create %(unique)s %(ascending)s index%(name)s on fields [%(fields)s] of %(dn)s due to %(e)s: %(msg)s') % {u'unique': {False: _(u'non-unique'), True: _(u'unique')}[unique], u'ascending': {False: _(u'descending'), True: _(u'ascending')}[ascending], u'name': name, u'fields': u', '.join(fields), u'dn': self.DisplayName, u'e': e.__class__.__name__, u'msg': self._Unicode(e)}) 1560 1561 def DeleteIndex(self, indexName): 1562 1563 # Verify that we have the required capabilities. 1564 1565 self._RequireCapability('DeleteIndex') 1566 1567 # Call the derived class to delete the index. 1568 1569 if indexName is None: 1570 name = '' 1571 else: 1572 name = ' ' + indexName 1573 1574 self._LogDebug(_(u'%(class)s 0x%(id)08X: Deleting index%(name)s.'), {u'class': self.__class__.__name__, u'id': id(self), u'name': name}) 1575 1576 try: 1577 self._DeleteIndex(indexName) 1578 except Exception, e: 1579 raise RuntimeError(_(u'Failed to delete index%(name)s of %(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)}) 1503 1580 1504 1581 def GetRowCount(self): … … 1535 1612 def _DeleteField(self, name): 1536 1613 raise NotImplementedError(_(u'The _DeleteField method of class %s has not been implemented.') % self.__class__.__name__) 1614 1615 def _CreateIndex(self, fields, indexName, unique, ascending): 1616 raise NotImplementedError(_(u'The _CreateIndex method of class %s has not been implemented.') % self.__class__.__name__) 1617 1618 def _DeleteIndex(self, indexName): 1619 raise NotImplementedError(_(u'The _DeleteIndex method of class %s has not been implemented.') % self.__class__.__name__) 1537 1620 1538 1621 def _GetRowCount(self): -
MGET/Branches/Jason/PythonPackage/src/GeoEco/__init__.py
r891 r903 1 __version__ = u'0.8a3 2'1 __version__ = u'0.8a33'
