Skip to content

Commit 43d3e55

Browse files
committed
Add GDALDatasetRunCloseWithoutDestroying() and use it Python bindings Dataset.Close()
1 parent a05ac7e commit 43d3e55

File tree

4 files changed

+67
-7
lines changed

4 files changed

+67
-7
lines changed

gcore/gdal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,7 @@ GDALDriverH CPL_DLL CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH);
13151315
char CPL_DLL **CPL_STDCALL GDALGetFileList(GDALDatasetH);
13161316
void CPL_DLL GDALDatasetMarkSuppressOnClose(GDALDatasetH);
13171317
CPLErr CPL_DLL CPL_STDCALL GDALClose(GDALDatasetH);
1318+
CPLErr CPL_DLL GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS);
13181319
int CPL_DLL CPL_STDCALL GDALGetRasterXSize(GDALDatasetH);
13191320
int CPL_DLL CPL_STDCALL GDALGetRasterYSize(GDALDatasetH);
13201321
int CPL_DLL CPL_STDCALL GDALGetRasterCount(GDALDatasetH);

gcore/gdaldataset.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ GDALDataset::~GDALDataset()
394394
* If a driver implements this method, it must also call it from its
395395
* dataset destructor.
396396
*
397+
* This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying().
398+
*
397399
* A typical implementation might look as the following
398400
* \code{.cpp}
399401
*
@@ -475,6 +477,37 @@ CPLErr GDALDataset::Close()
475477
return CE_None;
476478
}
477479

480+
/************************************************************************/
481+
/* GDALDatasetRunCloseWithoutDestroying() */
482+
/************************************************************************/
483+
484+
/** Run the Close() method, without running destruction of the object.
485+
*
486+
* This ensures that content that should be written to file is written and
487+
* that all file descriptors are closed.
488+
*
489+
* Note that this is different from GDALClose() which also destroys
490+
* the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
491+
* the only functions that can be safely called on the dataset handle after
492+
* this function has been called.
493+
*
494+
* Most users want to use GDALClose() or GDALReleaseDataset() rather than
495+
* this function.
496+
*
497+
* This function is equivalent to the C++ method GDALDataset:Close()
498+
*
499+
* @param hDS dataset handle.
500+
* @return CE_None if no error
501+
*
502+
* @since GDAL 3.12
503+
* @see GDALClose()
504+
*/
505+
CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
506+
{
507+
VALIDATE_POINTER1(hDS, __func__, CE_Failure);
508+
return GDALDataset::FromHandle(hDS)->Close();
509+
}
510+
478511
/************************************************************************/
479512
/* UnregisterFromSharedDataset() */
480513
/************************************************************************/

swig/include/Dataset.i

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,16 @@ public:
283283
return GDALClose(self);
284284
}
285285

286+
#ifdef SWIGPYTHON
287+
CPLErr _RunCloseWithoutDestroying() {
288+
CPLErr eErr = GDALDatasetRunCloseWithoutDestroying(self);
289+
if (eErr != CE_None && CPLGetLastErrorType() == CE_None ) {
290+
CPLError(CE_Failure, CPLE_AppDefined, "Error occurred in GDALDatasetRunCloseWithoutDestroying()");
291+
}
292+
return eErr;
293+
}
294+
#endif
295+
286296
GDALDriverShadow* GetDriver() {
287297
return (GDALDriverShadow*) GDALGetDatasetDriver( self );
288298
}

swig/include/python/gdal_python.i

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,12 +2066,22 @@ CPLErr ReadRaster1( double xoff, double yoff, double xsize, double ysize,
20662066
def Destroy(self):
20672067
import warnings
20682068
warnings.warn("Destroy() is deprecated; use a context manager or Close() instead", DeprecationWarning)
2069-
self.Close()
2069+
self._invalidate_children()
2070+
try:
2071+
return _gdal.Dataset_Close(self)
2072+
finally:
2073+
self.thisown = 0
2074+
self.this = None
20702075

20712076
def Release(self):
20722077
import warnings
20732078
warnings.warn("Release() is deprecated; use a context manager or Close() instead", DeprecationWarning)
2074-
self.Close()
2079+
self._invalidate_children()
2080+
try:
2081+
return _gdal.Dataset_Close(self)
2082+
finally:
2083+
self.thisown = 0
2084+
self.this = None
20752085

20762086
def SyncToDisk(self):
20772087
return self.FlushCache()
@@ -2176,17 +2186,23 @@ CPLErr ReadRaster1( double xoff, double yoff, double xsize, double ysize,
21762186
reachable. If :py:meth:`Close` is never called, the dataset will
21772187
be closed automatically during garbage collection.
21782188
2189+
It is illegal to call any method on the dataset or objects derived
2190+
from it (bands, layers, etc.) afterwards.
2191+
21792192
In most cases, it is preferable to open or create a dataset
21802193
using a context manager instead of calling :py:meth:`Close`
21812194
directly.
21822195
"""
21832196

21842197
self._invalidate_children()
2185-
try:
2186-
return _gdal.Dataset_Close(self, *args)
2187-
finally:
2188-
self.thisown = 0
2189-
self.this = None
2198+
if self.GetRefCount() == 1 and self.thisown:
2199+
try:
2200+
return _gdal.Dataset_Close(self, *args)
2201+
finally:
2202+
self.thisown = 0
2203+
self.this = None
2204+
else:
2205+
return _gdal.Dataset__RunCloseWithoutDestroying(self, *args)
21902206
%}
21912207

21922208
%feature("shadow") ExecuteSQL %{

0 commit comments

Comments
 (0)