1 /* 2 * $Id: ogr_python.i 83343857e45420d7b50dfd65e85ee6dcb7c3e7e9 2021-10-24 01:28:35 +0200 Even Rouault $ 3 * 4 * python specific code for ogr bindings. 5 */ 6 7 %feature("autodoc"); 8 9 #ifndef FROM_GDAL_I 10 %init %{ 11 12 if ( OGRGetDriverCount() == 0 ) { 13 OGRRegisterAll(); 14 } 15 16 %} 17 #endif 18 19 /*%{ 20 21 #if PY_MINOR_VERSION >= 4 22 #include "datetime.h" 23 #define USE_PYTHONDATETIME 1 24 #endif 25 %} 26 */ 27 28 %include "ogr_layer_docs.i" 29 #ifndef FROM_GDAL_I 30 %include "ogr_datasource_docs.i" 31 %include "ogr_driver_docs.i" 32 #endif 33 %include "ogr_feature_docs.i" 34 %include "ogr_featuredef_docs.i" 35 %include "ogr_fielddef_docs.i" 36 %include "ogr_geometry_docs.i" 37 38 %rename (GetDriverCount) OGRGetDriverCount; 39 %rename (GetOpenDSCount) OGRGetOpenDSCount; 40 %rename (SetGenerate_DB2_V72_BYTE_ORDER) OGRSetGenerate_DB2_V72_BYTE_ORDER; 41 %rename (RegisterAll) OGRRegisterAll(); 42 43 #ifndef FROM_GDAL_I 44 %{ 45 #define MODULE_NAME "ogr" 46 %} 47 48 %include "python_exceptions.i" 49 %include "python_strings.i" 50 51 %extend OGRDataSourceShadow { 52 %pythoncode { 53 def Destroy(self): 54 "Once called, self has effectively been destroyed. Do not access. For backwards compatibility only" 55 _ogr.delete_DataSource(self) 56 self.thisown = 0 57 58 def Release(self): 59 "Once called, self has effectively been destroyed. Do not access. For backwards compatibility only" 60 _ogr.delete_DataSource(self) 61 self.thisown = 0 62 63 def Reference(self): 64 "For backwards compatibility only." 65 return self.Reference() 66 67 def Dereference(self): 68 "For backwards compatibility only." 69 self.Dereference() 70 71 def __len__(self): 72 """Returns the number of layers on the datasource""" 73 return self.GetLayerCount() 74 75 def __getitem__(self, value): 76 """Support dictionary, list, and slice -like access to the datasource. 77 ds[0] would return the first layer on the datasource. 78 ds['aname'] would return the layer named "aname". 79 ds[0:4] would return a list of the first four layers.""" 80 if isinstance(value, slice): 81 output = [] 82 step = value.step if value.step else 1 83 for i in range(value.start, value.stop, step): 84 lyr = self.GetLayer(i) 85 if lyr is None: 86 return output 87 output.append(lyr) 88 return output 89 if isinstance(value, int): 90 if value > len(self) - 1: 91 raise IndexError 92 return self.GetLayer(value) 93 elif isinstance(value, str): 94 return self.GetLayer(value) 95 else: 96 raise TypeError('Input %s is not of String or Int type' % type(value)) 97 98 def GetLayer(self, iLayer=0): 99 """Return the layer given an index or a name""" 100 if isinstance(iLayer, str): 101 return self.GetLayerByName(str(iLayer)) 102 elif isinstance(iLayer, int): 103 return self.GetLayerByIndex(iLayer) 104 else: 105 raise TypeError("Input %s is not of String or Int type" % type(iLayer)) 106 107 def DeleteLayer(self, value): 108 """Deletes the layer given an index or layer name""" 109 if isinstance(value, str): 110 for i in range(self.GetLayerCount()): 111 name = self.GetLayer(i).GetName() 112 if name == value: 113 return _ogr.DataSource_DeleteLayer(self, i) 114 raise ValueError("Layer %s not found to delete" % value) 115 elif isinstance(value, int): 116 return _ogr.DataSource_DeleteLayer(self, value) 117 else: 118 raise TypeError("Input %s is not of String or Int type" % type(value)) 119 } 120 } 121 122 #endif 123 124 125 %extend OGRLayerShadow { 126 %pythoncode %{ 127 def Reference(self): 128 "For backwards compatibility only." 129 pass 130 131 def Dereference(self): 132 "For backwards compatibility only." 133 pass 134 135 def __len__(self): 136 """Returns the number of features in the layer""" 137 return self.GetFeatureCount() 138 139 # To avoid __len__ being called when testing boolean value 140 # which can have side effects (#4758) 141 def __nonzero__(self): 142 return True 143 144 # For Python 3 compat 145 __bool__ = __nonzero__ 146 147 def __getitem__(self, value): 148 """Support list and slice -like access to the layer. 149 layer[0] would return the first feature on the layer. 150 layer[0:4] would return a list of the first four features.""" 151 if isinstance(value, slice): 152 import sys 153 output = [] 154 if value.stop == sys.maxsize: 155 #for an unending slice, sys.maxsize is used 156 #We need to stop before that or GDAL will write an 157 ##error to stdout 158 stop = len(self) - 1 159 else: 160 stop = value.stop 161 for i in range(value.start, stop, value.step): 162 feature = self.GetFeature(i) 163 if feature: 164 output.append(feature) 165 else: 166 return output 167 return output 168 if isinstance(value, int): 169 if value > len(self) - 1: 170 raise IndexError 171 return self.GetFeature(value) 172 else: 173 raise TypeError("Input %s is not of IntType or SliceType" % type(value)) 174 175 def CreateFields(self, fields): 176 """Create a list of fields on the Layer""" 177 for i in fields: 178 self.CreateField(i) 179 180 def __iter__(self): 181 self.ResetReading() 182 while True: 183 feature = self.GetNextFeature() 184 if not feature: 185 break 186 yield feature 187 188 def schema(self): 189 output = [] 190 defn = self.GetLayerDefn() 191 for n in range(defn.GetFieldCount()): 192 output.append(defn.GetFieldDefn(n)) 193 return output 194 schema = property(schema) 195 196 %} 197 198 } 199 200 %extend OGRFeatureShadow { 201 202 %apply ( const char *utf8_path ) { (const char* value) }; 203 void SetFieldString(int id, const char* value) { 204 OGR_F_SetFieldString(self, id, value); 205 } 206 %clear (const char* value ); 207 208 %pythoncode %{ 209 def Reference(self): 210 pass 211 212 def Dereference(self): 213 pass 214 215 def Destroy(self): 216 "Once called, self has effectively been destroyed. Do not access. For backwards compatibility only" 217 _ogr.delete_Feature(self) 218 self.thisown = 0 219 220 def __cmp__(self, other): 221 """Compares a feature to another for equality""" 222 return self.Equal(other) 223 224 def __copy__(self): 225 return self.Clone() 226 227 def _getfieldindex(self, fieldname): 228 case_insensitive_idx = -1 229 fdefn = _ogr.Feature_GetDefnRef(self) 230 for i in range(fdefn.GetFieldCount()): 231 name = fdefn.GetFieldDefn(i).GetName() 232 if name == fieldname: 233 return i 234 elif case_insensitive_idx < 0 and name.lower() == fieldname.lower(): 235 case_insensitive_idx = i 236 return case_insensitive_idx 237 238 # This makes it possible to fetch fields in the form "feature.area". 239 # This has some risk of name collisions. 240 def __getattr__(self, key): 241 """Returns the values of fields by the given name""" 242 if key == 'this': 243 return self.__dict__[key] 244 245 idx = self._getfieldindex(key) 246 if idx < 0: 247 idx = self.GetGeomFieldIndex(key) 248 if idx < 0: 249 raise AttributeError(key) 250 else: 251 return self.GetGeomFieldRef(idx) 252 else: 253 return self.GetField(idx) 254 255 # This makes it possible to set fields in the form "feature.area". 256 # This has some risk of name collisions. 257 def __setattr__(self, key, value): 258 """Set the values of fields by the given name""" 259 if key == 'this' or key == 'thisown': 260 self.__dict__[key] = value 261 else: 262 idx = self._getfieldindex(key) 263 if idx != -1: 264 self.SetField2(idx, value) 265 else: 266 idx = self.GetGeomFieldIndex(key) 267 if idx != -1: 268 self.SetGeomField(idx, value) 269 else: 270 self.__dict__[key] = value 271 272 # This makes it possible to fetch fields in the form "feature['area']". 273 def __getitem__(self, key): 274 """Returns the values of fields by the given name / field_index""" 275 if isinstance(key, str): 276 fld_index = self._getfieldindex(key) 277 else: 278 fld_index = key 279 if key == self.GetFieldCount(): 280 raise IndexError 281 if fld_index < 0: 282 if isinstance(key, str): 283 fld_index = self.GetGeomFieldIndex(key) 284 if fld_index < 0: 285 raise KeyError("Illegal field requested in GetField()") 286 else: 287 return self.GetGeomFieldRef(fld_index) 288 else: 289 return self.GetField(fld_index) 290 291 # This makes it possible to set fields in the form "feature['area'] = 123". 292 def __setitem__(self, key, value): 293 """Returns the value of a field by field name / index""" 294 if isinstance(key, str): 295 fld_index = self._getfieldindex(key) 296 else: 297 fld_index = key 298 if key == self.GetFieldCount(): 299 raise IndexError 300 if fld_index < 0: 301 if isinstance(key, str): 302 fld_index = self.GetGeomFieldIndex(key) 303 if fld_index < 0: 304 raise KeyError("Illegal field requested in SetField()") 305 else: 306 return self.SetGeomField(fld_index, value) 307 else: 308 return self.SetField2(fld_index, value) 309 310 def GetField(self, fld_index): 311 if isinstance(fld_index, str): 312 fld_index = self._getfieldindex(fld_index) 313 if (fld_index < 0) or (fld_index > self.GetFieldCount()): 314 raise KeyError("Illegal field requested in GetField()") 315 if not (self.IsFieldSet(fld_index)) or self.IsFieldNull(fld_index): 316 return None 317 fld_type = self.GetFieldType(fld_index) 318 if fld_type == OFTInteger: 319 return self.GetFieldAsInteger(fld_index) 320 if fld_type == OFTInteger64: 321 return self.GetFieldAsInteger64(fld_index) 322 if fld_type == OFTReal: 323 return self.GetFieldAsDouble(fld_index) 324 if fld_type == OFTStringList: 325 return self.GetFieldAsStringList(fld_index) 326 if fld_type == OFTIntegerList: 327 return self.GetFieldAsIntegerList(fld_index) 328 if fld_type == OFTInteger64List: 329 return self.GetFieldAsInteger64List(fld_index) 330 if fld_type == OFTRealList: 331 return self.GetFieldAsDoubleList(fld_index) 332 ## if fld_type == OFTDateTime or fld_type == OFTDate or fld_type == OFTTime: 333 # return self.GetFieldAsDate(fld_index) 334 # default to returning as a string. Should we add more types? 335 try: 336 return self.GetFieldAsString(fld_index) 337 except: 338 # For Python3 on non-UTF8 strings 339 return self.GetFieldAsBinary(fld_index) 340 341 # With several override, SWIG cannot dispatch automatically unicode strings 342 # to the right implementation, so we have to do it at hand 343 def SetField(self, *args): 344 """ 345 SetField(self, int id, char value) 346 SetField(self, char name, char value) 347 SetField(self, int id, int value) 348 SetField(self, char name, int value) 349 SetField(self, int id, double value) 350 SetField(self, char name, double value) 351 SetField(self, int id, int year, int month, int day, int hour, int minute, 352 int second, int tzflag) 353 SetField(self, char name, int year, int month, int day, int hour, 354 int minute, int second, int tzflag) 355 """ 356 357 if len(args) == 2 and args[1] is None: 358 return _ogr.Feature_SetFieldNull(self, args[0]) 359 360 if len(args) == 2 and (type(args[1]) == type(1) or type(args[1]) == type(12345678901234)): 361 fld_index = args[0] 362 if isinstance(fld_index, str): 363 fld_index = self._getfieldindex(fld_index) 364 return _ogr.Feature_SetFieldInteger64(self, fld_index, args[1]) 365 366 367 if len(args) == 2 and isinstance(args[1], str): 368 fld_index = args[0] 369 if isinstance(fld_index, str): 370 fld_index = self._getfieldindex(fld_index) 371 return _ogr.Feature_SetFieldString(self, fld_index, args[1]) 372 373 return _ogr.Feature_SetField(self, *args) 374 375 def SetField2(self, fld_index, value): 376 if isinstance(fld_index, str): 377 fld_index = self._getfieldindex(fld_index) 378 if (fld_index < 0) or (fld_index > self.GetFieldCount()): 379 raise KeyError("Illegal field requested in SetField2()") 380 381 if value is None: 382 self.SetFieldNull(fld_index) 383 return 384 385 if isinstance(value, list): 386 if not value: 387 self.SetFieldNull(fld_index) 388 return 389 if isinstance(value[0], type(1)) or isinstance(value[0], type(12345678901234)): 390 self.SetFieldInteger64List(fld_index, value) 391 return 392 elif isinstance(value[0], float): 393 self.SetFieldDoubleList(fld_index, value) 394 return 395 elif isinstance(value[0], str): 396 self.SetFieldStringList(fld_index, value) 397 return 398 else: 399 raise TypeError('Unsupported type of list in SetField2(). Type of element is %s' % str(type(value[0]))) 400 401 try: 402 self.SetField(fld_index, value) 403 except: 404 self.SetField(fld_index, str(value)) 405 return 406 407 def keys(self): 408 names = [] 409 for i in range(self.GetFieldCount()): 410 fieldname = self.GetFieldDefnRef(i).GetName() 411 names.append(fieldname) 412 return names 413 414 def items(self): 415 keys = self.keys() 416 output = {} 417 for key in keys: 418 output[key] = self.GetField(key) 419 return output 420 def geometry(self): 421 return self.GetGeometryRef() 422 423 def ExportToJson(self, as_object=False, options=None): 424 """Exports a GeoJSON object which represents the Feature. The 425 as_object parameter determines whether the returned value 426 should be a Python object instead of a string. Defaults to False. 427 The options parameter is passed to Geometry.ExportToJson()""" 428 429 try: 430 import simplejson 431 except ImportError: 432 try: 433 import json as simplejson 434 except ImportError: 435 raise ImportError("Unable to import simplejson or json, needed for ExportToJson.") 436 437 geom = self.GetGeometryRef() 438 if geom is not None: 439 if options is None: 440 options = [] 441 geom_json_string = geom.ExportToJson(options=options) 442 geom_json_object = simplejson.loads(geom_json_string) 443 else: 444 geom_json_object = None 445 446 output = {'type':'Feature', 447 'geometry': geom_json_object, 448 'properties': {} 449 } 450 451 fid = self.GetFID() 452 if fid != NullFID: 453 output['id'] = fid 454 455 for key in self.keys(): 456 fld_defn = self.GetFieldDefnRef(self.GetFieldIndex(key)) 457 if fld_defn.GetType() == _ogr.OFTInteger and fld_defn.GetSubType() == _ogr.OFSTBoolean: 458 output['properties'][key] = bool(self.GetField(key)) 459 else: 460 output['properties'][key] = self.GetField(key) 461 462 if not as_object: 463 output = simplejson.dumps(output) 464 465 return output 466 467 468 %} 469 470 } 471 472 %extend OGRGeometryShadow { 473 %pythoncode %{ 474 def Destroy(self): 475 self.__swig_destroy__(self) 476 self.thisown = 0 477 478 def __str__(self): 479 return self.ExportToWkt() 480 481 def __copy__(self): 482 return self.Clone() 483 484 def __deepcopy__(self, memo): 485 g = self.Clone() 486 srs = self.GetSpatialReference() 487 if srs: 488 g.AssignSpatialReference(srs.Clone()) 489 return g 490 491 def __reduce__(self): 492 return (self.__class__, (), self.ExportToWkb()) 493 494 def __setstate__(self, state): 495 result = CreateGeometryFromWkb(state) 496 self.this = result.this 497 498 def __iter__(self): 499 for i in range(self.GetGeometryCount()): 500 yield self.GetGeometryRef(i) 501 502 %} 503 } 504 505 506 %extend OGRFieldDefnShadow { 507 %pythoncode { 508 width = property(GetWidth, SetWidth) 509 type = property(GetType, SetType) 510 precision = property(GetPrecision, SetPrecision) 511 name = property(GetName, SetName) 512 justify = property(GetJustify, SetJustify) 513 } 514 } 515 516 %extend OGRGeomFieldDefnShadow { 517 %pythoncode { 518 type = property(GetType, SetType) 519 name = property(GetName, SetName) 520 srs = property(GetSpatialRef, SetSpatialRef) 521 } 522 } 523 524 %extend OGRFeatureDefnShadow { 525 %pythoncode { 526 def Destroy(self): 527 "Once called, self has effectively been destroyed. Do not access. For backwards compatibility only" 528 _ogr.delete_FeatureDefn(self) 529 self.thisown = 0 530 531 } 532 } 533 534 %extend OGRFieldDefnShadow { 535 %pythoncode %{ 536 def Destroy(self): 537 "Once called, self has effectively been destroyed. Do not access. For backwards compatibility only" 538 _ogr.delete_FieldDefn(self) 539 self.thisown = 0 540 %} 541 } 542 543 %import typemaps_python.i 544 545 #ifndef FROM_GDAL_I 546 %include "callback.i" 547 548 549 %extend GDALMajorObjectShadow { 550 %pythoncode %{ 551 def GetMetadata(self, domain=''): 552 if domain[:4] == 'xml:': 553 return self.GetMetadata_List(domain) 554 return self.GetMetadata_Dict(domain) 555 %} 556 } 557 #endif 558 559 #ifdef no_longer_defined_since_it_breaks_py2exe_pyinstaller_ticket_6364 560 %pythoncode %{ 561 562 # Backup original dictionary before doing anything else 563 _initial_dict = globals().copy() 564 565 @property 566 def wkb25Bit(module): 567 import warnings 568 warnings.warn("ogr.wkb25DBit deprecated: use ogr.GT_Flatten(), ogr.GT_HasZ() or ogr.GT_SetZ() instead", DeprecationWarning) 569 return module._initial_dict['wkb25DBit'] 570 571 @property 572 def wkb25DBit(module): 573 import warnings 574 warnings.warn("ogr.wkb25DBit deprecated: use ogr.GT_Flatten(), ogr.GT_HasZ() or ogr.GT_SetZ() instead", DeprecationWarning) 575 return module._initial_dict['wkb25DBit'] 576 577 # Inspired from http://www.dr-josiah.com/2013/12/properties-on-python-modules.html 578 class _Module(object): 579 def __init__(self): 580 self.__dict__ = globals() 581 self._initial_dict = _initial_dict 582 583 # Transfer properties from the object to the Class 584 for k, v in list(self.__dict__.items()): 585 if isinstance(v, property): 586 setattr(self.__class__, k, v) 587 #del self.__dict__[k] 588 589 # Replace original module by our object 590 import sys 591 self._original_module = sys.modules[self.__name__] 592 sys.modules[self.__name__] = self 593 594 # Custom help() replacement to display the help of the original module 595 # instead of the one of our instance object 596 class _MyHelper(object): 597 598 def __init__(self, module): 599 self.module = module 600 self.original_help = help 601 602 # Replace builtin help by ours 603 import builtins 604 builtins.help = self 605 606 def __repr__(self): 607 return self.original_help.__repr__() 608 609 def __call__(self, *args, **kwds): 610 611 if args == (self.module,): 612 import sys 613 614 # Restore original module before calling help() otherwise 615 # we don't get methods or classes mentioned 616 sys.modules[self.module.__name__] = self.module._original_module 617 618 ret = self.original_help(self.module._original_module, **kwds) 619 620 # Reinstall our module 621 sys.modules[self.module.__name__] = self.module 622 623 return ret 624 elif args == (self,): 625 return self.original_help(self.original_help, **kwds) 626 else: 627 return self.original_help(*args, **kwds) 628 629 _MyHelper(_Module()) 630 del _MyHelper 631 del _Module 632 633 %} 634 #endif 635