From 557763e92dce282d2843fe4a843e7f5a026ad921 Mon Sep 17 00:00:00 2001 From: theroggy Date: Sun, 3 Apr 2022 01:59:45 +0200 Subject: [PATCH 1/7] Fix: pass kwargs on to OGR write --- pyogrio/geopandas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyogrio/geopandas.py b/pyogrio/geopandas.py index 3b21f68f..281954b8 100644 --- a/pyogrio/geopandas.py +++ b/pyogrio/geopandas.py @@ -216,4 +216,5 @@ def write_dataframe(df, path, layer=None, driver=None, encoding=None, **kwargs): crs=crs, geometry_type=geometry_type, encoding=encoding, + **kwargs ) From c199715ae5ee43d2cd3e954d7a6b253f4df256de Mon Sep 17 00:00:00 2001 From: Pieter Roggemans Date: Tue, 27 Aug 2024 23:13:37 +0200 Subject: [PATCH 2/7] Revert "MAINT: avoid tests to run if linting fails (#459)" This reverts commit 6f9db16fb9a06f66ffb4d8514efa64557892f38c. --- .github/workflows/docker-gdal.yml | 11 ++++++++--- .github/workflows/lint.yml | 9 --------- .github/workflows/tests-conda.yml | 11 ++++++++--- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/docker-gdal.yml b/.github/workflows/docker-gdal.yml index b713dc20..601edbe4 100644 --- a/.github/workflows/docker-gdal.yml +++ b/.github/workflows/docker-gdal.yml @@ -1,14 +1,19 @@ name: Docker GDAL Test -on: [workflow_call] # will be called from lint workflow. +on: + push: + branches: + - main + pull_request: + workflow_dispatch: # cancel running jobs on new commit to PR concurrency: - group: Tests-docker-gdal-${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: - Tests-docker-gdal: + TestLinux: name: GDAL ${{ matrix.container }} runs-on: ubuntu-latest strategy: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1d6e80f1..a5eb8080 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,12 +17,3 @@ jobs: with: python-version: "3.11" - uses: pre-commit/action@v3.0.1 - - Call-tests-conda: - needs: [Linting] # require linting to pass before tests run - uses: ./.github/workflows/tests-conda.yml - - Call-tests-docker-gdal: - needs: [Linting] # require linting to pass before tests run - uses: ./.github/workflows/docker-gdal.yml - \ No newline at end of file diff --git a/.github/workflows/tests-conda.yml b/.github/workflows/tests-conda.yml index c11d288b..8fb37da5 100644 --- a/.github/workflows/tests-conda.yml +++ b/.github/workflows/tests-conda.yml @@ -1,14 +1,19 @@ name: Conda Tests -on: [workflow_call] # will be called from lint workflow. +on: + push: + branches: + - main + pull_request: + workflow_dispatch: # cancel running jobs on new commit to PR concurrency: - group: Tests-conda-${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: - Tests-conda: + test: name: ${{ matrix.os }}, python ${{ matrix.python }}, ${{ matrix.env }} runs-on: ${{ matrix.os }} defaults: From 6dbef2c220502b10e16123ea18f03fdb73b05724 Mon Sep 17 00:00:00 2001 From: Pieter Roggemans Date: Thu, 4 Sep 2025 13:46:15 +0200 Subject: [PATCH 3/7] ENH: unlock the gil during execute of SQL --- pyogrio/_io.pyx | 9 +++++---- pyogrio/_ogr.pxd | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pyogrio/_io.pyx b/pyogrio/_io.pyx index a4aed843..1c281a9a 100644 --- a/pyogrio/_io.pyx +++ b/pyogrio/_io.pyx @@ -347,18 +347,19 @@ cdef OGRLayerH execute_sql( ------- pointer to OGR layer """ + cdef char * sql_c + cdef char * sql_dialect_c try: sql_b = sql.encode("utf-8") sql_c = sql_b if sql_dialect is None: - return check_pointer(GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, NULL)) + with nogil: + return GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, NULL) sql_dialect_b = sql_dialect.encode("utf-8") sql_dialect_c = sql_dialect_b - return check_pointer(GDALDatasetExecuteSQL( - ogr_dataset, sql_c, NULL, sql_dialect_c) - ) + return GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, sql_dialect_c) # GDAL does not always raise exception messages in this case except NullPointerError: diff --git a/pyogrio/_ogr.pxd b/pyogrio/_ogr.pxd index 681190ca..b031aa75 100644 --- a/pyogrio/_ogr.pxd +++ b/pyogrio/_ogr.pxd @@ -497,7 +497,7 @@ cdef extern from "gdal.h": OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH ds, const char* pszStatement, OGRGeometryH hSpatialFilter, - const char* pszDialect) + const char* pszDialect) nogil void GDALDatasetReleaseResultSet(GDALDatasetH, OGRLayerH) OGRErr GDALDatasetStartTransaction(GDALDatasetH ds, int bForce) OGRErr GDALDatasetCommitTransaction(GDALDatasetH ds) From d83390325cf796d825b33b0971b3469206c8c5e8 Mon Sep 17 00:00:00 2001 From: Pieter Roggemans Date: Fri, 5 Sep 2025 10:06:49 +0200 Subject: [PATCH 4/7] Use check_pointer outside nogil --- pyogrio/_io.pyx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pyogrio/_io.pyx b/pyogrio/_io.pyx index 1c281a9a..9f6790d0 100644 --- a/pyogrio/_io.pyx +++ b/pyogrio/_io.pyx @@ -349,17 +349,21 @@ cdef OGRLayerH execute_sql( """ cdef char * sql_c cdef char * sql_dialect_c + cdef OGRLayerH retval = NULL try: sql_b = sql.encode("utf-8") sql_c = sql_b if sql_dialect is None: with nogil: - return GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, NULL) + retval = GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, NULL) + return check_pointer(retval) sql_dialect_b = sql_dialect.encode("utf-8") sql_dialect_c = sql_dialect_b - return GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, sql_dialect_c) + with nogil: + retval = GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, sql_dialect_c) + return check_pointer(retval) # GDAL does not always raise exception messages in this case except NullPointerError: From 7841b82e927e63655b825bcf784dc087ae7409e3 Mon Sep 17 00:00:00 2001 From: Pieter Roggemans Date: Fri, 5 Sep 2025 22:36:22 +0200 Subject: [PATCH 5/7] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index ee4a01f5..a8ef89da 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ - Add listing of GDAL data types and subtypes to `read_info` (#556). - Add support to read list fields without arrow (#558). +- Unlock the gil during GDALDatasetExecuteSQL (#572). ### Bug fixes From 86b5b86b0a78a004b9e8a1688473e394a9381edf Mon Sep 17 00:00:00 2001 From: Pieter Roggemans Date: Sun, 7 Sep 2025 23:39:08 +0200 Subject: [PATCH 6/7] Use nogil on all GDAL functions that can take significant time --- pyogrio/_geometry.pyx | 4 +- pyogrio/_io.pyx | 118 +++++++++++++++++++++++++++++------------- pyogrio/_ogr.pxd | 38 +++++++------- 3 files changed, 106 insertions(+), 54 deletions(-) diff --git a/pyogrio/_geometry.pyx b/pyogrio/_geometry.pyx index 87b7ea5a..1fd9a508 100644 --- a/pyogrio/_geometry.pyx +++ b/pyogrio/_geometry.pyx @@ -84,7 +84,9 @@ cdef str get_geometry_type(void *ogr_layer): cdef OGRwkbGeometryType ogr_type try: - ogr_featuredef = check_pointer(OGR_L_GetLayerDefn(ogr_layer)) + with nogil: + ogr_featuredef = OGR_L_GetLayerDefn(ogr_layer) + ogr_featuredef = check_pointer(ogr_featuredef) except NullPointerError: raise DataLayerError("Could not get layer definition") diff --git a/pyogrio/_io.pyx b/pyogrio/_io.pyx index 9f6790d0..46a2ac67 100644 --- a/pyogrio/_io.pyx +++ b/pyogrio/_io.pyx @@ -15,7 +15,6 @@ from pathlib import Path from libc.stdint cimport uint8_t, uintptr_t from libc.stdlib cimport malloc, free -from libc.string cimport strlen from libc.math cimport isnan from cpython.pycapsule cimport PyCapsule_GetPointer @@ -226,6 +225,7 @@ cdef void* ogr_open(const char* path_c, int mode, char** options) except NULL: """ cdef void *ogr_dataset = NULL cdef ErrorHandler errors + cdef int flags # Force linear approximations in all cases OGRSetNonLinearGeometriesEnabledFlag(0) @@ -240,9 +240,10 @@ cdef void* ogr_open(const char* path_c, int mode, char** options) except NULL: # WARNING: GDAL logs warnings about invalid open options to stderr # instead of raising an error with capture_errors() as errors: - ogr_dataset = GDALOpenEx( - path_c, flags, NULL, options, NULL - ) + with nogil: + ogr_dataset = GDALOpenEx( + path_c, flags, NULL, options, NULL + ) return errors.check_pointer(ogr_dataset, True) except NullPointerError: @@ -295,15 +296,23 @@ cdef OGRLayerH get_ogr_layer(GDALDatasetH ogr_dataset, layer) except NULL: pointer to OGR layer """ cdef OGRLayerH ogr_layer = NULL + cdef char *layer_c + cdef int layer_int + cdef char *sql_c try: if isinstance(layer, str): - name_b = layer.encode("utf-8") - name_c = name_b - ogr_layer = check_pointer(GDALDatasetGetLayerByName(ogr_dataset, name_c)) + layer_b = layer.encode("utf-8") + layer_c = layer_b + with nogil: + ogr_layer = GDALDatasetGetLayerByName(ogr_dataset, layer_c) + ogr_layer = check_pointer(ogr_layer) elif isinstance(layer, int): - ogr_layer = check_pointer(GDALDatasetGetLayer(ogr_dataset, layer)) + layer_int = layer + with nogil: + ogr_layer = GDALDatasetGetLayer(ogr_dataset, layer_int) + ogr_layer = check_pointer(ogr_layer) else: raise ValueError( f"'layer' parameter must be a str or int, got {type(layer)}" @@ -325,7 +334,8 @@ cdef OGRLayerH get_ogr_layer(GDALDatasetH ogr_dataset, layer) except NULL: sql_b = f"SET interest_layers = {layer_name}".encode("utf-8") sql_c = sql_b - GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, NULL) + with nogil: + GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL, NULL) return ogr_layer @@ -391,7 +401,9 @@ cdef str get_crs(OGRLayerH ogr_layer): cdef char *ogr_wkt = NULL try: - ogr_crs = check_pointer(OGR_L_GetSpatialRef(ogr_layer)) + with nogil: + ogr_crs = OGR_L_GetSpatialRef(ogr_layer) + ogr_crs = check_pointer(ogr_crs) except NullPointerError: # No coordinate system defined. @@ -438,7 +450,9 @@ cdef get_driver(OGRDataSourceH ogr_dataset): cdef void *ogr_driver try: - ogr_driver = check_pointer(GDALGetDatasetDriver(ogr_dataset)) + with nogil: + ogr_driver = GDALGetDatasetDriver(ogr_dataset) + ogr_driver = check_pointer(ogr_driver) except NullPointerError: raise DataLayerError(f"Could not detect driver of dataset") from None @@ -469,19 +483,25 @@ cdef get_feature_count(OGRLayerH ogr_layer, int force): """ cdef OGRFeatureH ogr_feature = NULL - cdef int feature_count = OGR_L_GetFeatureCount(ogr_layer, force) + cdef int feature_count + + with nogil: + feature_count = OGR_L_GetFeatureCount(ogr_layer, force) # if GDAL refuses to give us the feature count, we have to loop over all # features ourselves and get the count. This can happen for some drivers # (e.g., OSM) or if a where clause is invalid but not rejected as error if force and feature_count == -1: # make sure layer is read from beginning - OGR_L_ResetReading(ogr_layer) + with nogil: + OGR_L_ResetReading(ogr_layer) feature_count = 0 while True: try: - ogr_feature = check_pointer(OGR_L_GetNextFeature(ogr_layer)) + with nogil: + ogr_feature = OGR_L_GetNextFeature(ogr_layer) + ogr_feature = check_pointer(ogr_feature) feature_count +=1 except NullPointerError: @@ -524,10 +544,11 @@ cdef get_total_bounds(OGRLayerH ogr_layer, int force): tuple of (xmin, ymin, xmax, ymax) or None The total bounds of the layer, or None if they could not be determined. """ - cdef OGREnvelope ogr_envelope - if OGR_L_GetExtent(ogr_layer, &ogr_envelope, force) == OGRERR_NONE: + with nogil: + err = OGR_L_GetExtent(ogr_layer, &ogr_envelope, force) + if err == OGRERR_NONE: bounds = ( ogr_envelope.MinX, ogr_envelope.MinY, ogr_envelope.MaxX, ogr_envelope.MaxY ) @@ -682,7 +703,9 @@ cdef get_fields(OGRLayerH ogr_layer, str encoding, use_arrow=False): cdef const char *key_c try: - ogr_featuredef = check_pointer(OGR_L_GetLayerDefn(ogr_layer)) + with nogil: + ogr_featuredef = OGR_L_GetLayerDefn(ogr_layer) + ogr_featuredef = check_pointer(ogr_featuredef) except NullPointerError: raise DataLayerError("Could not get layer definition") from None @@ -756,10 +779,14 @@ cdef apply_where_filter(OGRLayerH ogr_layer, str where): ------ ValueError: if SQL query is not valid """ + cdef const char* where_c + cdef int err where_b = where.encode("utf-8") where_c = where_b - err = OGR_L_SetAttributeFilter(ogr_layer, where_c) + with nogil: + err = OGR_L_SetAttributeFilter(ogr_layer, where_c) + # WARNING: GDAL does not raise this error for GPKG but instead only # logs to stderr if err != OGRERR_NONE: @@ -786,12 +813,14 @@ cdef apply_bbox_filter(OGRLayerH ogr_layer, bbox): ValueError: if bbox is not a list or tuple or does not have proper number of items """ + cdef double xmin, ymin, xmax, ymax if not (isinstance(bbox, (tuple, list)) and len(bbox) == 4): raise ValueError(f"Invalid bbox: {bbox}") xmin, ymin, xmax, ymax = bbox - OGR_L_SetSpatialFilterRect(ogr_layer, xmin, ymin, xmax, ymax) + with nogil: + OGR_L_SetSpatialFilterRect(ogr_layer, xmin, ymin, xmax, ymax) cdef apply_geometry_filter(OGRLayerH ogr_layer, wkb): @@ -812,7 +841,8 @@ cdef apply_geometry_filter(OGRLayerH ogr_layer, wkb): OGR_G_DestroyGeometry(ogr_geometry) raise GeometryError("Could not create mask geometry") from None - OGR_L_SetSpatialFilter(ogr_layer, ogr_geometry) + with nogil: + OGR_L_SetSpatialFilter(ogr_layer, ogr_geometry) OGR_G_DestroyGeometry(ogr_geometry) @@ -824,7 +854,9 @@ cdef apply_skip_features(OGRLayerH ogr_layer, int skip_features): ogr_layer : pointer to open OGR layer wskip_features : int """ - err = OGR_L_SetNextByIndex(ogr_layer, skip_features) + with nogil: + err = OGR_L_SetNextByIndex(ogr_layer, skip_features) + # GDAL can raise an error (depending on the format) for out-of-bound index, # but `validate_feature_range()` should ensure we only pass a valid number if err != OGRERR_NONE: @@ -1081,14 +1113,14 @@ cdef get_features( uint8_t return_fids, bint datetime_as_string ): - cdef OGRFeatureH ogr_feature = NULL cdef int n_fields cdef int i cdef int field_index # make sure layer is read from beginning - OGR_L_ResetReading(ogr_layer) + with nogil: + OGR_L_ResetReading(ogr_layer) if skip_features > 0: apply_skip_features(ogr_layer, skip_features) @@ -1133,7 +1165,9 @@ cdef get_features( break try: - ogr_feature = check_pointer(OGR_L_GetNextFeature(ogr_layer)) + with nogil: + ogr_feature = OGR_L_GetNextFeature(ogr_layer) + ogr_feature = check_pointer(ogr_feature) except NullPointerError: # No more rows available, so stop reading @@ -1201,7 +1235,8 @@ cdef get_features_by_fid( cdef int count = len(fids) # make sure layer is read from beginning - OGR_L_ResetReading(ogr_layer) + with nogil: + OGR_L_ResetReading(ogr_layer) if read_geometry: geometries = np.empty(shape=(count, ), dtype="object") @@ -1231,7 +1266,9 @@ cdef get_features_by_fid( fid = fids[i] try: - ogr_feature = check_pointer(OGR_L_GetFeature(ogr_layer, fid)) + with nogil: + ogr_feature = OGR_L_GetFeature(ogr_layer, fid) + ogr_feature = check_pointer(ogr_feature) except NullPointerError: raise FeatureError(f"Could not read feature with fid {fid}") from None @@ -1263,7 +1300,8 @@ cdef get_bounds(OGRLayerH ogr_layer, int skip_features, int num_features): cdef int i # make sure layer is read from beginning - OGR_L_ResetReading(ogr_layer) + with nogil: + OGR_L_ResetReading(ogr_layer) if skip_features > 0: apply_skip_features(ogr_layer, skip_features) @@ -1281,7 +1319,9 @@ cdef get_bounds(OGRLayerH ogr_layer, int skip_features, int num_features): break try: - ogr_feature = check_pointer(OGR_L_GetNextFeature(ogr_layer)) + with nogil: + ogr_feature = OGR_L_GetNextFeature(ogr_layer) + ogr_feature = check_pointer(ogr_feature) except NullPointerError: # No more rows available, so stop reading @@ -1462,7 +1502,8 @@ def ogr_read( field_c = field_b fields_c = CSLAddString(fields_c, field_c) - OGR_L_SetIgnoredFields(ogr_layer, fields_c) + with nogil: + OGR_L_SetIgnoredFields(ogr_layer, fields_c) geometry_type = get_geometry_type(ogr_layer) @@ -1807,7 +1848,8 @@ def ogr_open_arrow( field_c = field_b fields_c = CSLAddString(fields_c, field_c) - OGR_L_SetIgnoredFields(ogr_layer, fields_c) + with nogil: + OGR_L_SetIgnoredFields(ogr_layer, fields_c) if not return_fids: options = CSLSetNameValue(options, "INCLUDE_FID", "NO") @@ -1828,12 +1870,15 @@ def ogr_open_arrow( ) # make sure layer is read from beginning - OGR_L_ResetReading(ogr_layer) + with nogil: + OGR_L_ResetReading(ogr_layer) # allocate the stream struct and wrap in capsule to ensure clean-up on error capsule = alloc_c_stream(&stream) - if not OGR_L_GetArrowStream(ogr_layer, stream, options): + with nogil: + reval = OGR_L_GetArrowStream(ogr_layer, stream, options) + if not reval: raise RuntimeError("Failed to open ArrowArrayStream from Layer") if skip_features > 0: @@ -1841,7 +1886,8 @@ def ogr_open_arrow( # the Arrow stream # use `OGR_L_SetNextByIndex` directly and not `apply_skip_features` # to ignore errors in case skip_features == feature_count - OGR_L_SetNextByIndex(ogr_layer, skip_features) + with nogil: + OGR_L_SetNextByIndex(ogr_layer, skip_features) if use_pyarrow: import pyarrow as pa @@ -2150,12 +2196,14 @@ cdef get_layer_names(OGRDataSourceH ogr_dataset): """ cdef OGRLayerH ogr_layer = NULL - layer_count = GDALDatasetGetLayerCount(ogr_dataset) + with nogil: + layer_count = GDALDatasetGetLayerCount(ogr_dataset) data = np.empty(shape=(layer_count, 2), dtype=object) data_view = data[:] for i in range(layer_count): - ogr_layer = GDALDatasetGetLayer(ogr_dataset, i) + with nogil: + ogr_layer = GDALDatasetGetLayer(ogr_dataset, i) data_view[i, 0] = get_string(OGR_L_GetName(ogr_layer)) data_view[i, 1] = get_geometry_type(ogr_layer) diff --git a/pyogrio/_ogr.pxd b/pyogrio/_ogr.pxd index b031aa75..fb4737cc 100644 --- a/pyogrio/_ogr.pxd +++ b/pyogrio/_ogr.pxd @@ -387,25 +387,27 @@ cdef extern from "ogr_api.h": const char* OGR_L_GetGeometryColumn(OGRLayerH layer) OGRErr OGR_L_GetExtent(OGRLayerH layer, OGREnvelope *psExtent, - int bForce) + int bForce) nogil - OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH layer) + OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH layer) nogil int OGR_L_TestCapability(OGRLayerH layer, const char *name) - OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH layer) - OGRFeatureH OGR_L_GetNextFeature(OGRLayerH layer) - OGRFeatureH OGR_L_GetFeature(OGRLayerH layer, int nFeatureId) - void OGR_L_ResetReading(OGRLayerH layer) + OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH layer) nogil + OGRFeatureH OGR_L_GetNextFeature(OGRLayerH layer) nogil + OGRFeatureH OGR_L_GetFeature(OGRLayerH layer, int nFeatureId) nogil + void OGR_L_ResetReading(OGRLayerH layer) nogil OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, - const char* pszQuery) - OGRErr OGR_L_SetNextByIndex(OGRLayerH layer, int nIndex) - int OGR_L_GetFeatureCount(OGRLayerH layer, int m) + const char* pszQuery) nogil + OGRErr OGR_L_SetNextByIndex(OGRLayerH layer, int nIndex) nogil + int OGR_L_GetFeatureCount(OGRLayerH layer, int m) nogil void OGR_L_SetSpatialFilterRect(OGRLayerH layer, double xmin, double ymin, double xmax, - double ymax) - void OGR_L_SetSpatialFilter(OGRLayerH layer, OGRGeometryH geometry) - OGRErr OGR_L_SetIgnoredFields(OGRLayerH layer, const char** fields) + double ymax) nogil + void OGR_L_SetSpatialFilter(OGRLayerH layer, + OGRGeometryH geometry) nogil + OGRErr OGR_L_SetIgnoredFields(OGRLayerH layer, + const char** fields) nogil void OGRSetNonLinearGeometriesEnabledFlag(int bFlag) int OGRGetNonLinearGeometriesEnabledFlag() @@ -424,7 +426,7 @@ IF CTE_GDAL_VERSION >= (3, 6, 0): cdef extern from "ogr_api.h": bint OGR_L_GetArrowStream( OGRLayerH hLayer, ArrowArrayStream *out_stream, char** papszOptions - ) + ) nogil IF CTE_GDAL_VERSION >= (3, 8, 0): @@ -483,17 +485,17 @@ cdef extern from "gdal.h": int GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer) - GDALDriverH GDALGetDatasetDriver(GDALDatasetH ds) + GDALDriverH GDALGetDatasetDriver(GDALDatasetH ds) nogil GDALDriverH GDALGetDriverByName(const char * pszName) GDALDatasetH GDALOpenEx(const char * pszFilename, unsigned int nOpenFlags, const char *const *papszAllowedDrivers, const char *const *papszOpenOptions, - const char *const *papszSiblingFiles) + const char *const *papszSiblingFiles) nogil - int GDALDatasetGetLayerCount(GDALDatasetH ds) - OGRLayerH GDALDatasetGetLayer(GDALDatasetH ds, int iLayer) - OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH ds, char * pszName) + int GDALDatasetGetLayerCount(GDALDatasetH ds) nogil + OGRLayerH GDALDatasetGetLayer(GDALDatasetH ds, int iLayer) nogil + OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH ds, char * pszName) nogil OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH ds, const char* pszStatement, OGRGeometryH hSpatialFilter, From 9b76da1bda99ed7b35b9e7b873924c99ab20b9ef Mon Sep 17 00:00:00 2001 From: Pieter Roggemans Date: Mon, 8 Sep 2025 10:38:29 +0200 Subject: [PATCH 7/7] Update CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index a8ef89da..4087e3cb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ - Add listing of GDAL data types and subtypes to `read_info` (#556). - Add support to read list fields without arrow (#558). -- Unlock the gil during GDALDatasetExecuteSQL (#572). +- Unlock the gil during GDAL functions that can take significant time (#572). ### Bug fixes