[GIS] Python GDAL (/OGR) 2.x: read vectors with gdal.OpenEx or ogr.Open

gdalogrpython

Upgrading one of my GIS Python tool which uses GDAL/OGR to read vectors and rasters datasets, I've installed the last GDAL pypi package in version 2.1.3.

Until now, I do:

driver = ogr.GetDriverByName(str("ESRI Shapefile"))
source_ogr = driver.Open(shp_path, 0)
# or directly source_ogr = ogr.Open(shp_path, 0)
print(type(source_ogr))
>>> <class 'osgeo.ogr.DataSource'>

But when I checked the help, I see:

print(help(driver.Open))

[...]
NOTE: Starting with GDAL 2.0, it is *NOT* safe to cast the returned
handle to OGRDataSource*. If a C++ object is needed, the handle should
be cast to GDALDataset*. Similarly, the returned OGRSFDriverH handle
should be cast to GDALDriver*, and NOT* OGRSFDriver*.

Deprecated Use GDALOpenEx() in GDAL 2.0
[...]

And looking for more information, RFC 46 says:

A global pass has been made to in-tree OGR drivers that have to open a
file to determine if they recognize it. They have been converted to
GDALDriver to accept a GDALOpenInfo argument and they now use its
pabyHeader field to examine the first bytes of files. The number of
system calls realated to file access (open/stat), in order to
determine that a file is not recognized by any OGR driver, has now
dropped from 46 in GDAL 1.11 to 1. The converted drivers are :
AeronavFAA, ArcGEN, AVCBin, AVCE00, BNA, CSV, DGN, EDIGEO, ESRI
Shapefile, GeoJSON, GeoRSS, GML, GPKG, GPSBabel, GPX, GTM, HTF, ILI1,
ILI2, KML, LIBKML, MapInfo? File, MySQL, NAS, NTF, OpenAIR, OSM, PDS,
REC, S57, SDTS, SEGUKOOA, SEGY, SOSI, SQLite, SUA, SVG, TIGER, VFK,
VRT, WFS

Indeed, using gdal.OpenEx it seems to work:

source_gdal = gdal.OpenEx(shp_path, 0)
pringt(type(source_gdal))
>>> <class 'osgeo.gdal.Dataset'>

And two objects are not identical:

print(source_ogr == source_gdal)
>>> False

Which method is better?

==== EDIT after first comments

# with OGR: note the GetName method
driver = ogr.GetDriverByName(str("OpenFileGDB"))
src = driver.Open(source_path, 0)
print(type(src), dir(src), len(dir(src)))
>>> <class 'osgeo.ogr.DataSource'> ['CommitTransaction', 'CopyLayer', 'CreateLayer', 'DeleteLayer', 'Dereference', 'Destroy', 'ExecuteSQL', 'FlushCache', 'GetDescription', 'GetDriver', 'GetLayer', 'GetLayerByIndex', 'GetLayerByName', 'GetLayerCount', 'GetMetadata', 'GetMetadataDomainList', 'GetMetadataItem', 'GetMetadata_Dict', 'GetMetadata_List', 'GetName', 'GetRefCount', 'GetStyleTable', 'GetSummaryRefCount', 'Reference', 'Release', 'ReleaseResultSet', 'RollbackTransaction', 'SetDescription', 'SetMetadata', 'SetMetadataItem', 'SetStyleTable', 'StartTransaction', 'SyncToDisk', 'TestCapability', '__class__', '__del__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__len__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__swig_destroy__', '__weakref__', 'name', 'this', 'thisown'] 59


# with GDAL: note that the method list is different and GetName method is missing
src = gdal.OpenEx(source_path, 0)
print(type(src), dir(src), len(dir(src)))
>>> <class 'osgeo.gdal.Dataset'> ['AddBand', 'BeginAsyncReader', 'BuildOverviews', 'CommitTransaction', 'CopyLayer', 'CreateLayer', 'CreateMaskBand', 'DeleteLayer', 'EndAsyncReader', 'ExecuteSQL', 'FlushCache', 'GetDescription', 'GetDriver', 'GetFileList', 'GetGCPCount', 'GetGCPProjection', 'GetGCPs', 'GetGeoTransform', 'GetLayer', 'GetLayerByIndex', 'GetLayerByName', 'GetLayerCount', 'GetMetadata', 'GetMetadataDomainList', 'GetMetadataItem', 'GetMetadata_Dict', 'GetMetadata_List', 'GetProjection', 'GetProjectionRef', 'GetRasterBand', 'GetStyleTable', 'GetSubDatasets', 'GetTiledVirtualMem', 'GetTiledVirtualMemArray', 'GetVirtualMem', 'GetVirtualMemArray', 'RasterCount', 'RasterXSize', 'RasterYSize', 'ReadAsArray', 'ReadRaster', 'ReadRaster1', 'ReleaseResultSet', 'RollbackTransaction', 'SetDescription', 'SetGCPs', 'SetGeoTransform', 'SetMetadata', 'SetMetadataItem', 'SetProjection', 'SetStyleTable', 'StartTransaction', 'TestCapability', 'WriteRaster', '__class__', '__del__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__swig_destroy__', '__weakref__', 'this', 'thisown'] 76

Best Answer

In GDAL 2 the OGRDatasource was merged with GDALDataset.

Traditionally GDAL used to design the raster part of the library, and OGR the vector part for Simple Features. Starting with GDAL 2.0, both sides have been more tightly integrated

And now all classes inherited from one class - GDALDataset. The OpenEx is preferable to use in GDAL 2 and higher versions. The different between source_ogr and source_gdal is because python binding features.