# This file was automatically generated by SWIG (https://www.swig.org).
# Version 4.4.1
#
# Do not make changes to this file unless you know what you are doing - modify
# the SWIG interface file instead.

from sys import version_info as _swig_python_version_info
# Import the low-level C/C++ module
if getattr(globals().get("__spec__"), "parent", None) or __package__ or "." in __name__:
    from . import _gdal
else:
    import _gdal

try:
    import builtins as __builtin__
except ImportError:
    import __builtin__

def _swig_repr(self):
    try:
        strthis = "proxy of " + self.this.__repr__()
    except __builtin__.Exception:
        strthis = ""
    return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)


def _swig_setattr_nondynamic_instance_variable(set):
    def set_instance_attr(self, name, value):
        if name == "this":
            set(self, name, value)
        elif name == "thisown":
            self.this.own(value)
        elif hasattr(self, name) and isinstance(getattr(type(self), name), property):
            set(self, name, value)
        else:
            raise AttributeError("You cannot add instance attributes to %s" % self)
    return set_instance_attr


def _swig_setattr_nondynamic_class_variable(set):
    def set_class_attr(cls, name, value):
        if hasattr(cls, name) and not isinstance(getattr(cls, name), property):
            set(cls, name, value)
        else:
            raise AttributeError("You cannot add class attributes to %s" % cls)
    return set_class_attr


def _swig_add_metaclass(metaclass):
    """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
    def wrapper(cls):
        return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
    return wrapper


class _SwigNonDynamicMeta(type):
    """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
    __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)


GRAUO_LOGICAL_NOT = _gdal.GRAUO_LOGICAL_NOT
GRAUO_ABS = _gdal.GRAUO_ABS
GRAUO_SQRT = _gdal.GRAUO_SQRT
GRAUO_LOG = _gdal.GRAUO_LOG
GRAUO_LOG10 = _gdal.GRAUO_LOG10
GRABO_ADD = _gdal.GRABO_ADD
GRABO_SUB = _gdal.GRABO_SUB
GRABO_MUL = _gdal.GRABO_MUL
GRABO_DIV = _gdal.GRABO_DIV
GRABO_POW = _gdal.GRABO_POW
GRABO_GT = _gdal.GRABO_GT
GRABO_GE = _gdal.GRABO_GE
GRABO_LT = _gdal.GRABO_LT
GRABO_LE = _gdal.GRABO_LE
GRABO_EQ = _gdal.GRABO_EQ
GRABO_NE = _gdal.GRABO_NE
GRABO_LOGICAL_AND = _gdal.GRABO_LOGICAL_AND
GRABO_LOGICAL_OR = _gdal.GRABO_LOGICAL_OR


have_warned = 0
def deprecation_warn(module, sub_package=None, new_module=None):
    global have_warned

    if have_warned == 1:
        return

    have_warned = 1
    if sub_package is None or sub_package == 'utils':
        sub_package = 'osgeo_utils'
    if new_module is None:
        new_module = module
    new_module = '{}.{}'.format(sub_package, new_module)

    from warnings import warn
    warn('{}.py was placed in a namespace, it is now available as {}' .format(module, new_module),
       DeprecationWarning)


from osgeo.gdalconst import *
from osgeo import gdalconst

import os
import sys
byteorders = {"little": "<",
              "big": ">"}
array_modes = { gdalconst.GDT_Int16:    ("%si2" % byteorders[sys.byteorder]),
                gdalconst.GDT_UInt16:   ("%su2" % byteorders[sys.byteorder]),
                gdalconst.GDT_Int32:    ("%si4" % byteorders[sys.byteorder]),
                gdalconst.GDT_UInt32:   ("%su4" % byteorders[sys.byteorder]),
                gdalconst.GDT_Int64:    ("%si8" % byteorders[sys.byteorder]),
                gdalconst.GDT_UInt64:   ("%su8" % byteorders[sys.byteorder]),
                gdalconst.GDT_Float16:  ("%sf2" % byteorders[sys.byteorder]),
                gdalconst.GDT_Float32:  ("%sf4" % byteorders[sys.byteorder]),
                gdalconst.GDT_Float64:  ("%sf8" % byteorders[sys.byteorder]),
                gdalconst.GDT_CFloat16: ("%sf2" % byteorders[sys.byteorder]),
                gdalconst.GDT_CFloat32: ("%sf4" % byteorders[sys.byteorder]),
                gdalconst.GDT_CFloat64: ("%sf8" % byteorders[sys.byteorder]),
                gdalconst.GDT_Byte:     ("%st8" % byteorders[sys.byteorder]),
}

def RGBFile2PCTFile( src_filename, dst_filename ):
  src_ds = Open(src_filename)
  if src_ds is None or src_ds == 'NULL':
      return 1

  ct = ColorTable()
  err = ComputeMedianCutPCT(src_ds.GetRasterBand(1),
                            src_ds.GetRasterBand(2),
                            src_ds.GetRasterBand(3),
                            256, ct)
  if err != 0:
      return err

  gtiff_driver = GetDriverByName('GTiff')
  if gtiff_driver is None:
      return 1

  dst_ds = gtiff_driver.Create(dst_filename,
                               src_ds.RasterXSize, src_ds.RasterYSize)
  dst_ds.GetRasterBand(1).SetRasterColorTable(ct)

  err = DitherRGB2PCT(src_ds.GetRasterBand(1),
                      src_ds.GetRasterBand(2),
                      src_ds.GetRasterBand(3),
                      dst_ds.GetRasterBand(1),
                      ct)
  dst_ds = None
  src_ds = None

  return 0

def listdir(path, recursionLevel = -1, options = []):
  """ Iterate over a directory.

      recursionLevel = -1 means unlimited level of recursion.
  """
  dir = OpenDir(path, recursionLevel, options)
  if not dir:
      raise OSError(path + ' does not exist')
  try:
      while True:
          entry = GetNextDirEntry(dir)
          if not entry:
              break
          yield entry
  finally:
      CloseDir(dir)

def where(cond_band, then_band, else_band):
    """Ternary operator. Return a band whose value is then_band if the
       corresponding pixel in cond_band is not zero, or the one from else_band
       otherwise.

       cond_band must be a band or convertible to a band. then_band or else_band
       can be band, convertible to band or numeric constants.

       The resulting band is lazily evaluated.

       :since: 3.12
    """
    cond_band = Band._get_as_band_if_possible(cond_band)
    then_band = Band._get_as_band_if_possible(then_band)
    else_band = Band._get_as_band_if_possible(else_band)

    if not isinstance(then_band, Band):
        then_band = (cond_band * 0).astype(DataTypeUnionWithValue(gdalconst.GDT_Unknown, then_band, False)) + then_band

    if not isinstance(else_band, Band):
        else_band = (cond_band * 0).astype(DataTypeUnionWithValue(gdalconst.GDT_Unknown, else_band, False)) + else_band

    return _gdal.Band_IfThenElse(cond_band, then_band, else_band)._add_parent_references([cond_band, then_band, else_band])

Where = where

def minimum(*args):
    """Return a band whose each pixel value is the minimum of the corresponding
       pixel values in the input arguments which may be gdal.Band or a numeric constant.

       The resulting band is lazily evaluated.

       :since: 3.12
    """
    constant = None
    band_refs = []
    band_args = []
    for arg in args:
        band_arg = Band._get_as_band_if_possible(arg)
        if isinstance(band_arg, Band):
            band_args.append(band_arg)
            band_refs.append(arg)
        elif constant is None or arg < constant:
            constant = arg
    if not band_args:
        raise RuntimeError("At least one argument should be a band (or convertible to a band)")
    res = _gdal.Band_MinimumOfNBands(band_args)._add_parent_references(band_refs)
    if constant is not None:
        res = _gdal.Band_MinConstant(res, constant)._add_parent_references([res])
    return res

Minimum = minimum

def maximum(*args):
    """Return a band whose each pixel value is the maximum of the corresponding
       pixel values in the input arguments which may be gdal.Band or a numeric constant.

       The resulting band is lazily evaluated.

       :since: 3.12
    """
    constant = None
    band_refs = []
    band_args = []
    for arg in args:
        band_arg = Band._get_as_band_if_possible(arg)
        if isinstance(band_arg, Band):
            band_args.append(band_arg)
            band_refs.append(arg)
        elif constant is None or arg > constant:
            constant = arg
    if not band_args:
        raise RuntimeError("At least one argument should be a band (or convertible to a band)")
    res = _gdal.Band_MaximumOfNBands(band_args)._add_parent_references(band_refs)
    if constant is not None:
        res = _gdal.Band_MaxConstant(res, constant)._add_parent_references([res])
    return res

Maximum = maximum

def mean(*args):
    """Return a band whose each pixel value is the arithmetic mean of the corresponding
       pixel values in the input bands.

       The resulting band is lazily evaluated.

       :since: 3.12
    """
    bands = [Band._get_as_band_if_possible(band) for band in args]
    band_refs = [band for band in args]
    return _gdal.Band_MeanOfNBands(bands)._add_parent_references(band_refs)

Mean = mean


def logical_and(x1, x2):
    """Perform a logical and between two objects, such objects being
       a raster band a numpy array or a constant

       The resulting band is lazily evaluated.
    """
    x1 = Band._get_as_band_if_possible(x1)
    x2 = Band._get_as_band_if_possible(x2)
    if isinstance(x1, Band) and isinstance(x2, Band):
        return _gdal.Band_BinaryOpBand(x1, GRABO_LOGICAL_AND, x2)._add_parent_references([x1, x2])
    elif isinstance(x1, Band):
        return _gdal.Band_BinaryOpDouble(x1, GRABO_LOGICAL_AND, x2)._add_parent_references([x1])
    else:
        return _gdal.Band_BinaryOpDouble(x2, GRABO_LOGICAL_AND, x1)._add_parent_references([x2])

LogicalAnd = logical_and


def logical_or(x1, x2):
    """Perform a logical or between two objects, such objects being
       a raster band a numpy array or a constant

       The resulting band is lazily evaluated.
    """
    x1 = Band._get_as_band_if_possible(x1)
    x2 = Band._get_as_band_if_possible(x2)
    if isinstance(x1, Band) and isinstance(x2, Band):
        return _gdal.Band_BinaryOpBand(x1, GRABO_LOGICAL_OR, x2)._add_parent_references([x1, x2])
    elif isinstance(x1, Band):
        return _gdal.Band_BinaryOpDouble(x1, GRABO_LOGICAL_OR, x2)._add_parent_references([x1])
    else:
        return _gdal.Band_BinaryOpDouble(x2, GRABO_LOGICAL_OR, x1)._add_parent_references([x2])

LogicalOr = logical_or


def logical_not(band):
    """Perform a logical not on a raster band or a numpy array.

       The resulting band is lazily evaluated.
    """
    band = Band._get_as_band_if_possible(band)
    return _gdal.Band_UnaryOp(band, GRAUO_LOGICAL_NOT)._add_parent_references([band])

LogicalNot = logical_not

def abs(band):
    """Return the absolute value (or module for complex data type) of a raster band or a numpy array.

       The resulting band is lazily evaluated.
    """
    band = Band._get_as_band_if_possible(band)
    return _gdal.Band_UnaryOp(band, GRAUO_ABS)._add_parent_references([band])

Abs = abs

def sqrt(band):
    """Return the square root of a raster band or a numpy array.

       The resulting band is lazily evaluated.
    """
    band = Band._get_as_band_if_possible(band)
    return _gdal.Band_UnaryOp(band, GRAUO_SQRT)._add_parent_references([band])

Sqrt = sqrt

def log10(band):
    """Return the logarithm base 10 of a raster band or a numpy array.

       The resulting band is lazily evaluated.
    """
    band = Band._get_as_band_if_possible(band)
    return _gdal.Band_UnaryOp(band, GRAUO_LOG10)._add_parent_references([band])

Log10 = log10

def log(band):
    """Return the natural logarithm of a raster band or a numpy array.

       The resulting band is lazily evaluated.
    """
    band = Band._get_as_band_if_possible(band)
    return _gdal.Band_UnaryOp(band, GRAUO_LOG)._add_parent_references([band])

Log = log


def pow(x1, x2):
    """Raise x1 to the power of x2 between two objects, such objects being
       a raster band a numpy array or a constant

       The resulting band is lazily evaluated.
    """
    x1 = Band._get_as_band_if_possible(x1)
    x2 = Band._get_as_band_if_possible(x2)
    if isinstance(x1, Band) and isinstance(x2, Band):
        return _gdal.Band_BinaryOpBand(x1, GRABO_POW, x2)._add_parent_references([x1, x2])
    elif isinstance(x1, Band):
        return _gdal.Band_BinaryOpDouble(x1, GRABO_POW, x2)._add_parent_references([x1])
    else:
        return _gdal.Band_BinaryOpDoubleToBand(x1, GRABO_POW, x2)._add_parent_references([x2])

Pow = pow

class Window:
    def __init__(self, xoff, yoff, xsize, ysize):
        self.data = [xoff, yoff, xsize, ysize]

    def __copy__(self):
        return Window(*self.data)

    def __getitem__(self, i):
        return self.data[i]

    def __setitem__(self, i, value):
        self.data[i] = value

    def __iter__(self):
        return iter(self.data)

    def __eq__(self, other):
        if isinstance(other, Window):
            return self.data == other.data
        if type(other) is tuple:
            return tuple(self.data) == other
        return self.data == other

    def __repr__(self):
        return f'Window({self.data[0]}, {self.data[1]}, {self.data[2]}, {self.data[3]})'

    @property
    def xoff(self):
        return self.data[0]

    @xoff.setter
    def xoff(self, value):
        self.data[0] = value

    @property
    def yoff(self):
        return self.data[1]

    @yoff.setter
    def yoff(self, value):
        self.data[1] = value

    @property
    def xsize(self):
        return self.data[2]

    @xsize.setter
    def xsize(self, value):
        self.data[2] = value

    @property
    def ysize(self):
        return self.data[3]

    @ysize.setter
    def ysize(self, value):
        self.data[3] = value



def GetUseExceptions(*args):
    r"""GetUseExceptions() -> int"""
    return _gdal.GetUseExceptions(*args)

def _GetExceptionsLocal(*args):
    r"""_GetExceptionsLocal() -> int"""
    return _gdal._GetExceptionsLocal(*args)

def _SetExceptionsLocal(*args):
    r"""_SetExceptionsLocal(bVal)"""
    return _gdal._SetExceptionsLocal(*args)

def _UseExceptions(*args):
    r"""_UseExceptions()"""
    return _gdal._UseExceptions(*args)

def _DontUseExceptions(*args):
    r"""_DontUseExceptions()"""
    return _gdal._DontUseExceptions(*args)

def _UserHasSpecifiedIfUsingExceptions(*args):
    r"""_UserHasSpecifiedIfUsingExceptions() -> int"""
    return _gdal._UserHasSpecifiedIfUsingExceptions(*args)

class ExceptionMgr:
    """
    Context manager to manage Python Exception state
    for GDAL/OGR/OSR/GNM.

    Separate exception state is maintained for each
    module (gdal, ogr, etc), and this class appears independently
    in all of them. This is built in top of calls to the older
    UseExceptions()/DontUseExceptions() functions.

    Example::

        >>> print(gdal.GetUseExceptions())
        0
        >>> with gdal.ExceptionMgr():
        ...     # Exceptions are now in use
        ...     print(gdal.GetUseExceptions())
        1
        >>>
        >>> # Exception state has now been restored
        >>> print(gdal.GetUseExceptions())
        0

    """
    def __init__(self, useExceptions=True):
        """
        Save whether or not this context will be using exceptions
        """
        self.requestedUseExceptions = useExceptions

    def __enter__(self):
        """
        On context entry, save the current GDAL exception state, and
        set it to the state requested for the context

        """
        self.currentUseExceptions = _GetExceptionsLocal()
        _SetExceptionsLocal(self.requestedUseExceptions)
        if ExceptionMgr.__module__ == "osgeo.gdal":
            try:
                from . import gdal_array
            except ImportError:
                gdal_array = None
            if gdal_array:
                gdal_array._SetExceptionsLocal(self.requestedUseExceptions)

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        On exit, restore the GDAL/OGR/OSR/GNM exception state which was
        current on entry to the context
        """
        _SetExceptionsLocal(self.currentUseExceptions)
        if ExceptionMgr.__module__ == "osgeo.gdal":
            try:
                from . import gdal_array
            except ImportError:
                gdal_array = None
            if gdal_array:
                gdal_array._SetExceptionsLocal(self.currentUseExceptions)




import importlib.util

def _has_gdal_array():
    return importlib.util.find_spec("osgeo.gdal_array") and importlib.util.find_spec("numpy")

def UseExceptions():
    """ Enable exceptions in all GDAL related modules (osgeo.gdal, osgeo.ogr, osgeo.osr, osgeo.gnm).
        Note: prior to GDAL 3.7, this only affected the calling module"""

    try:
        from . import gdal
        gdal._UseExceptions()
    except ImportError:
        pass

    if _has_gdal_array():
        try:
            from . import gdal_array
            gdal_array._UseExceptions()
        except ImportError:
            pass
    try:
        from . import ogr
        ogr._UseExceptions()
    except ImportError:
        pass

    try:
        from . import osr
        osr._UseExceptions()
    except ImportError:
        pass

    try:
        from . import gnm
        gnm._UseExceptions()
    except ImportError:
        pass

def DontUseExceptions():
    """ Disable exceptions in all GDAL related modules (osgeo.gdal, osgeo.ogr, osgeo.osr, osgeo.gnm).
        Note: prior to GDAL 3.7, this only affected the calling module"""

    try:
        from . import gdal
        gdal._DontUseExceptions()
    except ImportError:
        pass

    if _has_gdal_array():
        try:
            from . import gdal_array
            gdal_array._DontUseExceptions()
        except ImportError:
            pass

    try:
        from . import ogr
        ogr._DontUseExceptions()
    except ImportError:
        pass

    try:
        from . import osr
        osr._DontUseExceptions()
    except ImportError:
        pass

    try:
        from . import gnm
        gnm._DontUseExceptions()
    except ImportError:
        pass



def VSIFReadL(*args):
    r"""VSIFReadL(nMembSize, nMembCount, fp) -> unsigned int"""
    return _gdal.VSIFReadL(*args)

def VSIGetMemFileBuffer_unsafe(*args):
    r"""VSIGetMemFileBuffer_unsafe(utf8_string)"""
    return _gdal.VSIGetMemFileBuffer_unsafe(*args)


def _WarnIfUserHasNotSpecifiedIfUsingExceptions():
    from . import gdal
    if not hasattr(gdal, "hasWarnedAboutUserHasNotSpecifiedIfUsingExceptions") and not _UserHasSpecifiedIfUsingExceptions():
        gdal.hasWarnedAboutUserHasNotSpecifiedIfUsingExceptions = True
        import warnings
        warnings.warn(
            "Neither gdal.UseExceptions() nor gdal.DontUseExceptions() has been explicitly called. " +
            "In GDAL 4.0, exceptions will be enabled by default.", FutureWarning)

def _WarnIfUserHasNotSpecifiedIfUsingOgrExceptions():
    from . import ogr
    ogr._WarnIfUserHasNotSpecifiedIfUsingExceptions()



def InfoOptions(options=None, format='text', deserialize=True,
         computeMinMax=False, reportHistograms=False, reportProj4=False,
         stats=False, approxStats=False, computeChecksum=False,
         showGCPs=True, showMetadata=True, showRAT=True, showColorTable=True,
         showNodata=True, showMask=True,
         listMDD=False, showFileList=True, allMetadata=False,
         extraMDDomains=None, wktFormat=None):
    """ Create a InfoOptions() object that can be passed to gdal.Info()
        options can be an array of strings, a string or let empty and filled from other keywords."""

    options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
        format = 'text'
        if '-json' in new_options:
            format = 'json'
    else:
        import copy
        new_options = copy.copy(options)
        if format == 'json':
            new_options += ['-json']
        elif format != "text":
            raise Exception("Invalid value for format")
        if '-json' in new_options:
            format = 'json'
        if computeMinMax:
            new_options += ['-mm']
        if reportHistograms:
            new_options += ['-hist']
        if reportProj4:
            new_options += ['-proj4']
        if stats:
            new_options += ['-stats']
        if approxStats:
            new_options += ['-approx_stats']
        if computeChecksum:
            new_options += ['-checksum']
        if not showGCPs:
            new_options += ['-nogcp']
        if not showMetadata:
            new_options += ['-nomd']
        if not showRAT:
            new_options += ['-norat']
        if not showColorTable:
            new_options += ['-noct']
        if not showNodata:
            new_options += ['-nonodata']
        if not showMask:
            new_options += ['-nomask']
        if listMDD:
            new_options += ['-listmdd']
        if not showFileList:
            new_options += ['-nofl']
        if allMetadata:
            new_options += ['-mdd', 'all']
        if wktFormat:
            new_options += ['-wkt_format', wktFormat]
        if extraMDDomains is not None:
            for mdd in extraMDDomains:
                new_options += ['-mdd', mdd]

    return (GDALInfoOptions(new_options), format, deserialize)


def _get_allowed_drivers_and_open_options(**kwargs):

    allowed_drivers = []
    open_options = []
    if 'options' in kwargs and isinstance(kwargs['options'], list):
        options = kwargs['options']
        i = 0
        while i < len(options):
            if options[i] == "-if":
                i += 1
                allowed_drivers.append(options[i])
            elif options[i] == "-oo":
                i += 1
                open_options.append(options[i])
            i += 1

    return allowed_drivers, open_options


def Info(ds, **kwargs):
    """Return information on a raster dataset.

    Parameters
    ----------
    ds : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.InfoOptions(), string or array of strings
        other keywords arguments of gdal.InfoOptions().
        If options is provided as a gdal.InfoOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, format, deserialize) = InfoOptions(**kwargs)
    else:
        (opts, format, deserialize) = kwargs['options']

    if isinstance(ds, (str, os.PathLike)):
        ds = OpenEx(ds, allowed_drivers = allowed_drivers, open_options = open_options)
    ret = InfoInternal(ds, opts)
    if format == 'json' and deserialize:
        import json
        ret = json.loads(ret)
    return ret


def VectorInfoOptions(options=None,
                      format='text',
                      deserialize=True,
                      layers=None,
                      dumpFeatures=False,
                      limit=None,
                      featureCount=True,
                      extent=True,
                      SQLStatement=None,
                      SQLDialect=None,
                      where=None,
                      wktFormat=None):
    """ Create a VectorInfoOptions() object that can be passed to gdal.VectorInfo()
        options can be an array of strings, a string or let empty and filled from other keywords.

        Parameters
        ----------
        options : any
            can be an array of strings, a string or let empty and filled from other keywords.
        format : any
            "text" or "json"
        deserialize : any
            if JSON output should be returned as a Python dictionary. Otherwise as a serialized representation.
        SQLStatement : str
            SQL statement to apply to the source dataset
        SQLDialect : str
            SQL dialect ('OGRSQL', 'SQLITE', ...)
        where : str
            WHERE clause to apply to source layer(s)
        layers : any
            list of layers of interest
        featureCount : any
            whether to compute and display the feature count
        extent : any
            whether to compute and display the layer extent. Can also be set to the string '3D' to request a 3D extent
        dumpFeatures : any
            set to True to get the dump of all features
        limit : int
            maximum number of features to read per layer
    """

    options = [] if options is None else options
    deserialize=True

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
        format = 'text'
        if '-json' in new_options:
            format = 'json'
    else:
        import copy
        new_options = copy.copy(options)
        if format == 'json':
            new_options += ['-json']
        elif format != "text":
            raise Exception("Invalid value for format")
        if '-json' in new_options:
            format = 'json'
        if SQLStatement:
            new_options += ['-sql', SQLStatement]
        if SQLDialect:
            new_options += ['-dialect', SQLDialect]
        if where:
            new_options += ['-where', where]
        if wktFormat:
            new_options += ['-wkt_format', wktFormat]
        if not featureCount:
            new_options += ['-nocount']
        if extent in ('3d', '3D'):
            new_options += ['-extent3D']
        elif not extent:
            new_options += ['-noextent']
        if layers:
            new_options += ["dummy_dataset_name"]
            for layer in layers:
                new_options += [layer]
        else:
            new_options += ["-al"]
        if format == 'json':
            if dumpFeatures:
                new_options += ["-features"]
        else:
            if not dumpFeatures:
                new_options += ["-so"]
        if limit:
            new_options += ["-limit", str(limit)]

    return (GDALVectorInfoOptions(new_options), format, deserialize)


def VectorInfo(ds, **kwargs):
    """Return information on a vector dataset.

    Parameters
    ----------
    ds : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.VectorInfoOptions(), string or array of strings
        other keywords arguments of gdal.VectorInfoOptions().
        If options is provided as a gdal.VectorInfoOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, format, deserialize) = VectorInfoOptions(**kwargs)
    else:
        (opts, format, deserialize) = kwargs['options']

    if isinstance(ds, (str, os.PathLike)):
        ds = OpenEx(ds, OF_VERBOSE_ERROR | OF_VECTOR, allowed_drivers = allowed_drivers, open_options = open_options)
    ret = VectorInfoInternal(ds, opts)
    if format == 'json' and deserialize:
        import json
        ret = json.loads(ret)
    return ret


def MultiDimInfoOptions(options=None, detailed=False, array=None, arrayoptions=None, limit=None, as_text=False):
    """ Create a MultiDimInfoOptions() object that can be passed to gdal.MultiDimInfo()
        options can be an array of strings, a string or let empty and filled from other keywords."""

    options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if detailed:
            new_options += ['-detailed']
        if array:
            new_options += ['-array', array]
        if limit:
            new_options += ['-limit', str(limit)]
        if arrayoptions:
            for option in arrayoptions:
                new_options += ['-arrayoption', option]

    return GDALMultiDimInfoOptions(new_options), as_text

def MultiDimInfo(ds, **kwargs):
    """Return information on a dataset.

    Parameters
    ----------
    ds : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.MultiDimInfoOptions(), string or array of strings
        other keywords arguments of gdal.MultiDimInfoOptions().
        If options is provided as a gdal.MultiDimInfoOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        opts, as_text = MultiDimInfoOptions(**kwargs)
    else:
        opts = kwargs['options']
        as_text = True

    if isinstance(ds, (str, os.PathLike)):
        ds = OpenEx(ds, OF_VERBOSE_ERROR | OF_MULTIDIM_RASTER, allowed_drivers = allowed_drivers, open_options = open_options)
    ret = MultiDimInfoInternal(ds, opts)
    if not as_text:
        import json
        ret = json.loads(ret)
    return ret


def _strHighPrec(x):
    return ('%.18g' % x) if isinstance(x, float) else str(x)

mapGRIORAMethodToString = {
    gdalconst.GRIORA_NearestNeighbour: 'near',
    gdalconst.GRIORA_Bilinear: 'bilinear',
    gdalconst.GRIORA_Cubic: 'cubic',
    gdalconst.GRIORA_CubicSpline: 'cubicspline',
    gdalconst.GRIORA_Lanczos: 'lanczos',
    gdalconst.GRIORA_Average: 'average',
    gdalconst.GRIORA_RMS: 'rms',
    gdalconst.GRIORA_Mode: 'mode',
    gdalconst.GRIORA_Gauss: 'gauss',
}

def _addOptions(new_options, arg, options):
    if isinstance(options, str):
        new_options += [arg, options]
    elif isinstance(options, dict):
        for k, v in options.items():
            new_options += [arg, f'{k}={v}']
    else:
        for opt in options:
            new_options += [arg, opt]

def _addCreationOptions(new_options, creationOptions):
    """Update new_options with creationOptions formatted as expected by utilities"""
    _addOptions(new_options, '-co', creationOptions)

def TranslateOptions(options=None, format=None,
              outputType = gdalconst.GDT_Unknown, bandList=None, maskBand=None,
              width = 0, height = 0, widthPct = 0.0, heightPct = 0.0,
              xRes = 0.0, yRes = 0.0,
              creationOptions=None, srcWin=None, projWin=None, projWinSRS=None, strict = False,
              unscale = False, scaleParams=None, exponents=None,
              outputBounds=None, outputGeotransform=None, metadataOptions=None,
              outputSRS=None, nogcp=False, GCPs=None,
              noData=None, rgbExpand=None,
              stats = False, rat = True, xmp = True, resampleAlg=None,
              overviewLevel = 'AUTO',
              colorInterpretation=None,
              callback=None, callback_data=None,
              domainMetadataOptions = None,
              errorIfWindowOutsideSource = False):
    """Create a TranslateOptions() object that can be passed to gdal.Translate()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    format : str
        output format ("GTiff", etc...)
    outputType : any
        output type (gdalconst.GDT_Byte, etc...)
    bandList : any
        array of band numbers (index start at 1)
    maskBand : any
        mask band to generate or not ("none", "auto", "mask", 1, ...)
    width : int
        width of the output raster in pixel
    height : int
        height of the output raster in pixel
    widthPct : any
        width of the output raster in percentage (100 = original width)
    heightPct : any
        height of the output raster in percentage (100 = original height)
    xRes : int
        output horizontal resolution
    yRes : int
        output vertical resolution
    creationOptions : list or dict
        list or dict of creation options
    srcWin : any
        subwindow in pixels to extract: [left_x, top_y, width, height]
    projWin : any
        subwindow in projected coordinates to extract: [ulx, uly, lrx, lry]
    projWinSRS : any
        SRS in which projWin is expressed
    strict : any
        strict mode
    unscale : any
        unscale values with scale and offset metadata
    scaleParams : any
        list of scale parameters, each of the form [src_min,src_max] or [src_min,src_max,dst_min,dst_max]
    exponents : any
        list of exponentiation parameters
    outputBounds : any
        assigned output bounds: [ulx, uly, lrx, lry]
    outputGeotransform : any
        assigned geotransform matrix (array of 6 values) (mutually exclusive with outputBounds)
    metadataOptions : any
        list or dict of metadata options
    outputSRS : any
        assigned output SRS
    nogcp : any
        ignore GCP in the raster
    GCPs : any
        list of GCPs
    noData : any
        nodata value (or "none" to unset it)
    rgbExpand : any
        Color palette expansion mode: "gray", "rgb", "rgba"
    stats : any
        whether to calculate statistics
    rat : any
        whether to write source RAT
    xmp : any
        whether to copy XMP metadata
    resampleAlg : any
        resampling mode
    overviewLevel : any
        To specify which overview level of source files must be used
    colorInterpretation : any
        Band color interpretation, as a single value or a list, of the following values ("red", "green", "blue", "alpha", "grey", "undefined", etc.) or their GCI_xxxx symbolic names
    callback : any
        callback method
    callback_data : any
        user data for callback
    domainMetadataOptions : any
        list or dict of domain-specific metadata options
    errorIfWindowOutsideSource : {True, False, "partially", "completely"}, default=True
         raise an error if the requested window is partially or completely outside the source dataset. ("True" is a synonym for "partially"). This corresponds to the ``-epo`` and ``-eco`` options of ``gdal_translate``.
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'

    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if format is not None:
            new_options += ['-of', format]
        if outputType != gdalconst.GDT_Unknown:
            new_options += ['-ot', GetDataTypeName(outputType)]
        if maskBand != None:
            new_options += ['-mask', str(maskBand)]
        if bandList != None:
            for b in bandList:
                new_options += ['-b', str(b)]
        if width != 0 or height != 0:
            new_options += ['-outsize', str(width), str(height)]
        elif widthPct != 0 and heightPct != 0:
            new_options += ['-outsize', str(widthPct) + '%', str(heightPct) + '%']
        if creationOptions is not None:
            _addCreationOptions(new_options, creationOptions)
        if srcWin is not None:
            new_options += ['-srcwin', _strHighPrec(srcWin[0]), _strHighPrec(srcWin[1]), _strHighPrec(srcWin[2]), _strHighPrec(srcWin[3])]
        if strict:
            new_options += ['-strict']
        if unscale:
            new_options += ['-unscale']
        if scaleParams:
            for scaleParam in scaleParams:
                new_options += ['-scale']
                for v in scaleParam:
                    new_options += [str(v)]
        if exponents:
            for exponent in exponents:
                new_options += ['-exponent', _strHighPrec(exponent)]
        if outputBounds is not None:
            new_options += ['-a_ullr', _strHighPrec(outputBounds[0]), _strHighPrec(outputBounds[1]), _strHighPrec(outputBounds[2]), _strHighPrec(outputBounds[3])]
        if outputGeotransform:
            if outputBounds:
                raise Exception("outputBounds and outputGeotransform are mutually exclusive")
            assert len(outputGeotransform) == 6
            new_options += ['-a_gt']
            for val in outputGeotransform:
                new_options += [_strHighPrec(val)]
        if metadataOptions is not None:
            _addOptions(new_options, '-mo', metadataOptions)
        if domainMetadataOptions is not None:
            if isinstance(domainMetadataOptions, str):
                new_options += ['-dmo', domainMetadataOptions]
            elif isinstance(domainMetadataOptions, dict):
                for d in domainMetadataOptions:
                  things = domainMetadataOptions[d]
                  for k, v in things.items():
                    new_options += ['-dmo', f'{d}:{k}={v}']
            else:
                for opt in domainMetadataOptions:
                    new_options += ['-dmo', opt]
        if outputSRS is not None:
            new_options += ['-a_srs', str(outputSRS)]
        if nogcp:
            new_options += ['-nogcp']
        if GCPs is not None:
            for gcp in GCPs:
                new_options += ['-gcp', _strHighPrec(gcp.GCPPixel), _strHighPrec(gcp.GCPLine), _strHighPrec(gcp.GCPX), str(gcp.GCPY), _strHighPrec(gcp.GCPZ)]
        if projWin is not None:
            new_options += ['-projwin', _strHighPrec(projWin[0]), _strHighPrec(projWin[1]), _strHighPrec(projWin[2]), _strHighPrec(projWin[3])]
        if projWinSRS is not None:
            new_options += ['-projwin_srs', str(projWinSRS)]
        if noData is not None:
            new_options += ['-a_nodata', _strHighPrec(noData)]
        if rgbExpand is not None:
            new_options += ['-expand', str(rgbExpand)]
        if stats:
            new_options += ['-stats']
        if not rat:
            new_options += ['-norat']
        if not xmp:
            new_options += ['-noxmp']
        if resampleAlg is not None:
            if resampleAlg in mapGRIORAMethodToString:
                new_options += ['-r', mapGRIORAMethodToString[resampleAlg]]
            else:
                new_options += ['-r', str(resampleAlg)]
        if xRes != 0 and yRes != 0:
            new_options += ['-tr', _strHighPrec(xRes), _strHighPrec(yRes)]

        if overviewLevel is None or isinstance(overviewLevel, str):
            pass
        elif isinstance(overviewLevel, int):
            if overviewLevel < 0:
                overviewLevel = 'AUTO' + str(overviewLevel)
            else:
                overviewLevel = str(overviewLevel)
        else:
            overviewLevel = None
        if colorInterpretation is not None:
            def colorInterpAsString(x):
                return GetColorInterpretationName(x) if isinstance(x, int) else x
            if isinstance(colorInterpretation, list):
                new_options += ['-colorinterp', ','.join([colorInterpAsString(x) for x in colorInterpretation])]
            else:
                new_options += ['-colorinterp', colorInterpAsString(colorInterpretation)]

        if overviewLevel is not None and overviewLevel != 'AUTO':
            new_options += ['-ovr', overviewLevel]

        if errorIfWindowOutsideSource is not False:
            if errorIfWindowOutsideSource in ("partially", True):
                new_options.append('-epo')
            elif errorIfWindowOutsideSource == "completely":
                new_options.append('-eco')
            else:
                raise RuntimeError("errorIfWindowOutsideSource must be one of True / 'partially', False, or 'completely'")


    if return_option_list:
        return new_options

    return (GDALTranslateOptions(new_options), callback, callback_data)

def Translate(destName, srcDS, **kwargs):
    """Convert a dataset.

    Parameters
    ----------
    destName : str
        Output dataset name
    srcDS : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.TranslateOptions(), string or array of strings
        other keywords arguments of gdal.TranslateOptions().
        If options is provided as a gdal.TranslateOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    filenamePrefix = ""
    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = TranslateOptions(**kwargs)
        if "format" in kwargs and kwargs["format"].upper() == "ZARR" and "creationOptions" in kwargs:
            for opt in kwargs["creationOptions"]:
                if opt.upper() in ("CONVERT_TO_KERCHUNK_PARQUET_REFERENCE=YES", "CONVERT_TO_KERCHUNK_PARQUET_REFERENCE=ON", "CONVERT_TO_KERCHUNK_PARQUET_REFERENCE=TRUE"):
                    filenamePrefix = "ZARR_DUMMY:"

    else:
        (opts, callback, callback_data) = kwargs['options']

    if isinstance(srcDS, (str, os.PathLike)):
        srcDS = OpenEx(filenamePrefix + str(srcDS), allowed_drivers = allowed_drivers, open_options = open_options)

    return TranslateInternal(destName, srcDS, opts, callback, callback_data)

def WarpOptions(options=None, format=None,
         srcBands=None,
         dstBands=None,
         outputBounds=None,
         outputBoundsSRS=None,
         xRes=None, yRes=None, targetAlignedPixels = False,
         width = 0, height = 0,
         srcSRS=None, dstSRS=None,
         coordinateOperation=None,
         srcAlpha = None, dstAlpha = False,
         warpOptions=None, errorThreshold=None,
         warpMemoryLimit=None, creationOptions=None, outputType = gdalconst.GDT_Unknown,
         workingType = gdalconst.GDT_Unknown, resampleAlg=None,
         srcNodata=None, dstNodata=None, multithread = False,
         tps = False, rpc = False, geoloc = False, polynomialOrder=None,
         transformerOptions=None, cutlineDSName=None,
         cutlineWKT=None,
         cutlineSRS=None,
         cutlineLayer=None, cutlineWhere=None, cutlineSQL=None, cutlineBlend=None, cropToCutline = False,
         copyMetadata = True, metadataConflictValue=None,
         setColorInterpretation = False,
         overviewLevel = 'AUTO',
         callback=None, callback_data=None):
    """Create a WarpOptions() object that can be passed to gdal.Warp()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    format : str
        output format ("GTiff", etc...)
    srcBands : any
        list of source band numbers (between 1 and the number of input bands)
    dstBands : any
        list of output band numbers
    outputBounds : any
        output bounds as (minX, minY, maxX, maxY) in target SRS
    outputBoundsSRS : any
        SRS in which output bounds are expressed, in the case they are not expressed in dstSRS
    xRes : any
        output resolution in target SRS
    yRes : any
        output resolution in target SRS
    targetAlignedPixels : any
        whether to force output bounds to be multiple of output resolution
    width : int
        width of the output raster in pixel
    height : int
        height of the output raster in pixel
    srcSRS : any
        source SRS
    dstSRS : any
        output SRS
    coordinateOperation : any
        coordinate operation as a PROJ string or WKT string
    srcAlpha : any
        whether to force the last band of the input dataset to be considered as an alpha band.
        If set to False, source alpha warping will be disabled.
    dstAlpha : any
        whether to force the creation of an output alpha band
    outputType : any
        output type (gdalconst.GDT_Byte, etc...)
    workingType : any
        working type (gdalconst.GDT_Byte, etc...)
    warpOptions : any
        list or dict of warping options. For a list of available options, see :cpp:member:`GDALWarpOptions::papszWarpOptions`.
    errorThreshold : any
        error threshold for approximation transformer (in pixels)
    warpMemoryLimit : any
        size of working buffer in MB
    resampleAlg : any
        resampling mode
    creationOptions : list or dict
        list or dict of creation options
    srcNodata : any
        source nodata value(s)
    dstNodata : any
        output nodata value(s)
    multithread : any
        whether to multithread computation and I/O operations
    tps : any
        whether to use Thin Plate Spline GCP transformer
    rpc : any
        whether to use RPC transformer
    geoloc : any
        whether to use GeoLocation array transformer
    polynomialOrder : any
        order of polynomial GCP interpolation
    transformerOptions : any
        list or dict of transformer options
    cutlineDSName : any
        cutline dataset name (mutually exclusive with cutlineWKT)
    cutlineWKT : any
        cutline WKT geometry (POLYGON or MULTIPOLYGON) (mutually exclusive with cutlineDSName)
    cutlineSRS : any
        set/override cutline SRS
    cutlineLayer : any
        cutline layer name
    cutlineWhere : any
        cutline WHERE clause
    cutlineSQL : any
        cutline SQL statement
    cutlineBlend : any
        cutline blend distance in pixels
    cropToCutline : any
        whether to use cutline extent for output bounds
    copyMetadata : any
        whether to copy source metadata
    metadataConflictValue : any
        metadata data conflict value
    setColorInterpretation : any
        whether to force color interpretation of input bands to output bands
    overviewLevel : any
        To specify which overview level of source files must be used
    callback : any
        callback method
    callback_data : any
        user data for callback
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'
    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if srcBands:
            for b in srcBands:
                new_options += ['-srcband', str(b)]
        if dstBands:
            for b in dstBands:
                new_options += ['-dstband', str(b)]
        if format is not None:
            new_options += ['-of', format]
        if outputType != gdalconst.GDT_Unknown:
            new_options += ['-ot', GetDataTypeName(outputType)]
        if workingType != gdalconst.GDT_Unknown:
            new_options += ['-wt', GetDataTypeName(workingType)]
        if outputBounds is not None:
            new_options += ['-te', _strHighPrec(outputBounds[0]), _strHighPrec(outputBounds[1]), _strHighPrec(outputBounds[2]), _strHighPrec(outputBounds[3])]
        if outputBoundsSRS is not None:
            new_options += ['-te_srs', str(outputBoundsSRS)]
        if xRes is not None and yRes is not None:
            new_options += ['-tr', _strHighPrec(xRes), _strHighPrec(yRes)]
        if width != 0 or height != 0:
            new_options += ['-ts', str(width), str(height)]
        if srcSRS is not None:
            new_options += ['-s_srs', str(srcSRS)]
        if dstSRS is not None:
            new_options += ['-t_srs', str(dstSRS)]
        if coordinateOperation is not None:
            new_options += ['-ct', coordinateOperation]
        if targetAlignedPixels:
            new_options += ['-tap']
        if srcAlpha:
            new_options += ['-srcalpha']
        elif srcAlpha is not None:
            new_options += ['-nosrcalpha']
        if dstAlpha:
            new_options += ['-dstalpha']
        if warpOptions is not None:
            _addOptions(new_options, '-wo', warpOptions)
        if errorThreshold is not None:
            new_options += ['-et', _strHighPrec(errorThreshold)]
        if resampleAlg is not None:

            mapMethodToString = {
                gdalconst.GRA_NearestNeighbour: 'near',
                gdalconst.GRA_Bilinear: 'bilinear',
                gdalconst.GRA_Cubic: 'cubic',
                gdalconst.GRA_CubicSpline: 'cubicspline',
                gdalconst.GRA_Lanczos: 'lanczos',
                gdalconst.GRA_Average: 'average',
                gdalconst.GRA_RMS: 'rms',
                gdalconst.GRA_Mode: 'mode',
                gdalconst.GRA_Max: 'max',
                gdalconst.GRA_Min: 'min',
                gdalconst.GRA_Med: 'med',
                gdalconst.GRA_Q1: 'q1',
                gdalconst.GRA_Q3: 'q3',
                gdalconst.GRA_Sum: 'sum',
            }

            if resampleAlg in mapMethodToString:
                new_options += ['-r', mapMethodToString[resampleAlg]]
            else:
                new_options += ['-r', str(resampleAlg)]
        if warpMemoryLimit is not None:
            new_options += ['-wm', str(warpMemoryLimit)]
        if creationOptions is not None:
            _addCreationOptions(new_options, creationOptions)
        if srcNodata is not None:
            new_options += ['-srcnodata', str(srcNodata)]
        if dstNodata is not None:
            new_options += ['-dstnodata', str(dstNodata)]
        if multithread:
            new_options += ['-multi']
        if tps:
            new_options += ['-tps']
        if rpc:
            new_options += ['-rpc']
        if geoloc:
            new_options += ['-geoloc']
        if polynomialOrder is not None:
            new_options += ['-order', str(polynomialOrder)]
        if transformerOptions is not None:
            _addOptions(new_options, '-to', transformerOptions)
        if cutlineDSName is not None:
            if cutlineWKT is not None:
                raise Exception("cutlineDSName and cutlineWKT are mutually exclusive")
            new_options += ['-cutline', str(cutlineDSName)]
        if cutlineWKT is not None:
            new_options += ['-cutline', str(cutlineWKT)]
        if cutlineSRS is not None:
            new_options += ['-cutline_srs', str(cutlineSRS)]
        if cutlineLayer is not None:
            new_options += ['-cl', str(cutlineLayer)]
        if cutlineWhere is not None:
            new_options += ['-cwhere', str(cutlineWhere)]
        if cutlineSQL is not None:
            new_options += ['-csql', str(cutlineSQL)]
        if cutlineBlend is not None:
            new_options += ['-cblend', str(cutlineBlend)]
        if cropToCutline:
            new_options += ['-crop_to_cutline']
        if not copyMetadata:
            new_options += ['-nomd']
        if metadataConflictValue:
            new_options += ['-cvmd', str(metadataConflictValue)]
        if setColorInterpretation:
            new_options += ['-setci']

        if overviewLevel is None or isinstance(overviewLevel, str):
            pass
        elif isinstance(overviewLevel, int):
            if overviewLevel < 0:
                overviewLevel = 'AUTO' + str(overviewLevel)
            else:
                overviewLevel = str(overviewLevel)
        else:
            overviewLevel = None

        if overviewLevel is not None and overviewLevel != 'AUTO':
            new_options += ['-ovr', overviewLevel]

    if return_option_list:
        return new_options

    return (GDALWarpAppOptions(new_options), callback, callback_data)

def Warp(destNameOrDestDS, srcDSOrSrcDSTab, **kwargs):
    """Warp one or several datasets.

    Parameters
    ----------
    destNameOrDestDS : any
        Output dataset name or object.

        If passed as a dataset name, a potentially existing output dataset of
        the same name will be overwritten. To update an existing output dataset,
        it must be passed as a dataset object.

    srcDSOrSrcDSTab : any
        an array of Dataset objects or filenames, or a Dataset object or a filename
    **kwargs : any
        options: return of gdal.WarpOptions(), string or array of strings,
        other keywords arguments of gdal.WarpOptions().
        If options is provided as a gdal.WarpOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = WarpOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    if isinstance(srcDSOrSrcDSTab, (str, os.PathLike)):
        srcDSTab = [OpenEx(srcDSOrSrcDSTab, allowed_drivers = allowed_drivers, open_options = open_options)]
    elif isinstance(srcDSOrSrcDSTab, list):
        srcDSTab = []
        for elt in srcDSOrSrcDSTab:
            if isinstance(elt, (str, os.PathLike)):
                srcDSTab.append(OpenEx(elt, allowed_drivers = allowed_drivers, open_options = open_options))
            else:
                srcDSTab.append(elt)
    else:
        srcDSTab = [srcDSOrSrcDSTab]

    if isinstance(destNameOrDestDS, (str, os.PathLike)):
        return wrapper_GDALWarpDestName(destNameOrDestDS, srcDSTab, opts, callback, callback_data)
    else:
        return wrapper_GDALWarpDestDS(destNameOrDestDS, srcDSTab, opts, callback, callback_data)


def VectorTranslateOptions(options=None, format=None,
         accessMode=None,
         srcSRS=None, dstSRS=None, reproject=True,
         coordinateOperation=None,
         coordinateOperationOptions=None,
         SQLStatement=None, SQLDialect=None, where=None, selectFields=None,
         addFields=False,
         relaxedFieldNameMatch=False,
         forceNullable=False,
         emptyStrAsNull=False,
         spatFilter=None, spatSRS=None,
         datasetCreationOptions=None,
         layerCreationOptions=None,
         layers=None,
         layerName=None,
         geometryType=None,
         dim=None,
         transactionSize=None,
         clipSrc=None,
         clipSrcSQL=None,
         clipSrcLayer=None,
         clipSrcWhere=None,
         clipDst=None,
         clipDstSQL=None,
         clipDstLayer=None,
         clipDstWhere=None,
         preserveFID=False,
         simplifyTolerance=None,
         segmentizeMaxDist=None,
         makeValid=False,
         skipInvalid=False,
         mapFieldType=None,
         explodeCollections=False,
         zField=None,
         resolveDomains=False,
         skipFailures=False,
         limit=None,
         xyRes=None,
         zRes=None,
         mRes=None,
         setCoordPrecision=True,
         quiet=False,
         callback=None, callback_data=None):
    """
    Create a VectorTranslateOptions() object that can be passed to
    gdal.VectorTranslate()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other
        keywords.
    format : str
        format ("ESRI Shapefile", etc...)
    accessMode : any
        None for creation, 'update', 'append', 'upsert', 'overwrite'
    srcSRS : any
        source SRS
    dstSRS : any
        output SRS (with reprojection if reproject = True)
    coordinateOperation : any
        coordinate operation as a PROJ string or WKT string
    coordinateOperationOptions : any
        list or dict of coordinate operation options (ALLOW_BALLPARK=NO, ONLY_BEST=YES, WARN_ABOUT_DIFFERENT_COORD_OP=NO)
    reproject : any
        whether to do reprojection
    SQLStatement : any
        SQL statement to apply to the source dataset
    SQLDialect : any
        SQL dialect ('OGRSQL', 'SQLITE', ...)
    where : any
        WHERE clause to apply to source layer(s)
    selectFields : any
        list of fields to select
    addFields : any
        whether to add new fields found in source layers (to be used with
        accessMode == 'append' or 'upsert')
    relaxedFieldNameMatch : any
        Do field name matching between source and existing target layer in a more relaxed way if the target driver has an implementation for it.
    forceNullable : any
        whether to drop NOT NULL constraints on newly created fields
    emptyStrAsNull : any
        whether to treat empty string values as NULL
    spatFilter : any
        spatial filter as (minX, minY, maxX, maxY) bounding box
    spatSRS : any
        SRS in which the spatFilter is expressed. If not specified, it is assumed to be
        the one of the layer(s)
    datasetCreationOptions : any
        list or dict of dataset creation options
    layerCreationOptions : any
        list or dict of layer creation options
    layers : any
        list of layers to convert
    layerName : any
        output layer name
    geometryType : any
        output layer geometry type ('POINT', ....). May be an array of strings
        when using a special value like 'PROMOTE_TO_MULTI', 'CONVERT_TO_LINEAR',
        'CONVERT_TO_CURVE' combined with another one or a geometry type.
    dim : any
        output dimension ('XY', 'XYZ', 'XYM', 'XYZM', 'layer_dim')
    transactionSize : any
        number of features to save per transaction (default 100 000). Increase the value
        for better performance when writing into DBMS drivers that have transaction
        support. Set to "unlimited" to load the data into a single transaction.
    clipSrc : any
        clip geometries to the specified bounding box (expressed in source SRS),
        WKT geometry (POLYGON or MULTIPOLYGON), from a datasource or to the spatial
        extent of the -spat option if you use the "spat_extent" keyword. When
        specifying a datasource, you will generally want to use it in combination with
        the clipSrcLayer, clipSrcWhere or clipSrcSQL options.
    clipSrcSQL : any
        select desired geometries using an SQL query instead.
    clipSrcLayer : any
        select the named layer from the source clip datasource.
    clipSrcWhere : any
        restrict desired geometries based on attribute query.
    clipDst : any
        clip geometries after reprojection to the specified bounding box (expressed in
        dest SRS), WKT geometry (POLYGON or MULTIPOLYGON) or from a datasource. When
        specifying a datasource, you will generally want to use it in combination of
        the clipDstLayer, clipDstWhere or clipDstSQL options.
    clipDstSQL : any
        select desired geometries using an SQL query instead.
    clipDstLayer : any
        select the named layer from the destination clip datasource.
    clipDstWhere : any
        restrict desired geometries based on attribute query.
    simplifyTolerance : any
        distance tolerance for simplification. The algorithm used preserves topology per
        feature, in particular for polygon geometries, but not for a whole layer.
    segmentizeMaxDist : any
        maximum distance between consecutive nodes of a line geometry
    makeValid : any
        run MakeValid() on geometries
    skipInvalid : any
        whether to skip features with invalid geometries regarding the rules of
        the Simple Features specification.
    mapFieldType : any
        converts any field of the specified type to another type. Valid types are:
        Integer, Integer64, Real, String, Date, Time, DateTime, Binary, IntegerList,
        Integer64List, RealList, StringList. Types can also include subtype between
        parenthesis, such as Integer(Boolean), Real(Float32),... Special value All can
        be used to convert all fields to another type. This is an alternate way to using
        the CAST operator of OGR SQL, that may avoid typing a long SQL query.
        Note that this does not influence the field types used by the source driver,
        and is only an afterwards conversion.
    explodeCollections : any
        produce one feature for each geometry in any kind of geometry collection in the
        source file, applied after any -sql option. This option is not compatible with
        preserveFID but a SQLStatement (e.g. SELECT fid AS original_fid, * FROM ...)
        can be used to store the original FID if needed.
    preserveFID : any
        Use the FID of the source features instead of letting the output driver automatically
        assign a new one (for formats that require a FID). If not in append mode, this behavior
        is the default if the output driver has a FID  layer  creation  option,  in which case
        the name of the source FID column will be used and source feature IDs will be attempted
        to be preserved. This behavior can be disabled by setting -unsetFid.
        This option is not compatible with explodeCollections
    zField : any
        name of field to use to set the Z component of geometries
    resolveDomains : any
        whether to create an additional field for each field associated with a coded
        field domain.
    skipFailures : any
        whether to skip failures
    limit : int
        maximum number of features to read per layer
    xyRes : any
        Geometry X,Y coordinate resolution. Numeric value, or numeric value suffixed with " m", " mm" or "deg".
    zRes : any
        Geometry Z coordinate resolution. Numeric value, or numeric value suffixed with " m" or " mm".
    mRes : any
        Geometry M coordinate resolution. Numeric value.
    setCoordPrecision : any
        Set to False to unset the geometry coordinate precision.
    quiet: bool
        Whether to suppress some warnings
    callback : any
        callback method
    callback_data : any
        user data for callback
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'
    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if format is not None:
            new_options += ['-f', format]
        if srcSRS is not None:
            new_options += ['-s_srs', str(srcSRS)]
        if dstSRS is not None:
            if reproject:
                new_options += ['-t_srs', str(dstSRS)]
            else:
                new_options += ['-a_srs', str(dstSRS)]
        if coordinateOperation is not None:
            new_options += ['-ct', coordinateOperation]

        if coordinateOperationOptions is not None:
            _addOptions(new_options,'-ct_opt', coordinateOperationOptions)
        if SQLStatement is not None:
            new_options += ['-sql', str(SQLStatement)]
        if SQLDialect is not None:
            new_options += ['-dialect', str(SQLDialect)]
        if where is not None:
            new_options += ['-where', str(where)]
        if accessMode is not None:
            if accessMode == 'update':
                new_options += ['-update']
            elif accessMode == 'append':
                new_options += ['-append']
            elif accessMode == 'overwrite':
                new_options += ['-overwrite']
            elif accessMode == 'upsert':
                new_options += ['-upsert']
            else:
                raise Exception('unhandled accessMode')
        if addFields:
            new_options += ['-addfields']
        if relaxedFieldNameMatch:
            new_options += ['-relaxedFieldNameMatch']
        if forceNullable:
            new_options += ['-forceNullable']
        if emptyStrAsNull:
            new_options += ['-emptyStrAsNull']
        if selectFields is not None:
            val = ''
            for item in selectFields:
                if val:
                    val += ','
                if ',' in item or ' ' in item or '"' in item:
                    val += '"' + item.replace('"', '\\"') + '"'
                else:
                    val += item
            new_options += ['-select', val]

        if datasetCreationOptions is not None:
            _addOptions(new_options, '-dsco', datasetCreationOptions)

        if layerCreationOptions is not None:
            _addOptions(new_options, '-lco', layerCreationOptions)

        if layers is not None:
            if isinstance(layers, str):
                new_options += [layers]
            else:
                for lyr in layers:
                    new_options += [lyr]

        if transactionSize is not None:
            new_options += ['-gt', str(transactionSize)]

        if clipSrc is not None:
            import os

            new_options += ['-clipsrc']
            if isinstance(clipSrc, str):
                new_options += [clipSrc]
            elif isinstance(clipSrc, os.PathLike):
                new_options += [str(clipSrc)]
            else:
                try:
                    new_options += [
                        str(clipSrc[0]),
                        str(clipSrc[1]),
                        str(clipSrc[2]),
                        str(clipSrc[3])
                    ]
                except Exception as ex:
                    raise ValueError(f"invalid value for clipSrc: {clipSrc}") from ex
        if clipSrcSQL is not None:
            new_options += ['-clipsrcsql', str(clipSrcSQL)]
        if clipSrcLayer is not None:
            new_options += ['-clipsrclayer', str(clipSrcLayer)]
        if clipSrcWhere is not None:
            new_options += ['-clipsrcwhere', str(clipSrcWhere)]

        if clipDst is not None:
            import os

            new_options += ['-clipdst']
            if isinstance(clipDst, str):
                new_options += [clipDst]
            elif isinstance(clipDst, os.PathLike):
                new_options += [str(clipDst)]
            else:
                try:
                    new_options += [
                        str(clipDst[0]),
                        str(clipDst[1]),
                        str(clipDst[2]),
                        str(clipDst[3])
                    ]
                except Exception as ex:
                    raise ValueError(f"invalid value for clipDst: {clipDst}") from ex
        if clipDstSQL is not None:
            new_options += ['-clipdstsql', str(clipDstSQL)]
        if clipDstLayer is not None:
            new_options += ['-clipdstlayer', str(clipDstLayer)]
        if clipDstWhere is not None:
            new_options += ['-clipdstwhere', str(clipDstWhere)]

        if simplifyTolerance is not None:
            new_options += ['-simplify', str(simplifyTolerance)]
        if segmentizeMaxDist is not None:
            new_options += ['-segmentize', str(segmentizeMaxDist)]
        if makeValid:
            new_options += ['-makevalid']
        if skipInvalid:
            new_options += ['-skipinvalid']
        if mapFieldType is not None:
            new_options += ['-mapFieldType']
            if isinstance(mapFieldType, str):
                new_options += [mapFieldType]
            else:
                new_options += [",".join(mapFieldType)]
        if explodeCollections:
            new_options += ['-explodecollections']
        if preserveFID:
            new_options += ['-preserve_fid']
        if spatFilter is not None:
            new_options += [
                '-spat',
                str(spatFilter[0]),
                str(spatFilter[1]),
                str(spatFilter[2]),
                str(spatFilter[3])
            ]
        if spatSRS is not None:
            new_options += ['-spat_srs', str(spatSRS)]
        if layerName is not None:
            new_options += ['-nln', layerName]
        if geometryType is not None:
            if isinstance(geometryType, str):
                new_options += ['-nlt', geometryType]
            else:
                for opt in geometryType:
                    new_options += ['-nlt', opt]
        if dim is not None:
            new_options += ['-dim', dim]
        if zField is not None:
            new_options += ['-zfield', zField]
        if resolveDomains:
            new_options += ['-resolveDomains']
        if skipFailures:
            new_options += ['-skip']
        if limit is not None:
            new_options += ['-limit', str(limit)]
        if xyRes is not None:
            new_options += ['-xyRes', str(xyRes)]
        if zRes is not None:
            new_options += ['-zRes', str(zRes)]
        if mRes is not None:
            new_options += ['-mRes', str(mRes)]
        if setCoordPrecision is False:
            new_options += ["-unsetCoordPrecision"]
        if quiet:
            new_options += ["--quiet"]

    if callback is not None:
        new_options += ['-progress']

    if return_option_list:
        return new_options

    return (GDALVectorTranslateOptions(new_options), callback, callback_data)


def VectorTranslate(destNameOrDestDS, srcDS, **kwargs):
    """Convert one vector dataset

    Parameters
    ----------
    destNameOrDestDS : any
        Output dataset name or object

        If passed as a dataset name, a potentially existing output dataset of
        the same name will be overwritten. To update an existing output dataset,
        it must be passed as a dataset object. Note that the accessMode parameter
        also controls, at the layer level, if existing layers must be overwritten
        or updated.

    srcDS : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.VectorTranslateOptions(), string or array of strings,
        other keywords arguments of gdal.VectorTranslateOptions().
        If options is provided as a gdal.VectorTranslateOptions() object,
        other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = VectorTranslateOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    if isinstance(srcDS, (str, os.PathLike)):
        srcDS = OpenEx(srcDS, gdalconst.OF_VECTOR, allowed_drivers = allowed_drivers, open_options = open_options)

    if isinstance(destNameOrDestDS, (str, os.PathLike)):
        return wrapper_GDALVectorTranslateDestName(destNameOrDestDS, srcDS, opts, callback, callback_data)
    else:
        return wrapper_GDALVectorTranslateDestDS(destNameOrDestDS, srcDS, opts, callback, callback_data)

def DEMProcessingOptions(options=None, colorFilename=None, format=None,
              creationOptions=None, computeEdges=False, alg=None, band=1,
              zFactor=None, scale=None, xscale=None, yscale=None, azimuth=None, altitude=None,
              combined=False, multiDirectional=False, igor=False,
              slopeFormat=None, trigonometric=False, zeroForFlat=False,
              addAlpha=None, colorSelection=None,
              callback=None, callback_data=None):
    """Create a DEMProcessingOptions() object that can be passed to gdal.DEMProcessing()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    colorFilename : any
        (mandatory for "color-relief") name of file that contains palette definition for the "color-relief" processing.
    format : any
        output format ("GTiff", etc...)
    creationOptions : any
        list or dict of creation options
    computeEdges : any
        whether to compute values at raster edges.
    alg : any
        'Horn' (default) or 'ZevenbergenThorne' for hillshade, slope or aspect. 'Wilson' (default) or 'Riley' for TRI
    band : any
        source band number to use
    zFactor : any
        (hillshade only) vertical exaggeration used to pre-multiply the elevations.
    scale : any
        ratio of vertical units to horizontal.
    xscale : any
        Ratio of vertical units to horizontal X axis units.
    yscale : any
        Ratio of vertical units to horizontal Y axis units.
    azimuth : any
        (hillshade only) azimuth of the light, in degrees. 0 if it comes from the top of the raster, 90 from the east, ... The default value, 315, should rarely be changed as it is the value generally used to generate shaded maps.
    altitude : any
        (hillshade only) altitude of the light, in degrees. 90 if the light comes from above the DEM, 0 if it is raking light.
    combined : any
        (hillshade only) whether to compute combined shading, a combination of slope and oblique shading. Only one of combined, multiDirectional and igor can be specified.
    multiDirectional : any
        (hillshade only) whether to compute multi-directional shading. Only one of combined, multiDirectional and igor can be specified.
    igor : any
        (hillshade only) whether to use Igor's hillshading from Maperitive.  Only one of combined, multiDirectional and igor can be specified.
    slopeFormat : any
        (slope only) "degree" or "percent".
    trigonometric : any
        (aspect only) whether to return trigonometric angle instead of azimuth. Thus 0deg means East, 90deg North, 180deg West, 270deg South.
    zeroForFlat : any
        (aspect only) whether to return 0 for flat areas with slope=0, instead of -9999.
    addAlpha : any
        adds an alpha band to the output file (only for processing = 'color-relief')
    colorSelection : any
        (color-relief only) Determines how color entries are selected from an input value. Can be "nearest_color_entry", "exact_color_entry" or "linear_interpolation". Defaults to "linear_interpolation"
    callback : any
        callback method
    callback_data : any
        user data for callback
    """
# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'
    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if format is not None:
            new_options += ['-of', format]
        if creationOptions is not None:
            _addCreationOptions(new_options, creationOptions)
        if computeEdges:
            new_options += ['-compute_edges']
        if alg:
            new_options += ['-alg', alg]
        new_options += ['-b', str(band)]
        if zFactor is not None:
            new_options += ['-z', str(zFactor)]
        if scale is not None:
            new_options += ['-s', str(scale)]
        if xscale is not None:
            new_options += ['-xscale', str(xscale)]
        if yscale is not None:
            new_options += ['-yscale', str(yscale)]
        if azimuth is not None:
            new_options += ['-az', str(azimuth)]
        if altitude is not None:
            new_options += ['-alt', str(altitude)]
        if combined:
            new_options += ['-combined']
        if multiDirectional:
            new_options += ['-multidirectional']
        if igor:
            new_options += ['-igor']
        if slopeFormat == 'percent':
            new_options += ['-p']
        if trigonometric:
            new_options += ['-trigonometric']
        if zeroForFlat:
            new_options += ['-zero_for_flat']
        if colorSelection is not None:
            if colorSelection == 'nearest_color_entry':
                new_options += ['-nearest_color_entry']
            elif colorSelection == 'exact_color_entry':
                new_options += ['-exact_color_entry']
            elif colorSelection == 'linear_interpolation':
                pass
            else:
                raise ValueError("Unsupported value for colorSelection")
        if addAlpha:
            new_options += ['-alpha']

    if return_option_list:
        return new_options

    return (GDALDEMProcessingOptions(new_options), colorFilename, callback, callback_data)

def DEMProcessing(destName, srcDS, processing, **kwargs):
    """Apply a DEM processing.

    Parameters
    ----------
    destName : any
        Output dataset name
    srcDS : any
        a Dataset object or a filename
    processing : any
        one of "hillshade", "slope", "aspect", "color-relief", "TRI", "TPI", "Roughness"
    **kwargs : any
        options: return of gdal.DEMProcessingOptions(), string or array of strings,
        other keywords arguments of gdal.DEMProcessingOptions().
        If options is provided as a gdal.DEMProcessingOptions() object,
        other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, colorFilename, callback, callback_data) = DEMProcessingOptions(**kwargs)
    else:
        (opts, colorFilename, callback, callback_data) = kwargs['options']

    if isinstance(srcDS, (str, os.PathLike)):
        srcDS = Open(srcDS)

    if isinstance(colorFilename, os.PathLike):
        colorFilename = str(colorFilename)

    return DEMProcessingInternal(destName, srcDS, processing, colorFilename, opts, callback, callback_data)


def NearblackOptions(options=None, format=None,
         creationOptions=None, white = False, colors=None,
         maxNonBlack=None, nearDist=None, setAlpha = False, setMask = False,
         alg=None,
         callback=None, callback_data=None):
    """Create a NearblackOptions() object that can be passed to gdal.Nearblack()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    format : any
        output format ("GTiff", etc...)
    creationOptions : any
        list or dict of creation options
    white : any
        whether to search for nearly white (255) pixels instead of nearly black pixels.
    colors : any
        list of colors  to search for, e.g. ((0,0,0),(255,255,255)). The pixels that are considered as the collar are set to 0
    maxNonBlack : any
        number of non-black (or other searched colors specified with white / colors) pixels that can be encountered before the giving up search inwards. Defaults to 2.
    nearDist : any
        select how far from black, white or custom colors the pixel values can be and still considered near black, white or custom color.  Defaults to 15.
    setAlpha : any
        adds an alpha band to the output file.
    setMask : any
        adds a mask band to the output file.
    alg : any
        "twopasses" (default), or "floodfill"
    callback : any
        callback method
    callback_data : any
        user data for callback
    """
# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'
    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if format is not None:
            new_options += ['-of', format]
        if creationOptions is not None:
            _addCreationOptions(new_options, creationOptions)
        if white:
            new_options += ['-white']
        if colors is not None:
            for color in colors:
                color_str = ''
                for cpt in color:
                    if color_str != '':
                        color_str += ','
                    color_str += str(cpt)
                new_options += ['-color', color_str]
        if maxNonBlack is not None:
            new_options += ['-nb', str(maxNonBlack)]
        if nearDist is not None:
            new_options += ['-near', str(nearDist)]
        if setAlpha:
            new_options += ['-setalpha']
        if setMask:
            new_options += ['-setmask']
        if alg:
            new_options += ['-alg', alg]

    if return_option_list:
        return new_options

    return (GDALNearblackOptions(new_options), callback, callback_data)

def Nearblack(destNameOrDestDS, srcDS, **kwargs):
    """Convert nearly black/white borders to exact value.

    Parameters
    ----------
    destNameOrDestDS : any
        Output dataset name or object

        If passed as a dataset name, a potentially existing output dataset of
        the same name will be overwritten. To update an existing output dataset,
        it must be passed as a dataset object.

    srcDS : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.NearblackOptions(), string or array of strings,
        other keywords arguments of gdal.NearblackOptions().
        If options is provided as a gdal.NearblackOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = NearblackOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    if isinstance(srcDS, (str, os.PathLike)):
        srcDS = OpenEx(srcDS, allowed_drivers = allowed_drivers, open_options = open_options)

    if isinstance(destNameOrDestDS, (str, os.PathLike)):
        return wrapper_GDALNearblackDestName(destNameOrDestDS, srcDS, opts, callback, callback_data)
    else:
        return wrapper_GDALNearblackDestDS(destNameOrDestDS, srcDS, opts, callback, callback_data)


def GridOptions(options=None, format=None,
              outputType=gdalconst.GDT_Unknown,
              width=0, height=0,
              creationOptions=None,
              outputBounds=None,
              outputSRS=None,
              noData=None,
              algorithm=None,
              layers=None,
              SQLStatement=None,
              where=None,
              spatFilter=None,
              zfield=None,
              z_increase=None,
              z_multiply=None,
              callback=None, callback_data=None):
    """ Create a GridOptions() object that can be passed to gdal.Grid()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    format : any
        output format ("GTiff", etc...)
    outputType : any
        output type (gdalconst.GDT_Byte, etc...)
    width : any
        width of the output raster in pixel
    height : any
        height of the output raster in pixel
    creationOptions : any
        list or dict of creation options
    outputBounds : any
        assigned output bounds:
        [ulx, uly, lrx, lry]
    outputSRS : any
        assigned output SRS
    noData : any
        nodata value
    algorithm : any
        e.g "invdist:power=2.0:smoothing=0.0:radius1=0.0:radius2=0.0:angle=0.0:max_points=0:min_points=0:nodata=0.0"
    layers : any
        list of layers to convert
    SQLStatement : any
        SQL statement to apply to the source dataset
    where : any
        WHERE clause to apply to source layer(s)
    spatFilter : any
        spatial filter as (minX, minY, maxX, maxY) bounding box
    zfield : any
        Identifies an attribute field on the features to be used to get a Z value from.
        This value overrides Z value read from feature geometry record.
    z_increase : any
        Addition to the attribute field on the features to be used to get a Z value from.
        The addition should be the same unit as Z value. The result value will be
        Z value + Z increase value. The default value is 0.
    z_multiply : any
        Multiplication ratio for Z field. This can be used for shift from e.g. foot to meters
        or from  elevation to deep. The result value will be
        (Z value + Z increase value) * Z multiply value. The default value is 1.
    callback : any
        callback method
    callback_data : any
        user data for callback
    """
# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'

    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if format is not None:
            new_options += ['-of', format]
        if outputType != gdalconst.GDT_Unknown:
            new_options += ['-ot', GetDataTypeName(outputType)]
        if width != 0 or height != 0:
            new_options += ['-outsize', str(width), str(height)]
        if creationOptions is not None:
            _addCreationOptions(new_options, creationOptions)
        if outputBounds is not None:
            new_options += ['-txe', _strHighPrec(outputBounds[0]), _strHighPrec(outputBounds[2]), '-tye', _strHighPrec(outputBounds[1]), _strHighPrec(outputBounds[3])]
        if outputSRS is not None:
            new_options += ['-a_srs', str(outputSRS)]
        if algorithm is not None:
            new_options += ['-a', algorithm]
        if layers is not None:
            if isinstance(layers, (tuple, list)):
                for layer in layers:
                    new_options += ['-l', layer]
            else:
                new_options += ['-l', layers]
        if SQLStatement is not None:
            new_options += ['-sql', str(SQLStatement)]
        if where is not None:
            new_options += ['-where', str(where)]
        if zfield is not None:
            new_options += ['-zfield', zfield]
        if z_increase is not None:
            new_options += ['-z_increase', str(z_increase)]
        if z_multiply is not None:
            new_options += ['-z_multiply', str(z_multiply)]
        if spatFilter is not None:
            new_options += ['-spat', str(spatFilter[0]), str(spatFilter[1]), str(spatFilter[2]), str(spatFilter[3])]

    if return_option_list:
        return new_options

    return (GDALGridOptions(new_options), callback, callback_data)

def Grid(destName, srcDS, **kwargs):
    """ Create raster from the scattered data.

    Parameters
    ----------
    destName : any
        Output dataset name
    srcDS : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.GridOptions(), string or array of strings,
        other keywords arguments of gdal.GridOptions()
        If options is provided as a gdal.GridOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = GridOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    if isinstance(srcDS, (str, os.PathLike)):
        srcDS = OpenEx(srcDS, gdalconst.OF_VECTOR, allowed_drivers = allowed_drivers, open_options = open_options)

    return GridInternal(destName, srcDS, opts, callback, callback_data)

def ContourOptions(
    options=None,
    format=None,
    band=1,
    elevationName=None,
    minName=None,
    maxName=None,
    with3d=False,
    srcNodata=None,
    offset=None,
    datasetCreationOptions=None,
    layerCreationOptions=None,
    interval=None,
    fixedLevels=None,
    exponentialBase=None,
    layerName="contour",
    polygonize=False,
    groupTransactions=100000,
    callback=None,
    callback_data=None):
    """Create a ContourOptions() object that can be passed to gdal.Contour()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    format : any
        output format ("ESRI Shapefile", etc...)
    band : any
        band number to use (default = 1)
    elevationName : any
        name of the attribute in which to put the elevation.
        If not provided no elevation attribute is attached.
        Ignored in polygonal contouring (polygonize) mode.
    minName : any
        name for the attribute in which to put the minimum elevation of contour polygon.
        If not provided no minimum elevation attribute is attached.
        Ignored in default line contouring mode.
    maxName : any
        name for the attribute in which to put the maximum elevation of contour polygon.
        If not provided no maximum elevation attribute is attached.
        Ignored in default line contouring mode.
    with3d : any
        Force production of 3D vectors instead of 2D. Includes elevation at every vertex.
    srcNodata : any
        Input pixel value to treat as "nodata".
    offset : any
        Offset to apply to the elevation values.
    datasetCreationOptions : any
        List or dict of dataset creation options.
    layerCreationOptions : any
        List or dict of layer creation options.
    interval : any
        Elevation interval between contours. Must specify either "interval" or "fixedLevels" or "exponentialBase".
    fixedLevels : any
        Name one or more "fixed levels" to extract. Must specify either "interval" or "fixedLevels" or "exponentialBase".
    exponentialBase : any
        Generate levels on an exponential scale: base ^ k, for k an integer. Must specify either. Must specify either "interval" or "fixedLevels" or "exponentialBase".
    layerName : any
        Name for the output vector layer, defaults to "contour".
    polygonize : any
        Produce polygons instead of lines (default = False).
    groupTransactions : any
        Group n features per transaction (default 100 000). Increase the value for better performance when writing into
        DBMS drivers that have transaction support. n can be set to unlimited to load the data into a single transaction.
        If set to 0, no explicit transaction is done.
    callback : any
        Callback method.
    callback_data : any
        User data for callback.
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'

    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)

        if format is not None:
            new_options += ['-of', format]
        if elevationName is not None:
            new_options += ['-a', elevationName]
        if minName is not None:
            new_options += ['-amin', minName]
        if maxName is not None:
            new_options += ['-amax', maxName]
        if with3d:
            new_options += ['-3d']
        if srcNodata is not None:
            new_options += ['-snodata', str(srcNodata)]
        if offset is not None:
            new_options += ['-off', str(offset)]
        if datasetCreationOptions is not None:
            _addOptions(new_options, '-dsco', datasetCreationOptions)

        if layerCreationOptions is not None:
            _addOptions(new_options, '-lco', layerCreationOptions)

        if interval is not None:
            new_options += ['-i', str(interval)]
        if fixedLevels is not None:
            for level in fixedLevels:
                new_options += ['-fl', str(level)]
        if exponentialBase is not None:
            new_options += ['-e', str(exponentialBase)]
        if layerName is not None:
            new_options += ['-nln', layerName]
        if polygonize:
            new_options += ['-p']
        if groupTransactions is not None:
            new_options += ['-gt', str(groupTransactions)]

    if return_option_list:
        return new_options

    return (GDALContourOptions(new_options), callback, callback_data)


def Contour(destNameOrDestDS, srcDS, **kwargs):
    """Create contour lines or polygons from raster data.

    Parameters
    ----------
    destNameOrDestDS : any
        Output dataset name or object

        If passed as a dataset name, a potentially existing output dataset of
        the same name will be overwritten. To update an existing output dataset,
        it must be passed as a dataset object.

    srcDS : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.ContourOptions(), string or array of strings,
        other keywords arguments of gdal.ContourOptions().
        If options is provided as a gdal.ContourOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = ContourOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    if isinstance(srcDS, (str, os.PathLike)):
        srcDS = OpenEx(srcDS, allowed_drivers = allowed_drivers, open_options = open_options)

    if isinstance(destNameOrDestDS, (str, os.PathLike)):
        return wrapper_GDALContourDestName(destNameOrDestDS, srcDS, opts, callback, callback_data)
    else:
        return wrapper_GDALContourDestDS(destNameOrDestDS, srcDS, opts, callback, callback_data)


def RasterizeOptions(options=None, format=None,
         outputType=gdalconst.GDT_Unknown,
         creationOptions=None, noData=None, initValues=None,
         outputBounds=None, outputSRS=None,
         transformerOptions=None,
         width=None, height=None,
         xRes=None, yRes=None, targetAlignedPixels=False,
         bands=None, inverse=False, allTouched=False,
         burnValues=None, attribute=None, useZ=False, layers=None,
         SQLStatement=None, SQLDialect=None, where=None, optim=None,
         add=None,
         callback=None, callback_data=None):
    """Create a RasterizeOptions() object that can be passed to gdal.Rasterize()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    format : any
        output format ("GTiff", etc...)
    outputType : any
        output type (gdalconst.GDT_Byte, etc...)
    creationOptions : any
        list or dict of creation options
    outputBounds : any
        assigned output bounds : any
        [minx, miny, maxx, maxy]
    outputSRS : any
        assigned output SRS
    transformerOptions : any
        list or dict of transformer options
    width : any
        width of the output raster in pixel
    height : any
        height of the output raster in pixel
    xRes : any
        output resolution in target SRS
    yRes : any
        output resolution in target SRS
    targetAlignedPixels : any
        whether to force output bounds to be multiple of output resolution
    noData : any
        nodata value
    initValues : any
        Value or list of values to pre-initialize the output image bands with.
         However, it is not marked as the nodata value in the output file.
          If only one value is given, the same value is used in all the bands.
    bands : any
        list of output bands to burn values into
    inverse : any
        whether to invert rasterization, i.e. burn the fixed burn value, or the
        burn value associated with the first feature into all parts of the image
        not inside the provided a polygon.
    allTouched : any
        whether to enable the ALL_TOUCHED rasterization option so that all pixels
        touched by lines or polygons will be updated, not just those on the line
        render path, or whose center point is within the polygon.
    burnValues : any
        list of fixed values to burn into each band for all objects.
        Exclusive with attribute.
    attribute : any
        identifies an attribute field on the features to be used for a burn-in value.
        The value will be burned into all output bands. Exclusive with burnValues.
    useZ : any
        whether to indicate that a burn value should be extracted from the "Z" values
        of the feature. These values are added to the burn value given by burnValues
        or attribute if provided. As of now, only points and lines are drawn in 3D.
    layers : any
        list of layers from the datasource that will be used for input features.
    SQLStatement : any
        SQL statement to apply to the source dataset
    SQLDialect : any
        SQL dialect ('OGRSQL', 'SQLITE', ...)
    where : any
        WHERE clause to apply to source layer(s)
    optim : any
        optimization mode ('RASTER', 'VECTOR')
    add : any
        set to True to use additive mode instead of replace when burning values
    callback : any
        callback method
    callback_data : any
        user data for callback
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'

    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if format is not None:
            new_options += ['-of', format]
        if outputType != gdalconst.GDT_Unknown:
            new_options += ['-ot', GetDataTypeName(outputType)]
        if creationOptions is not None:
            _addCreationOptions(new_options, creationOptions)
        if bands is not None:
            for b in bands:
                new_options += ['-b', str(b)]
        if noData is not None:
            new_options += ['-a_nodata', str(noData)]
        if initValues is not None:
            if isinstance(initValues, (tuple, list)):
                for val in initValues:
                    new_options += ['-init', str(val)]
            else:
                new_options += ['-init', str(initValues)]
        if outputBounds is not None:
            new_options += ['-te', _strHighPrec(outputBounds[0]), _strHighPrec(outputBounds[1]), _strHighPrec(outputBounds[2]), _strHighPrec(outputBounds[3])]
        if outputSRS is not None:
            new_options += ['-a_srs', str(outputSRS)]
        if transformerOptions is not None:
            _addOptions(new_options, '-to', transformerOptions)
        if width is not None and height is not None:
            new_options += ['-ts', str(width), str(height)]
        if xRes is not None and yRes is not None:
            new_options += ['-tr', _strHighPrec(xRes), _strHighPrec(yRes)]
        if targetAlignedPixels:
            new_options += ['-tap']
        if inverse:
            new_options += ['-i']
        if allTouched:
            new_options += ['-at']
        if burnValues is not None:
            if attribute is not None:
                raise Exception('burnValues and attribute option are exclusive.')
            if isinstance(burnValues, (tuple, list)):
                for val in burnValues:
                    new_options += ['-burn', str(val)]
            else:
                new_options += ['-burn', str(burnValues)]
        if attribute is not None:
            new_options += ['-a', attribute]
        if useZ:
            new_options += ['-3d']
        if layers is not None:
            if isinstance(layers, ((tuple, list))):
                for layer in layers:
                    new_options += ['-l', layer]
            else:
                new_options += ['-l', layers]
        if SQLStatement is not None:
            new_options += ['-sql', str(SQLStatement)]
        if SQLDialect is not None:
            new_options += ['-dialect', str(SQLDialect)]
        if where is not None:
            new_options += ['-where', str(where)]
        if optim is not None:
            new_options += ['-optim', str(optim)]
        if add:
            new_options += ['-add']

    if return_option_list:
        return new_options

    return (GDALRasterizeOptions(new_options), callback, callback_data)

def Rasterize(destNameOrDestDS, srcDS, **kwargs):
    """Burns vector geometries into a raster

    Parameters
    ----------
    destNameOrDestDS : any
        Output dataset name or object.

        If passed as a dataset name, a potentially existing output dataset of
        the same name will be overwritten. To update an existing output dataset,
        it must be passed as a dataset object.

    srcDS : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.RasterizeOptions(), string or array of strings,
        other keywords arguments of gdal.RasterizeOptions()
        If options is provided as a gdal.RasterizeOptions() object, other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = RasterizeOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']
    if isinstance(srcDS, (str, os.PathLike)):
        srcDS = OpenEx(srcDS, gdalconst.OF_VECTOR, allowed_drivers = allowed_drivers, open_options = open_options)

    if isinstance(destNameOrDestDS, (str, os.PathLike)):
        return wrapper_GDALRasterizeDestName(destNameOrDestDS, srcDS, opts, callback, callback_data)
    else:
        return wrapper_GDALRasterizeDestDS(destNameOrDestDS, srcDS, opts, callback, callback_data)


def FootprintOptions(options=None,
                     format=None,
                     bands=None,
                     combineBands=None,
                     srcNodata=None,
                     ovr=None,
                     targetCoordinateSystem=None,
                     dstSRS=None,
                     splitPolys=None,
                     convexHull=None,
                     densify=None,
                     simplify=None,
                     maxPoints=None,
                     minRingArea=None,
                     layerName=None,
                     locationFieldName="location",
                     writeAbsolutePath=False,
                     layerCreationOptions=None,
                     datasetCreationOptions=None,
                     callback=None, callback_data=None):
    """Create a FootprintOptions() object that can be passed to gdal.Footprint()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    format : any
        output format ("GeoJSON", etc...)
    bands : any
        list of output bands to burn values into
    combineBands : any
        how to combine bands: "union" (default) or "intersection"
    srcNodata : any
        source nodata value(s).
    ovr : any
        overview index.
    targetCoordinateSystem : any
        "pixel" or "georef"
    dstSRS : any
        output SRS
    datasetCreationOptions : any
        list or dict of dataset creation options
    layerCreationOptions : any
        list or dict of layer creation options
    splitPolys : any
        whether to split multipolygons as several polygons
    convexHull : any
        whether to compute the convex hull of polygons/multipolygons
    densify : any
        tolerance value for polygon densification
    simplify : any
        tolerance value for polygon simplification
    maxPoints : any
        maximum number of points (100 by default, "unlimited" for unlimited)
    minRingArea : any
        Minimum value for the area of a ring The unit of the area is in square pixels if targetCoordinateSystem equals "pixel", or otherwise in georeferenced units of the target vector dataset. This option is applied after the reprojection implied by dstSRS
    locationFieldName : any
        Specifies the name of the field in the resulting vector dataset where the path of the input dataset will be stored. The default field name is "location". Can be set to None to disable creation of such field.
    writeAbsolutePath : any
        Enables writing the absolute path of the input dataset. By default, the filename is written in the location field exactly as the dataset name.
    layerName : any
        output layer name
    callback : any
        callback method
    callback_data : any
        user data for callback
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'

    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if format is not None:
            new_options += ['-of', format]
        if bands is not None:
            for b in bands:
                new_options += ['-b', str(b)]
        if combineBands:
            new_options += ["-combine_bands", combineBands]
        if targetCoordinateSystem:
            new_options += ["-t_cs", targetCoordinateSystem]
        if dstSRS:
            new_options += ["-t_srs", dstSRS]
        if srcNodata is not None:
            new_options += ['-srcnodata', str(srcNodata)]
        if ovr is not None:
            new_options += ['-ovr', str(ovr)]
        if splitPolys:
            new_options += ["-split_polys"]
        if convexHull:
            new_options += ["-convex_hull"]
        if densify is not None:
            new_options += ['-densify', str(densify)]
        if simplify is not None:
            new_options += ['-simplify', str(simplify)]
        if maxPoints is not None:
            new_options += ['-max_points', str(maxPoints)]
        if minRingArea is not None:
            new_options += ['-min_ring_area', str(minRingArea)]
        if layerName is not None:
            new_options += ['-lyr_name', layerName]
        if datasetCreationOptions is not None:
            _addOptions(new_options, '-dsco', datasetCreationOptions)
        if layerCreationOptions is not None:
            _addOptions(new_options, '-lco', layerCreationOptions)
        if locationFieldName is not None:
            new_options += ['-location_field_name', locationFieldName]
        else:
            new_options += ['-no_location']
        if writeAbsolutePath:
            new_options += ['-write_absolute_path']

    if return_option_list:
        return new_options

    return (GDALFootprintOptions(new_options), callback, callback_data)

def Footprint(destNameOrDestDS, srcDS, **kwargs):
    """Compute the footprint of a raster

    Parameters
    ----------
    destNameOrDestDS : any
        Output dataset name or object

        If passed as a dataset name, a potentially existing output dataset of
        the same name will be overwritten. To update an existing output dataset,
        it must be passed as a dataset object.

    srcDS : any
        a Dataset object or a filename
    **kwargs : any
        options: return of gdal.FootprintOptions(), string or array of strings,
        other keywords arguments of gdal.FootprintOptions()
        If options is provided as a gdal.FootprintOptions() object, other keywords are ignored.

    Examples
    --------

    .. testsetup::

        >>> src_ds = gdal.GetDriverByName("MEM").Create("", 1, 1)

    1. Special mode to get deserialized GeoJSON (in EPSG:4326 if dstSRS not specified):

    >>> deserialized_geojson = gdal.Footprint(None, src_ds, format="GeoJSON")

    2. Special mode to get WKT:

    >>> wkt = gdal.Footprint(None, src_ds, format="WKT")

    3. Get result in a GeoPackage

    >>> gdal.Footprint("out.gpkg", src_ds, format="GPKG")
    <osgeo.gdal.Dataset; proxy of <Swig Object of type 'GDALDatasetShadow *' at 0x...> >
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    inline_geojson_requested = (destNameOrDestDS is None or destNameOrDestDS == "") and \
        "format" in kwargs and kwargs["format"] == "GeoJSON"
    if inline_geojson_requested and "dstSRS" not in kwargs:
        import copy
        kwargs = copy.copy(kwargs)
        kwargs["dstSRS"] = "EPSG:4326"

    wkt_requested = (destNameOrDestDS is None or destNameOrDestDS == "") and \
        "format" in kwargs and kwargs["format"] == "WKT"
    if wkt_requested:
        import copy
        kwargs = copy.copy(kwargs)
        kwargs["format"] = "GeoJSON"

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = FootprintOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    if isinstance(srcDS, (str, os.PathLike)):
        srcDS = OpenEx(srcDS, gdalconst.OF_RASTER, allowed_drivers = allowed_drivers, open_options = open_options)

    if inline_geojson_requested or wkt_requested:
        import uuid
        temp_filename = "/vsimem/" + str(uuid.uuid4())
        try:
            if not wrapper_GDALFootprintDestName(temp_filename, srcDS, opts, callback, callback_data):
                return None
            if inline_geojson_requested:
                f = VSIFOpenL(temp_filename, "rb")
                assert f
                VSIFSeekL(f, 0, 2) # SEEK_END
                size = VSIFTellL(f)
                VSIFSeekL(f, 0, 0) # SEEK_SET
                data = VSIFReadL(1, size, f)
                VSIFCloseL(f)
                import json
                return json.loads(data)
            else:
                assert wkt_requested
                ds = OpenEx(temp_filename)
                lyr = ds.GetLayer(0)
                wkts = []
                for f in lyr:
                    wkts.append(f.GetGeometryRef().ExportToWkt())
                if len(wkts) == 1:
                    return wkts[0]
                else:
                    return wkts
        finally:
            if VSIStatL(temp_filename):
                Unlink(temp_filename)

    if isinstance(destNameOrDestDS, (str, os.PathLike)):
        return wrapper_GDALFootprintDestName(destNameOrDestDS, srcDS, opts, callback, callback_data)
    else:
        return wrapper_GDALFootprintDestDS(destNameOrDestDS, srcDS, opts, callback, callback_data)


def BuildVRTOptions(options=None,
                    resolution=None,
                    outputBounds=None,
                    xRes=None,
                    yRes=None,
                    targetAlignedPixels=None,
                    separate=None,
                    bandList=None,
                    addAlpha=None,
                    resampleAlg=None,
                    outputSRS=None,
                    allowProjectionDifference=None,
                    srcNodata=None,
                    VRTNodata=None,
                    hideNodata=None,
                    nodataMaxMaskThreshold=None,
                    strict=False,
                    writeAbsolutePath=False,
                    pixelFunction=None,
                    pixelFunctionArgs=None,
                    creationOptions=None,
                    callback=None, callback_data=None):
    """Create a BuildVRTOptions() object that can be passed to gdal.BuildVRT()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    resolution : any
        'highest', 'lowest', 'average', 'user'.
    outputBounds : any
        output bounds as (minX, minY, maxX, maxY) in target SRS.
    xRes : any
        output resolution in target SRS.
    yRes : any
        output resolution in target SRS.
    targetAlignedPixels : any
        whether to force output bounds to be multiple of output resolution.
    separate : any
        whether each source file goes into a separate stacked band in the VRT band.
    bandList : any
        array of band numbers (index start at 1).
    addAlpha : any
        whether to add an alpha mask band to the VRT when the source raster have none.
    resampleAlg : any
        resampling mode.
    outputSRS : any
        assigned output SRS.
    allowProjectionDifference : any
        whether to accept input datasets have not the same projection.
        Note: they will *not* be reprojected.
    srcNodata : any
        source nodata value(s).
    VRTNodata : any
        nodata values at the VRT band level.
    hideNodata : any
        whether to make the VRT band not report the NoData value.
    nodataMaxMaskThreshold : any
        value of the mask band of a source below which the source band values should be replaced by VRTNodata (or 0 if not specified)
    strict : any
        set to True if warnings should be failures
    pixelFunction : any
        a pixel function to use to calculate output pixel values when multiple
        sources overlap. For a list of available pixel functions, see
        :ref:`builtin_pixel_functions`.
    pixelFunctionArgs : any
        list or dict of pixel function arguments
    creationOptions : any
        list or dict of creation options
    writeAbsolutePath : any
        Enables writing the absolute path of the input datasets. By default, input filenames are written in a relative way with respect to the VRT filename (when possible)
    callback : any
        callback method.
    callback_data : any
        user data for callback.
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'
    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if resolution is not None:
            new_options += ['-resolution', str(resolution)]
        if outputBounds is not None:
            new_options += ['-te', _strHighPrec(outputBounds[0]), _strHighPrec(outputBounds[1]), _strHighPrec(outputBounds[2]), _strHighPrec(outputBounds[3])]
        if xRes is not None and yRes is not None:
            new_options += ['-tr', _strHighPrec(xRes), _strHighPrec(yRes)]
        if targetAlignedPixels:
            new_options += ['-tap']
        if separate:
            new_options += ['-separate']
        if bandList != None:
            for b in bandList:
                new_options += ['-b', str(b)]
        if addAlpha:
            new_options += ['-addalpha']
        if resampleAlg is not None:
            if resampleAlg in mapGRIORAMethodToString:
                new_options += ['-r', mapGRIORAMethodToString[resampleAlg]]
            else:
                new_options += ['-r', str(resampleAlg)]
        if outputSRS is not None:
            new_options += ['-a_srs', str(outputSRS)]
        if allowProjectionDifference:
            new_options += ['-allow_projection_difference']
        if srcNodata is not None:
            new_options += ['-srcnodata', str(srcNodata)]
        if VRTNodata is not None:
            new_options += ['-vrtnodata', str(VRTNodata)]
        if nodataMaxMaskThreshold is not None:
            new_options += ['-nodata_max_mask_threshold', str(nodataMaxMaskThreshold)]
        if hideNodata:
            new_options += ['-hidenodata']
        if strict:
            new_options += ['-strict']
        if writeAbsolutePath:
            new_options += ['-write_absolute_path']
        if creationOptions is not None:
            _addCreationOptions(new_options, creationOptions)
        if pixelFunction:
            new_options += ['-pixel-function', pixelFunction]
        if pixelFunctionArgs:
            _addOptions(new_options, '-pixel-function-arg', pixelFunctionArgs)

    if return_option_list:
        return new_options

    return (GDALBuildVRTOptions(new_options), callback, callback_data)

def BuildVRT(destName, srcDSOrSrcDSTab, **kwargs):
    """Build a VRT from a list of datasets.

    Parameters
    ----------
    destName : any
        Output dataset name.
    srcDSOrSrcDSTab : any
        An array of Dataset objects or filenames, or a Dataset object or a filename.
    **kwargs : any
        options: return of gdal.BuildVRTOptions(), string or array of strings,
        other keywords arguments of gdal.BuildVRTOptions().
        If options is provided as a gdal.BuildVRTOptions() object,
        other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = BuildVRTOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    srcDSTab = []
    srcDSNamesTab = []

    if isinstance(srcDSOrSrcDSTab, (str, os.PathLike)):
        srcDSNamesTab = [str(srcDSOrSrcDSTab)]
    elif isinstance(srcDSOrSrcDSTab, list):
        for elt in srcDSOrSrcDSTab:
            if isinstance(elt, (str, os.PathLike)):
                srcDSNamesTab.append(str(elt))
            else:
                srcDSTab.append(elt)
        if srcDSTab and srcDSNamesTab:
            raise Exception('Mix of names and dataset objects not supported')
    else:
        srcDSTab = [srcDSOrSrcDSTab]

    if srcDSTab:
        return BuildVRTInternalObjects(destName, srcDSTab, opts, callback, callback_data)
    else:
        return BuildVRTInternalNames(destName, srcDSNamesTab, opts, callback, callback_data)


def TileIndexOptions(options=None,
                     overwrite=None,
                     recursive=None,
                     filenameFilter=None,
                     minPixelSize=None,
                     maxPixelSize=None,
                     format=None,
                     layerName=None,
                     layerCreationOptions=None,
                     locationFieldName="location",
                     outputSRS=None,
                     writeAbsolutePath=None,
                     skipDifferentProjection=None,
                     gtiFilename=None,
                     xRes=None,
                     yRes=None,
                     outputBounds=None,
                     colorInterpretation=None,
                     noData=None,
                     bandCount=None,
                     mask=None,
                     metadataOptions=None,
                     fetchMD=None):
    """Create a TileIndexOptions() object that can be passed to gdal.TileIndex()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    overwrite : any
        Whether to overwrite the existing tile index
    recursive : any
        Whether directories specified in source filenames should be explored recursively
    filenameFilter : any
        Pattern that the filenames contained in directories pointed by <file_or_dir> should follow. '*' and '?' wildcard can be used. String or list of strings.
    minPixelSize : any
        Minimum pixel size in term of geospatial extent per pixel (resolution) that a raster should have to be selected.
    maxPixelSize : any
        Maximum pixel size in term of geospatial extent per pixel (resolution) that a raster should have to be selected.
    format : any
        output format ("ESRI Shapefile", "GPKG", etc...)
    layerName : any
        output layer name
    layerCreationOptions : any
        list or dict of layer creation options
    locationFieldName : any
        Specifies the name of the field in the resulting vector dataset where the path of the input dataset will be stored. The default field name is "location". Can be set to None to disable creation of such field.
    outputSRS : any
        assigned output SRS
    writeAbsolutePath : any
        Enables writing the absolute path of the input dataset. By default, the filename is written in the location field exactly as the dataset name.
    skipDifferentProjection : any
        Whether to skip sources that have a different SRS
    gtiFilename : any
        Filename of the GDAL XML Tile Index file
    xRes : any
        output horizontal resolution
    yRes : any
        output vertical resolution
    outputBounds : any
        output bounds as [minx, miny, maxx, maxy]
    colorInterpretation : any
        Tile color interpretation, as a single value or a list, of the following values ("red", "green", "blue", "alpha", "grey", "undefined", etc.) or their GCI_xxxx symbolic names
    noData : any
        tile nodata value, as a single value or a list
    bandCount : any
        number of band of tiles in the index
    mask : any
        whether tiles have a band mask
    metadataOptions : any
        list or dict of metadata options
    fetchMD : any
        Fetch a metadata item from the raster tile and write it as a field in the
        tile index.
        Tuple (raster metadata item name, target field name, target field type), or list of such tuples, with target field type in "String", "Integer", "Integer64", "Real", "Date", "DateTime";
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'
    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if overwrite:
            new_options += ['-overwrite']
        if recursive:
            new_options += ['-recursive']
        if filenameFilter is not None:
            if isinstance(filenameFilter, list):
                for filter in filenameFilter:
                    new_options += ['-filename_filter', filter]
            else:
                new_options += ['-filename_filter', filenameFilter]
        if minPixelSize is not None:
            new_options += ['-min_pixel_size', _strHighPrec(minPixelSize)]
        if maxPixelSize is not None:
            new_options += ['-max_pixel_size', _strHighPrec(maxPixelSize)]
        if format:
            new_options += ['-f', format]
        if layerName is not None:
            new_options += ['-lyr_name', layerName]

        if layerCreationOptions is not None:
            _addOptions(new_options, '-lco', layerCreationOptions)

        if locationFieldName is not None:
            new_options += ['-tileindex', locationFieldName]
        if outputSRS is not None:
            new_options += ['-t_srs', str(outputSRS)]
        if writeAbsolutePath:
            new_options += ['-write_absolute_path']
        if skipDifferentProjection:
            new_options += ['-skip_different_projection']
        if gtiFilename is not None:
            new_options += ['-gti_filename', gtiFilename]
        if xRes is not None and yRes is not None:
            new_options += ['-tr', _strHighPrec(xRes), _strHighPrec(yRes)]
        elif xRes is not None:
            raise Exception("yRes should also be specified")
        elif yRes is not None:
            raise Exception("xRes should also be specified")
        if outputBounds is not None:
            new_options += ['-te', _strHighPrec(outputBounds[0]), _strHighPrec(outputBounds[1]), _strHighPrec(outputBounds[2]), _strHighPrec(outputBounds[3])]
        if colorInterpretation is not None:
            def colorInterpAsString(x):
                return GetColorInterpretationName(x) if isinstance(x, int) else x
            if isinstance(colorInterpretation, list):
                new_options += ['-colorinterp', ','.join([colorInterpAsString(x) for x in colorInterpretation])]
            else:
                new_options += ['-colorinterp', colorInterpAsString(colorInterpretation)]
        if noData is not None:
            if isinstance(noData, list):
                new_options += ['-nodata', ','.join([_strHighPrec(x) for x in noData])]
            else:
                new_options += ['-nodata', _strHighPrec(noData)]
        if bandCount is not None:
            new_options += ['-bandcount', str(bandCount)]
        if mask:
            new_options += ['-mask']
        if metadataOptions is not None:
            _addOptions(new_options, '-mo', metadataOptions)
        if fetchMD is not None:
            if isinstance(fetchMD, list):
                for mdItemName, fieldName, fieldType in fetchMD:
                    new_options += ['-fetch_md', mdItemName, fieldName, fieldType]
            else:
                new_options += ['-fetch_md', fetchMD[0], fetchMD[1], fetchMD[2]]

    if return_option_list:
        return new_options

    callback = None
    callback_data = None
    return (GDALTileIndexOptions(new_options), callback, callback_data)

def TileIndex(destName, srcFilenames, **kwargs):
    """Build a tileindex from a list of datasets.

    Parameters
    ----------
    destName : any
        Output dataset name.
    srcFilenames : any
        An array of filenames.
    **kwargs  : any
        options: return of gdal.TileIndexOptions(), string or array of strings,
        other keywords arguments of gdal.TileIndexOptions().
        If options is provided as a gdal.TileIndexOptions() object,
        other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = TileIndexOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    srcDSNamesTab = []

    if isinstance(srcFilenames, (str, os.PathLike)):
        srcDSNamesTab = [str(srcFilenames)]
    elif isinstance(srcFilenames, list):
        for elt in srcFilenames:
            srcDSNamesTab.append(str(elt))
    else:
        raise Exception("Unexpected type for srcFilenames")

    return TileIndexInternalNames(destName, srcDSNamesTab, opts, callback, callback_data)


def MultiDimTranslateOptions(options=None, format=None, creationOptions=None,
         arraySpecs=None, arrayOptions=None, groupSpecs=None, subsetSpecs=None, scaleAxesSpecs=None,
         callback=None, callback_data=None):
    """Create a MultiDimTranslateOptions() object that can be passed to gdal.MultiDimTranslate()

    Parameters
    ----------
    options : any
        can be an array of strings, a string or let empty and filled from other keywords.
    format : any
        output format ("GTiff", etc...)
    creationOptions : any
        list or dict of creation options
    arraySpecs : any
        list of array specifications, each of them being an array name or
        "name={src_array_name},dstname={dst_name},transpose=[1,0],view=[:,::-1]"
    arrayOptions : any
        list of options passed to `GDALGroup.GetMDArrayNames` to filter reported arrays.
    groupSpecs : any
        list of group specifications, each of them being a group name or
        "name={src_array_name},dstname={dst_name},recursive=no"
    subsetSpecs : any
        list of subset specifications, each of them being like
        "{dim_name}({min_val},{max_val})" or "{dim_name}({slice_va})"
    scaleAxesSpecs : any
        list of dimension scaling specifications, each of them being like
        "{dim_name}({scale_factor})"
    callback : any
        callback method
    callback_data : any
        user data for callback
    """

# Only used for tests
    return_option_list = options == '__RETURN_OPTION_LIST__'

    if return_option_list:
        options = []
    else:
        options = [] if options is None else options

    if isinstance(options, str):
        new_options = ParseCommandLine(options)
    else:
        import copy
        new_options = copy.copy(options)
        if format is not None:
            new_options += ['-of', format]
        if creationOptions is not None:
            _addCreationOptions(new_options, creationOptions)
        if arraySpecs is not None:
            for s in arraySpecs:
                new_options += ['-array', s]
        if arrayOptions:
            for option in arrayOptions:
                new_options += ['-arrayoption', option]
        if groupSpecs is not None:
            for s in groupSpecs:
                new_options += ['-group', s]
        if subsetSpecs is not None:
            for s in subsetSpecs:
                new_options += ['-subset', s]
        if scaleAxesSpecs is not None:
            for s in scaleAxesSpecs:
                new_options += ['-scaleaxes', s]

    if return_option_list:
        return new_options

    return (GDALMultiDimTranslateOptions(new_options), callback, callback_data)

def MultiDimTranslate(destName, srcDSOrSrcDSTab, **kwargs):
    """MultiDimTranslate one or several datasets.

    Parameters
    ----------
    destName : any
        Output dataset name
    srcDSOrSrcDSTab : any
        an array of Dataset objects or filenames, or a Dataset object or a filename
    **kwargs : any
        options: return of gdal.MultiDimTranslateOptions(), string or array of strings
        other keywords arguments of gdal.MultiDimTranslateOptions().
        If options is provided as a gdal.MultiDimTranslateOptions() object,
        other keywords are ignored.
    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()

    allowed_drivers, open_options = _get_allowed_drivers_and_open_options(**kwargs)
    if 'options' not in kwargs or isinstance(kwargs['options'], (list, str)):
        (opts, callback, callback_data) = MultiDimTranslateOptions(**kwargs)
    else:
        (opts, callback, callback_data) = kwargs['options']

    import os

    if isinstance(srcDSOrSrcDSTab, (str, os.PathLike)):
        srcDSTab = [OpenEx(srcDSOrSrcDSTab, OF_VERBOSE_ERROR | OF_RASTER | OF_MULTIDIM_RASTER, allowed_drivers = allowed_drivers, open_options = open_options)]
    elif isinstance(srcDSOrSrcDSTab, list):
        srcDSTab = []
        for elt in srcDSOrSrcDSTab:
            if isinstance(elt, str):
                srcDSTab.append(OpenEx(elt, OF_VERBOSE_ERROR | OF_RASTER | OF_MULTIDIM_RASTER, allowed_drivers = allowed_drivers, open_options = open_options))
            else:
                srcDSTab.append(elt)
    else:
        srcDSTab = [srcDSOrSrcDSTab]

    return wrapper_GDALMultiDimTranslateDestName(destName, srcDSTab, opts, callback, callback_data)

# Logging Helpers
def _pylog_handler(err_level, err_no, err_msg):
    if err_no != gdalconst.CPLE_None:
        typ = _pylog_handler.errcode_map.get(err_no, str(err_no))
        message = "%s: %s" % (typ, err_msg)
    else:
        message = err_msg

    level = _pylog_handler.level_map.get(err_level, 20)  # default level is INFO
    _pylog_handler.logger.log(level, message)

def ConfigurePythonLogging(logger_name='gdal', enable_debug=False):
    """ Configure GDAL to use Python's logging framework """
    import logging

    _pylog_handler.logger = logging.getLogger(logger_name)

# map CPLE_* constants to names
    _pylog_handler.errcode_map = {_num: _name[5:] for _name, _num in gdalconst.__dict__.items() if _name.startswith('CPLE_')}

# Map GDAL log levels to Python's
    _pylog_handler.level_map = {
        CE_None: logging.INFO,
        CE_Debug: logging.DEBUG,
        CE_Warning: logging.WARN,
        CE_Failure: logging.ERROR,
        CE_Fatal: logging.CRITICAL,
    }

# Set CPL_DEBUG so debug messages are passed through the logger
    if enable_debug:
        SetConfigOption("CPL_DEBUG", "ON")

# Install as the default GDAL log handler
    SetErrorHandler(_pylog_handler)


def EscapeString(*args, **kwargs):
    """EscapeString(string_or_bytes, scheme = gdal.CPLES_SQL)"""
    if isinstance(args[0], bytes):
        return _gdal.EscapeBinary(*args, **kwargs)
    else:
        return _gdal.wrapper_EscapeString(*args, **kwargs)


def ApplyVerticalShiftGrid(*args, **kwargs):
    """ApplyVerticalShiftGrid(Dataset src_ds, Dataset grid_ds, bool inverse=False, double srcUnitToMeter=1.0, double dstUnitToMeter=1.0, char ** options=None) -> Dataset"""

    from warnings import warn
    warn('ApplyVerticalShiftGrid() will be removed in GDAL 4.0', DeprecationWarning)
    return _ApplyVerticalShiftGrid(*args, **kwargs)


import contextlib
@contextlib.contextmanager
def config_options(options, thread_local=True):
    """Temporarily define a set of configuration options.

       Parameters
       ----------
       options : dict
            Dictionary of configuration options passed as key, value
       thread_local : bool, default=True
            Whether the configuration options should be only set on the current
            thread. Note that GDAL_CACHEMAX cannot be set with thread_local=True.

       Returns
       -------
       contextlib.contextmanager
           A context manager

       Examples
       --------

       >>> with gdal.config_options({"GDAL_NUM_THREADS": "ALL_CPUS"}):
       ...     gdal.Warp("out.tif", "in.tif", dstSRS="EPSG:4326")
       <osgeo.gdal.Dataset; proxy of <Swig Object of type 'GDALDatasetShadow *' at 0x...> >
    """
    get_config_option = GetThreadLocalConfigOption if thread_local else GetGlobalConfigOption
    set_config_option = SetThreadLocalConfigOption if thread_local else SetConfigOption

    if thread_local and "GDAL_CACHEMAX" in options:
        raise ValueError("Setting GDAL_CACHEMAX has process-wide visibility, and is thus incompatible of the thread_local=True argument of gdal.config_options()")

    oldvals = {key: get_config_option(key) for key in options}
    old_gdal_cache_max = GetCacheMax() if "GDAL_CACHEMAX" in options else None

    for key in options:
        val = options[key]
        if key == "GDAL_CACHEMAX":
            SetCacheMax(int(val))
        else:
            if val is None:
                val = "__CPL_NULL_VALUE__"
            set_config_option(key, val)
    try:
        yield
    finally:
        for key in options:
            if key == "GDAL_CACHEMAX":
                SetCacheMax(int(old_gdal_cache_max))
            else:
                set_config_option(key, oldvals[key])


def config_option(key, value, thread_local=True):
    """Temporarily define a configuration option.

       Parameters
       ----------
       key : str
            Name of the configuration option
       value : str
            Value of the configuration option
       thread_local : bool, default=True
            Whether the configuration option should be only set on the current
            thread. Note that GDAL_CACHEMAX cannot be set with thread_local=True.

       Returns
       -------
       contextlib.contextmanager
           A context manager

       Examples
       --------

       >>> with gdal.config_option("GDAL_NUM_THREADS", "ALL_CPUS"):
       ...     gdal.Warp("out.tif", "in.tif", dstSRS="EPSG:4326")
       <osgeo.gdal.Dataset; proxy of <Swig Object of type 'GDALDatasetShadow *' at 0x...> >
    """

    if thread_local and key == "GDAL_CACHEMAX":
        raise ValueError("Setting GDAL_CACHEMAX has process-wide visibility, and is thus incompatible of the thread_local=True argument of gdal.config_option()")

    return config_options({key: value}, thread_local=thread_local)


@contextlib.contextmanager
def quiet_errors():
    """Temporarily install an error handler that silences all warnings and errors.

       Returns
       -------
       contextlib.contextmanager
           A context manager

       Examples
       --------

       >>> with gdal.ExceptionMgr(useExceptions=False), gdal.quiet_errors():
       ...     gdal.Error(gdal.CE_Failure, gdal.CPLE_AppDefined, "you will never see me")
    """
    PushErrorHandler("CPLQuietErrorHandler")
    try:
        yield
    finally:
        PopErrorHandler()

@contextlib.contextmanager
def quiet_warnings():
    """Temporarily install an error handler that silences all warnings.

       .. versionadded:: 3.11

       Returns
       -------
       contextlib.contextmanager
           A context manager

       Examples
       --------

       >>> with gdal.ExceptionMgr(useExceptions=False), gdal.quiet_warnings():
       ...     gdal.Error(gdal.CE_Warning, gdal.CPLE_AppDefined, "you will never see me")
    """
    PushErrorHandler("CPLQuietWarningsErrorHandler")
    try:
        yield
    finally:
        PopErrorHandler()


def Run(*alg, arguments={}, progress=None, **kwargs):
    """Run a GDAL algorithm and return it.

       .. versionadded:: 3.11

       This method can also be used within a context manager, in which case
       :py:meth:`osgeo.gdal.Algorithm.Finalize` will be called at the exit of the
       context manager.  An exception will be raised if the algorithm fails,
       even if :py:meth:`osgeo.gdal.UseExceptions()` has not been called.

       This method must be called at most once per instance.

       Parameters
       ----------
       alg : str, list[str], tuple[str] or Algorithm
            Path to the algorithm or algorithm instance itself. For example "raster info", ["raster", "info"] or "raster", "info".
       arguments : dict
            Input arguments of the algorithm. For example {"format": "json", "input": "byte.tif"}
       progress : callable
            Progress function whose arguments are a progress ratio, a string and a user data
       **kwargs : any
            Instead of using the ``arguments`` parameter, it is possible to pass
            algorithm arguments directly as named parameters of gdal.Run().
            If the named argument has dash characters in it, the corresponding
            parameter must replace them with an underscore character.
            For example ``dst_crs`` as a a parameter of gdal.Run(), instead of
            ``dst-crs`` which is the name to use on the command line.

       Returns
       -------
       Algorithm

       Examples
       --------

       >>> alg = gdal.Run(["raster", "info"], {"input": "byte.tif"})
       >>> print(alg.Output()["bands"])
       [{'band': 1, 'block': [20, 20], 'type': 'Byte', 'colorInterpretation': 'Gray', 'metadata': {}}]

       >>> with gdal.Run("raster", "reproject", input="byte.tif", output_format="MEM", dst_crs="EPSG:4326") as alg:
       ...     print(alg.Output().ReadAsArray().shape)
       (18, 22)
    """

    new_alg = []
    for v in alg:
        if isinstance(v, dict):
            arguments = v
            break
        new_alg.append(v)
    alg = new_alg

    if len(alg) == 1 and isinstance(alg[0], Algorithm):
        alg = alg[0]
    elif len(alg) >= 1 and (isinstance(alg[0], list) or isinstance(alg[0], str)):
        alg = Algorithm(*alg)
    else:
        raise RuntimeError("Wrong type for alg. Expected string, list of strings or Algorithm")

    for k in arguments:
        alg[k.replace('_', '-')] = arguments[k]

    for k in kwargs:
        alg[k.replace('_', '-')] = kwargs[k]

    if not alg.Run(progress):
# We go here only if gdal.UseExceptions() has not been called
        raise RuntimeError("Algorithm.Run() failed: %s" % GetLastErrorMsg())

    return alg




# VSIFile: Copyright (c) 2024, Dan Baston <dbaston at gmail.com>

from io import BytesIO

class VSIFile(BytesIO):
    """Class wrapping a GDAL VSILFILE instance as a Python BytesIO instance

       :since: GDAL 3.11
    """

    def __init__(self, path, mode, encoding="utf-8", options = {}):
        self._path = path
        self._mode = mode

        self._binary = "b" in mode
        self._encoding = encoding

        self._closed = True
        self._fp = None

        self._fp = VSIFOpenExL(self._path, self._mode, True, options)
        if self._fp is None:
            raise OSError(VSIGetLastErrorMsg())

        self._closed = False

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()

    def __iter__(self):
        return self

    def __next__(self):
        line = CPLReadLineL(self._fp)
        if line is None:
            raise StopIteration
        if self._binary:
            return line.encode()
        return line

    def close(self):
        if self._closed:
            return

        self._closed = True
        VSIFCloseL(self._fp)

    def read(self, size=-1):
        if size == -1:
            pos = self.tell()
            self.seek(0, 2)
            size = self.tell()
            self.seek(pos)

        raw = VSIFReadL(1, size, self._fp)

        if self._binary:
            return bytes(raw)
        else:
            return raw.decode(self._encoding)

    def write(self, x):

        if self._binary:
            assert type(x) in (bytes, bytearray, memoryview)
        else:
            assert type(x) is str
            x = x.encode(self._encoding)

        planned_write = len(x)
        actual_write = VSIFWriteL(x, 1, planned_write, self._fp)

        if planned_write != actual_write:
            raise OSError(
                f"Expected to write {planned_write} bytes but {actual_write} were written"
            )

    def seek(self, offset, whence=0):
# We redefine the docstring since otherwise breathe would complain on the one coming from BytesIO.seek()
        """Change stream position.

           Seek to byte offset pos relative to position indicated by whence:

           - 0: Start of stream (the default).  pos should be >= 0;
           - 1: Current position - pos may be negative;
           - 2: End of stream - pos usually negative.

           Returns the new absolute position.
        """

        if VSIFSeekL(self._fp, offset, whence) != 0:
            raise OSError(VSIGetLastErrorMsg())

    def tell(self):
        return VSIFTellL(self._fp)


def Debug(*args):
    r"""Debug(msg_class, message)"""
    return _gdal.Debug(*args)

def SetErrorHandler(*args):
    r"""SetErrorHandler(pfnErrorHandler=0) -> CPLErr"""
    return _gdal.SetErrorHandler(*args)

def SetCurrentErrorHandlerCatchDebug(*args):
    r"""SetCurrentErrorHandlerCatchDebug(bCatchDebug)"""
    return _gdal.SetCurrentErrorHandlerCatchDebug(*args)

def PushErrorHandler(*args):
    r"""PushErrorHandler(pfnErrorHandler=0) -> CPLErr"""
    return _gdal.PushErrorHandler(*args)

def PopErrorHandler(*args):
    r"""PopErrorHandler()"""
    return _gdal.PopErrorHandler(*args)

def Error(*args):
    r"""Error(msg_class=CE_Failure, err_code=0, msg="error")"""
    return _gdal.Error(*args)

def GOA2GetAuthorizationURL(*args):
    r"""GOA2GetAuthorizationURL(pszScope) -> retStringAndCPLFree *"""
    return _gdal.GOA2GetAuthorizationURL(*args)

def GOA2GetRefreshToken(*args):
    r"""GOA2GetRefreshToken(pszAuthToken, pszScope) -> retStringAndCPLFree *"""
    return _gdal.GOA2GetRefreshToken(*args)

def GOA2GetAccessToken(*args):
    r"""GOA2GetAccessToken(pszRefreshToken, pszScope) -> retStringAndCPLFree *"""
    return _gdal.GOA2GetAccessToken(*args)

def ErrorReset(*args):
    r"""ErrorReset()"""
    return _gdal.ErrorReset(*args)

def VSICurlClearCache(*args):
    r"""VSICurlClearCache()"""
    return _gdal.VSICurlClearCache(*args)

def VSICurlPartialClearCache(*args):
    r"""VSICurlPartialClearCache(path)"""
    return _gdal.VSICurlPartialClearCache(*args)

def wrapper_EscapeString(*args, **kwargs):
    r"""wrapper_EscapeString(len, scheme=CPLES_SQL) -> retStringAndCPLFree *"""
    return _gdal.wrapper_EscapeString(*args, **kwargs)

def EscapeBinary(*args, **kwargs):
    r"""EscapeBinary(len, scheme=CPLES_SQL)"""
    return _gdal.EscapeBinary(*args, **kwargs)

def GetLastErrorNo(*args):
    r"""GetLastErrorNo() -> int"""
    return _gdal.GetLastErrorNo(*args)

def GetLastErrorType(*args):
    r"""GetLastErrorType() -> int"""
    return _gdal.GetLastErrorType(*args)

def GetLastErrorMsg(*args):
    r"""GetLastErrorMsg() -> char const *"""
    return _gdal.GetLastErrorMsg(*args)

def GetErrorCounter(*args):
    r"""GetErrorCounter() -> unsigned int"""
    return _gdal.GetErrorCounter(*args)

def VSIGetLastErrorNo(*args):
    r"""VSIGetLastErrorNo() -> int"""
    return _gdal.VSIGetLastErrorNo(*args)

def VSIGetLastErrorMsg(*args):
    r"""VSIGetLastErrorMsg() -> char const *"""
    return _gdal.VSIGetLastErrorMsg(*args)

def VSIErrorReset(*args):
    r"""VSIErrorReset()"""
    return _gdal.VSIErrorReset(*args)

def PushFinderLocation(*args):
    r"""PushFinderLocation(path)"""
    return _gdal.PushFinderLocation(*args)

def PopFinderLocation(*args):
    r"""PopFinderLocation()"""
    return _gdal.PopFinderLocation(*args)

def FinderClean(*args):
    r"""FinderClean()"""
    return _gdal.FinderClean(*args)

def FindFile(*args):
    r"""FindFile(pszClass, path) -> char const *"""
    return _gdal.FindFile(*args)

def ReadDir(*args):
    r"""ReadDir(path, nMaxFiles=0) -> char **"""
    return _gdal.ReadDir(*args)

def ReadDirRecursive(*args):
    r"""ReadDirRecursive(path) -> char **"""
    return _gdal.ReadDirRecursive(*args)

def OpenDir(*args):
    r"""OpenDir(path, nRecurseDepth=-1, options=None) -> VSIDIR *"""
    return _gdal.OpenDir(*args)
class DirEntry(object):
    r"""Proxy of C++ DirEntry class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    name = property(_gdal.DirEntry_name_get, doc=r"""name""")
    mode = property(_gdal.DirEntry_mode_get, doc=r"""mode""")
    size = property(_gdal.DirEntry_size_get, doc=r"""size""")
    mtime = property(_gdal.DirEntry_mtime_get, doc=r"""mtime""")
    modeKnown = property(_gdal.DirEntry_modeKnown_get, doc=r"""modeKnown""")
    sizeKnown = property(_gdal.DirEntry_sizeKnown_get, doc=r"""sizeKnown""")
    mtimeKnown = property(_gdal.DirEntry_mtimeKnown_get, doc=r"""mtimeKnown""")
    extra = property(_gdal.DirEntry_extra_get, doc=r"""extra""")

    def __init__(self, *args):
        r"""__init__(self, entryIn) -> DirEntry"""
        _gdal.DirEntry_swiginit(self, _gdal.new_DirEntry(*args))
    __swig_destroy__ = _gdal.delete_DirEntry

    def IsDirectory(self, *args):
        r"""IsDirectory(self) -> bool"""
        return _gdal.DirEntry_IsDirectory(self, *args)

# Register DirEntry in _gdal:
_gdal.DirEntry_swigregister(DirEntry)

def GetNextDirEntry(*args):
    r"""GetNextDirEntry(dir) -> DirEntry"""
    return _gdal.GetNextDirEntry(*args)

def CloseDir(*args):
    r"""CloseDir(dir)"""
    return _gdal.CloseDir(*args)

def SetConfigOption(*args):
    r"""
    SetConfigOption(pszKey, pszValue)


    Set the value of a configuration option for all threads.
    See :cpp:func:`CPLSetConfigOption`.

    Parameters
    ----------
    pszKey : str
        name of the configuration option
    pszValue : str
        value of the configuration option

    See Also
    --------
    :py:func:`SetThreadLocalConfigOption`
    :py:func:`config_option`
    :py:func:`config_options`


    """

    if type(args[1]) in (bool, int, float):
        args = (args[0], str(args[1]))


    return _gdal.SetConfigOption(*args)

def SetThreadLocalConfigOption(*args):
    r"""
    SetThreadLocalConfigOption(pszKey, pszValue)


    Set the value of a configuration option for the current thread.
    See :cpp:func:`CPLSetThreadLocalConfigOption`.

    Parameters
    ----------
    pszKey : str
        name of the configuration option
    pszValue : str
        value of the configuration option

    See Also
    --------
    :py:func:`SetConfigOption`
    :py:func:`config_option`
    :py:func:`config_options`

    """

    if type(args[1]) in (bool, int, float):
        args = (args[0], str(args[1]))


    return _gdal.SetThreadLocalConfigOption(*args)

def GetConfigOption(*args):
    r"""
    GetConfigOption(pszKey, pszDefault=None) -> char const *


    Return the value of a configuration option.
    See :cpp:func:`CPLGetConfigOption`.

    Parameters
    ----------
    pszKey : str
        name of the configuration option
    pszDefault : str, optional
        default value to return if the option has not been set

    Returns
    -------
    str

    See Also
    --------
    :py:func:`GetConfigOptions`
    :py:func:`GetThreadLocalConfigOption`

    """
    return _gdal.GetConfigOption(*args)

def GetGlobalConfigOption(*args):
    r"""
    GetGlobalConfigOption(pszKey, pszDefault=None) -> char const *


    Return the value of a global (not thread-local) configuration option.
    See :cpp:func:`CPLGetGlobalConfigOption`.

    Parameters
    ----------
    pszKey : str
        name of the configuration option
    pszDefault : str, optional
        default value to return if the option has not been set

    Returns
    -------
    str

    """
    return _gdal.GetGlobalConfigOption(*args)

def GetThreadLocalConfigOption(*args):
    r"""
    GetThreadLocalConfigOption(pszKey, pszDefault=None) -> char const *


    Return the value of a thread-local configuration option.
    See :cpp:func:`CPLGetThreadLocalConfigOption`.

    Parameters
    ----------
    pszKey : str
        name of the configuration option
    pszDefault : str, optional
        default value to return if the option has not been set

    Returns
    -------
    str


    """
    return _gdal.GetThreadLocalConfigOption(*args)

def GetConfigOptions(*args):
    r"""
    GetConfigOptions() -> char **


    Return a dictionary of currently set configuration options.
    See :cpp:func:`CPLGetConfigOptions`.

    Returns
    -------
    dict

    Examples
    --------
    >>> with gdal.config_options({'A': '3', 'B': '4'}):
    ...     gdal.SetConfigOption('C', '5')
    ...     gdal.GetConfigOptions()
    ...
    {'C': '5', 'A': '3', 'B': '4'}

    See Also
    --------
    :py:func:`GetConfigOption`
    :py:func:`GetGlobalConfigOptions`

    """
    return _gdal.GetConfigOptions(*args)

def SetPathSpecificOption(*args):
    r"""SetPathSpecificOption(pszPathPrefix, pszKey, pszValue)"""
    return _gdal.SetPathSpecificOption(*args)

def SetCredential(*args):
    r"""SetCredential(pszPathPrefix, pszKey, pszValue)"""
    return _gdal.SetCredential(*args)

def GetCredential(*args):
    r"""GetCredential(pszPathPrefix, pszKey, pszDefault=None) -> char const *"""
    return _gdal.GetCredential(*args)

def GetPathSpecificOption(*args):
    r"""GetPathSpecificOption(pszPathPrefix, pszKey, pszDefault=None) -> char const *"""
    return _gdal.GetPathSpecificOption(*args)

def ClearCredentials(*args):
    r"""ClearCredentials(pszPathPrefix=None)"""
    return _gdal.ClearCredentials(*args)

def ClearPathSpecificOptions(*args):
    r"""ClearPathSpecificOptions(pszPathPrefix=None)"""
    return _gdal.ClearPathSpecificOptions(*args)

def CPLBinaryToHex(*args):
    r"""CPLBinaryToHex(nBytes) -> retStringAndCPLFree *"""
    return _gdal.CPLBinaryToHex(*args)

def CPLHexToBinary(*args):
    r"""CPLHexToBinary(pszHex, pnBytes) -> GByte *"""
    return _gdal.CPLHexToBinary(*args)

def FileFromMemBuffer(*args):
    r"""FileFromMemBuffer(path, nBytes) -> VSI_RETVAL"""
    return _gdal.FileFromMemBuffer(*args)

def Unlink(*args):
    r"""Unlink(path) -> VSI_RETVAL"""
    return _gdal.Unlink(*args)

def UnlinkBatch(*args):
    r"""UnlinkBatch(files) -> bool"""
    return _gdal.UnlinkBatch(*args)

def HasThreadSupport(*args):
    r"""HasThreadSupport() -> int"""
    return _gdal.HasThreadSupport(*args)

def GetCurrentThreadCount(*args):
    r"""GetCurrentThreadCount() -> int"""
    return _gdal.GetCurrentThreadCount(*args)

def Mkdir(*args):
    r"""Mkdir(path, mode) -> VSI_RETVAL"""
    return _gdal.Mkdir(*args)

def Rmdir(*args):
    r"""Rmdir(path) -> VSI_RETVAL"""
    return _gdal.Rmdir(*args)

def MkdirRecursive(*args):
    r"""MkdirRecursive(path, mode) -> VSI_RETVAL"""
    return _gdal.MkdirRecursive(*args)

def RmdirRecursive(*args):
    r"""RmdirRecursive(path) -> VSI_RETVAL"""
    return _gdal.RmdirRecursive(*args)

def Rename(*args):
    r"""Rename(old_path, new_path) -> VSI_RETVAL"""
    return _gdal.Rename(*args)

def Move(*args, **kwargs):
    r"""Move(old_path, new_path, options=None, callback=0, callback_data=None) -> VSI_RETVAL"""
    return _gdal.Move(*args, **kwargs)

def Sync(*args, **kwargs):
    r"""Sync(pszSource, pszTarget, options=None, callback=0, callback_data=None) -> bool"""
    return _gdal.Sync(*args, **kwargs)

def AbortPendingUploads(*args):
    r"""AbortPendingUploads(path) -> bool"""
    return _gdal.AbortPendingUploads(*args)

def CopyFile(*args, **kwargs):
    r"""CopyFile(pszSource, pszTarget, fpSource=None, nSourceSize=-1, options=None, callback=0, callback_data=None) -> int"""
    return _gdal.CopyFile(*args, **kwargs)

def CopyFileRestartable(*args):
    r"""CopyFileRestartable(pszSource, pszTarget, pszInputPayload, options=None, callback=0, callback_data=None)"""
    return _gdal.CopyFileRestartable(*args)

def MoveFile(*args):
    r"""MoveFile(pszSource, pszTarget) -> int"""
    return _gdal.MoveFile(*args)

def GetActualURL(*args):
    r"""GetActualURL(path) -> char const *"""
    return _gdal.GetActualURL(*args)

def GetSignedURL(*args):
    r"""GetSignedURL(path, options=None) -> retStringAndCPLFree *"""
    return _gdal.GetSignedURL(*args)

def GetFileSystemsPrefixes(*args):
    r"""GetFileSystemsPrefixes() -> char **"""
    return _gdal.GetFileSystemsPrefixes(*args)

def GetFileSystemOptions(*args):
    r"""GetFileSystemOptions(path) -> char const *"""
    return _gdal.GetFileSystemOptions(*args)
class VSILFILE(object):
    r"""Proxy of C++ VSILFILE class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr

# Register VSILFILE in _gdal:
_gdal.VSILFILE_swigregister(VSILFILE)
VSI_STAT_EXISTS_FLAG = _gdal.VSI_STAT_EXISTS_FLAG

VSI_STAT_NATURE_FLAG = _gdal.VSI_STAT_NATURE_FLAG

VSI_STAT_SIZE_FLAG = _gdal.VSI_STAT_SIZE_FLAG

VSI_STAT_SET_ERROR_FLAG = _gdal.VSI_STAT_SET_ERROR_FLAG

VSI_STAT_CACHE_ONLY = _gdal.VSI_STAT_CACHE_ONLY

class StatBuf(object):
    r"""Proxy of C++ StatBuf class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    mode = property(_gdal.StatBuf_mode_get, doc=r"""mode""")
    size = property(_gdal.StatBuf_size_get, doc=r"""size""")
    mtime = property(_gdal.StatBuf_mtime_get, doc=r"""mtime""")

    def __init__(self, *args):
        r"""__init__(self, psStatBuf) -> StatBuf"""
        _gdal.StatBuf_swiginit(self, _gdal.new_StatBuf(*args))
    __swig_destroy__ = _gdal.delete_StatBuf

    def IsDirectory(self, *args):
        r"""IsDirectory(self) -> int"""
        return _gdal.StatBuf_IsDirectory(self, *args)

# Register StatBuf in _gdal:
_gdal.StatBuf_swigregister(StatBuf)

def VSIStatL(*args):
    r"""VSIStatL(path, nFlags=0) -> int"""
    return _gdal.VSIStatL(*args)

def GetFileMetadata(*args):
    r"""GetFileMetadata(path, domain, options=None) -> char **"""
    return _gdal.GetFileMetadata(*args)

def SetFileMetadata(*args):
    r"""SetFileMetadata(path, metadata, domain, options=None) -> bool"""
    return _gdal.SetFileMetadata(*args)

def VSIFOpenL(*args):
    r"""VSIFOpenL(path, pszMode) -> VSILFILE"""
    return _gdal.VSIFOpenL(*args)

def VSIFOpenExL(*args):
    r"""VSIFOpenExL(path, pszMode, bSetError=FALSE, options=None) -> VSILFILE"""
    return _gdal.VSIFOpenExL(*args)

def VSIFEofL(*args):
    r"""VSIFEofL(fp) -> int"""

    if args[0].this is None:
        raise ValueError("I/O operation on closed file.")


    return _gdal.VSIFEofL(*args)

def VSIFErrorL(*args):
    r"""VSIFErrorL(fp) -> int"""
    return _gdal.VSIFErrorL(*args)

def VSIFClearErrL(*args):
    r"""VSIFClearErrL(fp)"""
    return _gdal.VSIFClearErrL(*args)

def VSIFFlushL(*args):
    r"""VSIFFlushL(fp) -> int"""

    if args[0].this is None:
        raise ValueError("I/O operation on closed file.")


    return _gdal.VSIFFlushL(*args)

def VSIFCloseL(*args):
    r"""VSIFCloseL(fp) -> VSI_RETVAL"""

    if args[0].this is None:
        raise ValueError("I/O operation on closed file.")


    val = _gdal.VSIFCloseL(*args)

    args[0].this = None


    return val

def VSIFSeekL(*args):
    r"""VSIFSeekL(fp, offset, whence) -> int"""

    if args[0].this is None:
        raise ValueError("I/O operation on closed file.")


    return _gdal.VSIFSeekL(*args)

def VSIFTellL(*args):
    r"""VSIFTellL(fp) -> GIntBig"""

    if args[0].this is None:
        raise ValueError("I/O operation on closed file.")


    return _gdal.VSIFTellL(*args)

def VSIFTruncateL(*args):
    r"""VSIFTruncateL(fp, length) -> int"""

    if args[0].this is None:
        raise ValueError("I/O operation on closed file.")


    return _gdal.VSIFTruncateL(*args)

def VSISupportsSparseFiles(*args):
    r"""VSISupportsSparseFiles(path) -> int"""
    return _gdal.VSISupportsSparseFiles(*args)
VSI_RANGE_STATUS_UNKNOWN = _gdal.VSI_RANGE_STATUS_UNKNOWN

VSI_RANGE_STATUS_DATA = _gdal.VSI_RANGE_STATUS_DATA

VSI_RANGE_STATUS_HOLE = _gdal.VSI_RANGE_STATUS_HOLE


def VSIFGetRangeStatusL(*args):
    r"""VSIFGetRangeStatusL(fp, offset, length) -> int"""
    return _gdal.VSIFGetRangeStatusL(*args)

def VSIFWriteL(*args):
    r"""VSIFWriteL(nLen, size, memb, fp) -> int"""

    if args[3].this is None:
        raise ValueError("I/O operation on closed file.")


    return _gdal.VSIFWriteL(*args)

def CPLReadLineL(*args):
    r"""CPLReadLineL(fp) -> char const *"""
    return _gdal.CPLReadLineL(*args)

def NetworkStatsReset(*args):
    r"""NetworkStatsReset()"""
    return _gdal.NetworkStatsReset(*args)

def NetworkStatsGetAsSerializedJSON(*args):
    r"""NetworkStatsGetAsSerializedJSON(options=None) -> retStringAndCPLFree *"""
    return _gdal.NetworkStatsGetAsSerializedJSON(*args)

def ParseCommandLine(*args):
    r"""ParseCommandLine(path) -> char **"""
    return _gdal.ParseCommandLine(*args)

def GetNumCPUs(*args):
    r"""
    GetNumCPUs() -> int


    Return the number of processors detected by GDAL.

    Returns
    -------
    int

    """
    return _gdal.GetNumCPUs(*args)

def GetUsablePhysicalRAM(*args):
    r"""GetUsablePhysicalRAM() -> GIntBig"""
    return _gdal.GetUsablePhysicalRAM(*args)

def MultipartUploadGetCapabilities(*args):
    r"""MultipartUploadGetCapabilities(pszFilename)"""
    val = _gdal.MultipartUploadGetCapabilities(*args)

    if val:
        non_sequential_upload_supported, parallel_upload_supported, abort_supported, min_part_size, max_part_size, max_part_count = val
        import collections
        tuple = collections.namedtuple('MultipartUploadGetCapabilitiesResult',
            ['non_sequential_upload_supported',
             'parallel_upload_supported',
             'abort_supported',
             'min_part_size',
             'max_part_size',
             'max_part_count',
             ])
        tuple.non_sequential_upload_supported = non_sequential_upload_supported
        tuple.parallel_upload_supported = parallel_upload_supported
        tuple.abort_supported = abort_supported
        tuple.min_part_size = min_part_size
        tuple.max_part_size = max_part_size
        tuple.max_part_count = max_part_count
        val = tuple


    return val

def MultipartUploadStart(*args):
    r"""MultipartUploadStart(pszFilename, options=None) -> retStringAndCPLFree *"""
    return _gdal.MultipartUploadStart(*args)

def MultipartUploadAddPart(*args):
    r"""MultipartUploadAddPart(pszFilename, pszUploadId, nPartNumber, nFileOffset, nDataLength, options=None) -> retStringAndCPLFree *"""
    return _gdal.MultipartUploadAddPart(*args)

def MultipartUploadEnd(*args):
    r"""MultipartUploadEnd(pszFilename, pszUploadId, partIds, nTotalSize, options=None) -> bool"""
    return _gdal.MultipartUploadEnd(*args)

def MultipartUploadAbort(*args):
    r"""MultipartUploadAbort(pszFilename, pszUploadId, options=None) -> bool"""
    return _gdal.MultipartUploadAbort(*args)
class MajorObject(object):
    r"""Proxy of C++ GDALMajorObjectShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr

    def GetDescription(self, *args):
        r"""GetDescription(self) -> char const *"""
        return _gdal.MajorObject_GetDescription(self, *args)

    def SetDescription(self, *args):
        r"""SetDescription(self, pszNewDesc)"""
        return _gdal.MajorObject_SetDescription(self, *args)

    def GetMetadataDomainList(self, *args):
        r"""GetMetadataDomainList(self) -> char **"""
        return _gdal.MajorObject_GetMetadataDomainList(self, *args)

    def GetMetadata_Dict(self, *args):
        r"""GetMetadata_Dict(self, pszDomain="") -> char **"""
        return _gdal.MajorObject_GetMetadata_Dict(self, *args)

    def GetMetadata_List(self, *args):
        r"""GetMetadata_List(self, pszDomain="") -> char **"""
        return _gdal.MajorObject_GetMetadata_List(self, *args)

    def SetMetadata(self, *args):
        r"""
        SetMetadata(self, papszMetadata, pszDomain="") -> CPLErr
        SetMetadata(self, pszMetadataString, pszDomain="") -> CPLErr
        """
        return _gdal.MajorObject_SetMetadata(self, *args)

    def GetMetadataItem(self, *args):
        r"""GetMetadataItem(self, pszName, pszDomain="") -> char const *"""
        return _gdal.MajorObject_GetMetadataItem(self, *args)

    def SetMetadataItem(self, *args):
        r"""SetMetadataItem(self, pszName, pszValue, pszDomain="") -> CPLErr"""
        return _gdal.MajorObject_SetMetadataItem(self, *args)

    def GetMetadata(self, domain=''):
      if domain and (domain[:4] == 'xml:' or domain[:5] == 'json:'):
        return self.GetMetadata_List(domain)
      return self.GetMetadata_Dict(domain)


# Register MajorObject in _gdal:
_gdal.MajorObject_swigregister(MajorObject)
class Driver(MajorObject):
    r"""

    Python proxy of a :cpp:class:`GDALDriver`.

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    ShortName = property(_gdal.Driver_ShortName_get, doc=r"""
    ShortName

    The short name of a :py:class:`Driver` that can be passed to
    :py:func:`GetDriverByName`.
    See :cpp:func:`GDALGetDriverShortName`.

    """)
    LongName = property(_gdal.Driver_LongName_get, doc=r"""
    LongName

    The long name of the driver.
    See :cpp:func:`GDALGetDriverLongName`.

    """)
    HelpTopic = property(_gdal.Driver_HelpTopic_get, doc=r"""
    HelpTopic

    The URL for driver documentation, relative to the GDAL documentation directory.
    See :cpp:func:`GDALGetDriverHelpTopic`.

    """)

    def Create(self, *args, **kwargs):
        r"""
        Create(self, path, xsize, ysize, bands=1, eType=GDT_Byte, options=None) -> Dataset


        Create a new :py:class:`Dataset` with this driver.
        See :cpp:func:`GDALDriver::Create`.

        Parameters
        ----------
        path : str
           Path of the dataset to create.
        xsize : int
           Width of created raster in pixels. Set to zero for vector datasets.
        ysize : int
           Height of created raster in pixels. Set to zero for vector datasets.
        bands : int, default = 1
            Number of bands. Set to zero for vector datasets.
        eType : int or numpy.dtype, default = :py:const:`GDT_Byte`
            Raster data type. Set to :py:const:`GDT_Unknown` for vector datasets.
        options : list or dict
            List of driver-specific options

        Returns
        -------
        Dataset

        Examples
        --------
        >>> with gdal.GetDriverByName('GTiff').Create('test.tif', 12, 4, 2, gdal.GDT_Float32, {'COMPRESS': 'DEFLATE'}) as ds:
        ...     print(gdal.Info(ds))
        ...
        Driver: GTiff/GeoTIFF
        Files: test.tif
        Size is 12, 4
        Image Structure Metadata:
          INTERLEAVE=PIXEL
        Corner Coordinates:
        Upper Left  (    0.0,    0.0)
        Lower Left  (    0.0,    4.0)
        Upper Right (   12.0,    0.0)
        Lower Right (   12.0,    4.0)
        Center      (    6.0,    2.0)
        Band 1 Block=12x4 Type=Float32, ColorInterp=Gray
        Band 2 Block=12x4 Type=Float32, ColorInterp=Undefined

        >>> with gdal.GetDriverByName('ESRI Shapefile').Create('test.shp', 0, 0, 0, gdal.GDT_Unknown) as ds:
        ...     print(gdal.VectorInfo(ds))
        ...
        INFO: Open of `test.shp'
              using driver `ESRI Shapefile' successful.

        """

        _WarnIfUserHasNotSpecifiedIfUsingExceptions()


        return _gdal.Driver_Create(self, *args, **kwargs)


    def CreateVector(self, *args, **kwargs):
        r"""
        CreateVector(self, path, options=None) -> Dataset


        Create a new vector :py:class:`Dataset` with this driver.
        This method is an alias for ``Create(name, 0, 0, 0, gdal.GDT_Unknown)``.

        Parameters
        ----------
        path : str
           Path of the dataset to create.

        Returns
        -------
        Dataset

        Examples
        --------
        >>> with gdal.GetDriverByName('ESRI Shapefile').CreateVector('test.shp') as ds:
        ...     print(ds.GetLayerCount())
        ...
        0


        """
        return _gdal.Driver_CreateVector(self, *args, **kwargs)

    def CreateMultiDimensional(self, *args, **kwargs):
        r"""
        CreateMultiDimensional(self, path, root_group_options=None, options=None) -> Dataset


        Create a new multidimensional dataset.
        See :cpp:func:`GDALDriver::CreateMultiDimensional`.

        Parameters
        ----------
        path : str
           Path of the dataset to create.
        root_group_options : list or dict
           Driver-specific options regarding the creation of the
           root group.
        options : list or dict
           List of driver-specific options regarding the creation
           of the Dataset.

        Returns
        -------
        Dataset

        Examples
        --------
        .. testsetup::
           >>> if gdal.GetDriverByName('netCDF') is None:
           ...     pytest.skip()

        >>> with gdal.GetDriverByName('netCDF').CreateMultiDimensional('test.nc') as ds:
        ...     gdal.MultiDimInfo(ds)
        ...
        {'type': 'group', 'driver': 'netCDF', 'name': '/', 'attributes': {'Conventions': 'CF-1.6'}, 'structural_info': {'NC_FORMAT': 'NETCDF4'}}


        """

        _WarnIfUserHasNotSpecifiedIfUsingExceptions()


        return _gdal.Driver_CreateMultiDimensional(self, *args, **kwargs)


    def CreateCopy(self, *args, **kwargs):
        r"""
        CreateCopy(self, path, src, strict=1, options=None, callback=0, callback_data=None) -> Dataset


        Create a copy of a :py:class:`Dataset`.
        See :cpp:func:`GDALDriver::CreateCopy`.

        Parameters
        ----------
        path : str
           Path of the dataset to create.
        src : Dataset
           The dataset being duplicated.
        strict : bool, default=1
           Indicates whether the copy must be strictly equivalent or if
           it may be adapted as needed for the output format.
        options : list or dict
           List of driver-specific options
        callback : callable, optional
           A progress callback function
        callback_data : any, optional
           Optional data to be passed to callback function

        Returns
        -------
        Dataset

        """

        _WarnIfUserHasNotSpecifiedIfUsingExceptions()

        if len(args) >= 2 and isinstance(args[1], Band):
            ds = args[1].GetDataset()
            if ds:
                args = [arg for arg in args]
                args[1] = ds
                args = tuple(args)



        return _gdal.Driver_CreateCopy(self, *args, **kwargs)


    def Delete(self, *args):
        r"""
        Delete(self, path) -> CPLErr

        Delete a :py:class:`Dataset`.
        See :cpp:func:`GDALDriver::Delete`.

        Parameters
        ----------
        path : str
           Path of the dataset to delete.

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        """

        _WarnIfUserHasNotSpecifiedIfUsingExceptions()


        return _gdal.Driver_Delete(self, *args)


    def Rename(self, *args):
        r"""
        Rename(self, newName, oldName) -> CPLErr

        Rename a :py:class:`Dataset`.
        See :cpp:func:`GDALDriver::Rename`.

        Parameters
        ----------
        newName : str
            new path for the dataset
        oldName : str
            old path for the dataset

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        """
        return _gdal.Driver_Rename(self, *args)

    def CopyFiles(self, *args):
        r"""
        CopyFiles(self, newName, oldName) -> CPLErr

        Copy all the files associated with a :py:class:`Dataset`.

        Parameters
        ----------
        newName : str
            new path for the dataset
        oldName : str
            old path for the dataset

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        """
        return _gdal.Driver_CopyFiles(self, *args)

    def HasOpenOption(self, *args):
        r"""
        HasOpenOption(self, openOptionName) -> bool


        Reports whether the driver supports a specified open option.

        Parameters
        ----------
        openOptionName : str
           The name of the option to test

        Returns
        -------
        bool
           ``True``, if the option is supported by this driver, ``False`` otherwise.

        Examples
        --------
        >>> gdal.GetDriverByName('GPKG').HasOpenOption('PRELUDE_STATEMENTS')
        True
        >>> gdal.GetDriverByName('GPKG').HasOpenOption('CLOSING_STATEMENTS')
        False


        """
        return _gdal.Driver_HasOpenOption(self, *args)

    def TestCapability(self, *args):
        r"""
        TestCapability(self, cap) -> bool


        Check whether the driver supports a specified capability
        (:py:const:`ogr.ODrCCreateDataSource` or
        :py:const:`ogr.ODrCDeleteDataSource`)`.

        Parameters
        ----------
        cap : str
            The name of the capability to test

        Returns
        -------
        bool
           ``True`` if the driver supports the capability, ``False`` otherwise.

        Examples
        --------
        >>> gdal.GetDriverByName('ESRI Shapefile').TestCapability(ogr.ODrCCreateDataSource)
        True
        >>> gdal.GetDriverByName('GTiff').TestCapability(ogr.ODrCCreateDataSource)
        True


        """
        return _gdal.Driver_TestCapability(self, *args)

    def Register(self, *args):
        r"""
        Register(self) -> int

        Register the driver for use.
        See :cpp:func:`GDALDriverManager::RegisterDriver`.

        """
        return _gdal.Driver_Register(self, *args)

    def Deregister(self, *args):
        r"""
        Deregister(self)

        Deregister the driver.
        See :cpp:func:`GDALDriverManager::DeregisterDriver`.

        """
        return _gdal.Driver_Deregister(self, *args)


    def CreateDataSource(self, utf8_string, options=None):
        """
        Synonym for :py:meth:`CreateVector`.
        """
        return self.Create(utf8_string, 0, 0, 0, GDT_Unknown, options or [])

    def CopyDataSource(self, ds, utf8_string, options=None):
        """
        Synonym for :py:meth:`CreateCopy`.
        """
        return self.CreateCopy(utf8_string, ds, options = options or [])

    def DeleteDataSource(self, utf8_string):
        """
        Synonym for :py:meth:`Delete`.
        """
        return self.Delete(utf8_string)

    def Open(self, utf8_string, update=False):
        """
        Attempt to open a specified path with this driver.

        Parameters
        ----------
        utf8_string : str
           The path to open
        update : bool, default = False
           Whether to open the dataset in update mode.

        Returns
        -------
        Dataset or None
            ``None`` on error
        """
        return OpenEx(utf8_string,
                      OF_VECTOR | (OF_UPDATE if update else 0),
                      [self.GetDescription()])

    def GetName(self):
        """
        Synonym for :py:meth:`GetDescription`.
        """
        return self.GetDescription()


# Register Driver in _gdal:
_gdal.Driver_swigregister(Driver)
from . import ogr
from . import osr
class ColorEntry(object):
    r"""Proxy of C++ GDALColorEntry class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    c1 = property(_gdal.ColorEntry_c1_get, _gdal.ColorEntry_c1_set, doc=r"""c1""")
    c2 = property(_gdal.ColorEntry_c2_get, _gdal.ColorEntry_c2_set, doc=r"""c2""")
    c3 = property(_gdal.ColorEntry_c3_get, _gdal.ColorEntry_c3_set, doc=r"""c3""")
    c4 = property(_gdal.ColorEntry_c4_get, _gdal.ColorEntry_c4_set, doc=r"""c4""")

# Register ColorEntry in _gdal:
_gdal.ColorEntry_swigregister(ColorEntry)
class GCP(object):
    r"""Proxy of C++ GDAL_GCP class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    GCPX = property(_gdal.GCP_GCPX_get, _gdal.GCP_GCPX_set, doc=r"""GCPX""")
    GCPY = property(_gdal.GCP_GCPY_get, _gdal.GCP_GCPY_set, doc=r"""GCPY""")
    GCPZ = property(_gdal.GCP_GCPZ_get, _gdal.GCP_GCPZ_set, doc=r"""GCPZ""")
    GCPPixel = property(_gdal.GCP_GCPPixel_get, _gdal.GCP_GCPPixel_set, doc=r"""GCPPixel""")
    GCPLine = property(_gdal.GCP_GCPLine_get, _gdal.GCP_GCPLine_set, doc=r"""GCPLine""")
    Info = property(_gdal.GCP_Info_get, _gdal.GCP_Info_set, doc=r"""Info""")
    Id = property(_gdal.GCP_Id_get, _gdal.GCP_Id_set, doc=r"""Id""")

    def __init__(self, *args):
        r"""__init__(self, x=0.0, y=0.0, z=0.0, pixel=0.0, line=0.0, info="", id="") -> GCP"""
        _gdal.GCP_swiginit(self, _gdal.new_GCP(*args))
    __swig_destroy__ = _gdal.delete_GCP

    def __str__(self):
      str = '%s (%.2fP,%.2fL) -> (%.7fE,%.7fN,%.2f) %s '\
            % (self.Id, self.GCPPixel, self.GCPLine,
               self.GCPX, self.GCPY, self.GCPZ, self.Info )
      return str

    def serialize(self, with_Z=0):
      base = [gdalconst.CXT_Element, 'GCP']
      base.append([gdalconst.CXT_Attribute, 'Id', [gdalconst.CXT_Text, self.Id]])
      pixval = '%0.15E' % self.GCPPixel
      lineval = '%0.15E' % self.GCPLine
      xval = '%0.15E' % self.GCPX
      yval = '%0.15E' % self.GCPY
      zval = '%0.15E' % self.GCPZ
      base.append([gdalconst.CXT_Attribute, 'Pixel', [gdalconst.CXT_Text, pixval]])
      base.append([gdalconst.CXT_Attribute, 'Line', [gdalconst.CXT_Text, lineval]])
      base.append([gdalconst.CXT_Attribute, 'X', [gdalconst.CXT_Text, xval]])
      base.append([gdalconst.CXT_Attribute, 'Y', [gdalconst.CXT_Text, yval]])
      if with_Z:
          base.append([gdalconst.CXT_Attribute, 'Z', [gdalconst.CXT_Text, zval]])
      return base



# Register GCP in _gdal:
_gdal.GCP_swigregister(GCP)

def GDAL_GCP_GCPX_get(*args):
    r"""GDAL_GCP_GCPX_get(gcp) -> double"""
    return _gdal.GDAL_GCP_GCPX_get(*args)

def GDAL_GCP_GCPX_set(*args):
    r"""GDAL_GCP_GCPX_set(gcp, dfGCPX)"""
    return _gdal.GDAL_GCP_GCPX_set(*args)

def GDAL_GCP_GCPY_get(*args):
    r"""GDAL_GCP_GCPY_get(gcp) -> double"""
    return _gdal.GDAL_GCP_GCPY_get(*args)

def GDAL_GCP_GCPY_set(*args):
    r"""GDAL_GCP_GCPY_set(gcp, dfGCPY)"""
    return _gdal.GDAL_GCP_GCPY_set(*args)

def GDAL_GCP_GCPZ_get(*args):
    r"""GDAL_GCP_GCPZ_get(gcp) -> double"""
    return _gdal.GDAL_GCP_GCPZ_get(*args)

def GDAL_GCP_GCPZ_set(*args):
    r"""GDAL_GCP_GCPZ_set(gcp, dfGCPZ)"""
    return _gdal.GDAL_GCP_GCPZ_set(*args)

def GDAL_GCP_GCPPixel_get(*args):
    r"""GDAL_GCP_GCPPixel_get(gcp) -> double"""
    return _gdal.GDAL_GCP_GCPPixel_get(*args)

def GDAL_GCP_GCPPixel_set(*args):
    r"""GDAL_GCP_GCPPixel_set(gcp, dfGCPPixel)"""
    return _gdal.GDAL_GCP_GCPPixel_set(*args)

def GDAL_GCP_GCPLine_get(*args):
    r"""GDAL_GCP_GCPLine_get(gcp) -> double"""
    return _gdal.GDAL_GCP_GCPLine_get(*args)

def GDAL_GCP_GCPLine_set(*args):
    r"""GDAL_GCP_GCPLine_set(gcp, dfGCPLine)"""
    return _gdal.GDAL_GCP_GCPLine_set(*args)

def GDAL_GCP_Info_get(*args):
    r"""GDAL_GCP_Info_get(gcp) -> char const *"""
    return _gdal.GDAL_GCP_Info_get(*args)

def GDAL_GCP_Info_set(*args):
    r"""GDAL_GCP_Info_set(gcp, pszInfo)"""
    return _gdal.GDAL_GCP_Info_set(*args)

def GDAL_GCP_Id_get(*args):
    r"""GDAL_GCP_Id_get(gcp) -> char const *"""
    return _gdal.GDAL_GCP_Id_get(*args)

def GDAL_GCP_Id_set(*args):
    r"""GDAL_GCP_Id_set(gcp, pszId)"""
    return _gdal.GDAL_GCP_Id_set(*args)

def GCPsToGeoTransform(*args):
    r"""GCPsToGeoTransform(nGCPs, bApproxOK=1) -> RETURN_NONE"""
    return _gdal.GCPsToGeoTransform(*args)

def GCPsToHomography(*args):
    r"""GCPsToHomography(nGCPs) -> RETURN_NONE"""
    return _gdal.GCPsToHomography(*args)
class VirtualMem(object):
    r"""Proxy of C++ CPLVirtualMemShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_VirtualMem

    def GetAddr(self, *args):
        r"""GetAddr(self)"""
        return _gdal.VirtualMem_GetAddr(self, *args)

    def Pin(self, *args):
        r"""Pin(self, start_offset=0, nsize=0, bWriteOp=0)"""
        return _gdal.VirtualMem_Pin(self, *args)

# Register VirtualMem in _gdal:
_gdal.VirtualMem_swigregister(VirtualMem)
class AsyncReader(object):
    r"""Proxy of C++ GDALAsyncReaderShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_AsyncReader

    def GetNextUpdatedRegion(self, *args):
        r"""GetNextUpdatedRegion(self, timeout) -> GDALAsyncStatusType"""
        return _gdal.AsyncReader_GetNextUpdatedRegion(self, *args)

    def GetBuffer(self, *args):
        r"""GetBuffer(self)"""
        return _gdal.AsyncReader_GetBuffer(self, *args)

    def LockBuffer(self, *args):
        r"""LockBuffer(self, timeout) -> int"""
        return _gdal.AsyncReader_LockBuffer(self, *args)

    def UnlockBuffer(self, *args):
        r"""UnlockBuffer(self)"""
        return _gdal.AsyncReader_UnlockBuffer(self, *args)

# Register AsyncReader in _gdal:
_gdal.AsyncReader_swigregister(AsyncReader)
class Dataset(MajorObject):
    r"""

    Python proxy of a :cpp:class:`GDALDataset`.

    Since GDAL 3.8, a Dataset can be used as a context manager.
    When exiting the context, the Dataset will be closed and
    data will be written to disk.

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    RasterXSize = property(_gdal.Dataset_RasterXSize_get, doc=r"""
    RasterXSize


    Raster width in pixels. See :cpp:func:`GDALGetRasterXSize`.


    """)
    RasterYSize = property(_gdal.Dataset_RasterYSize_get, doc=r"""
    RasterYSize


    Raster height in pixels. See :cpp:func:`GDALGetRasterYSize`.


    """)
    RasterCount = property(_gdal.Dataset_RasterCount_get, doc=r"""
    RasterCount


    The number of bands in this dataset.


    """)
    __swig_destroy__ = _gdal.delete_Dataset

    def MarkSuppressOnClose(self, *args):
        r"""MarkSuppressOnClose(self)"""
        return _gdal.Dataset_MarkSuppressOnClose(self, *args)

    def Close(self, callback=None, callback_data=None):
        r"""
        Close(Dataset self, callback=Callable|None, callback_data=any|None) -> CPLErr

        Closes opened dataset and releases allocated resources.

        This method can be used to force the dataset to close
        when one more references to the dataset are still
        reachable. If :py:meth:`Close` is never called, the dataset will
        be closed automatically during garbage collection.

        It is illegal to call any method on the dataset or objects derived
        from it (bands, layers, etc.) afterwards.

        In most cases, it is preferable to open or create a dataset
        using a context manager instead of calling :py:meth:`Close`
        directly.

        This function may report progress if a progress
        callback if provided and if the dataset returns True for
        GetCloseReportsProgress()

        Parameters
        ----------
        callback: Callable|None
            Callable that accepts (pct: float, message: str, user_data) and returns bool
        callback_data: any|None
            User data to pass to the callback
        """

        self._invalidate_children()
        if self.GetRefCount() == 1 and self.thisown:
            try:
                return _gdal.Dataset_Close(self, callback, callback_data)
            finally:
                self.thisown = 0
                self.this = None
        else:
            return _gdal.Dataset__RunCloseWithoutDestroying(self, callback, callback_data)



    def GetCloseReportsProgress(self, *args):
        r"""GetCloseReportsProgress(self) -> bool"""
        return _gdal.Dataset_GetCloseReportsProgress(self, *args)

    def _RunCloseWithoutDestroying(self, *args):
        r"""_RunCloseWithoutDestroying(self, callback=0, callback_data=None) -> CPLErr"""
        return _gdal.Dataset__RunCloseWithoutDestroying(self, *args)

    def GetDriver(self, *args):
        r"""
        GetDriver(self) -> Driver


        Fetch the driver used to open or create this :py:class:`Dataset`.


        """

        from . import gdal


        return _gdal.Dataset_GetDriver(self, *args)


    def GetRasterBand(self, *args):
        r"""
        GetRasterBand(self, nBand) -> Band


        Fetch a :py:class:`Band` band from a :py:class:`Dataset`. See :cpp:func:`GDALGetRasterBand`.

        Parameters
        ----------
        nBand : int
            the index of the band to fetch, from 1 to :py:attr:`RasterCount`

        Returns
        -------
        Band
            the :py:class:`Band`, or ``None`` on error.


        """
        val = _gdal.Dataset_GetRasterBand(self, *args)

        self._add_child_ref(val)


        return val


    def IsThreadSafe(self, *args):
        r"""IsThreadSafe(self, nScopeFlags) -> bool"""
        return _gdal.Dataset_IsThreadSafe(self, *args)

    def GetThreadSafeDataset(self, *args):
        r"""GetThreadSafeDataset(self, nScopeFlags) -> Dataset"""
        val = _gdal.Dataset_GetThreadSafeDataset(self, *args)

        if val:
            val._parent_ds = self

            import weakref
            if not hasattr(self, '_child_references'):
                self._child_references = weakref.WeakSet()
            self._child_references.add(val)


        return val


    def GetRootGroup(self, *args):
        r"""
        GetRootGroup(self) -> Group


        Return the root :py:class:`Group` of this dataset.
        Only value for multidimensional datasets.

        Returns
        -------
        Group


        """
        return _gdal.Dataset_GetRootGroup(self, *args)

    def GetProjection(self, *args):
        r"""
        GetProjection(self) -> char const *


        Return a WKT representation of the dataset spatial reference.
        Equivalent to :py:meth:`GetProjectionRef`.

        Returns
        -------
        str


        """
        return _gdal.Dataset_GetProjection(self, *args)

    def GetProjectionRef(self, *args):
        r"""
        GetProjectionRef(self) -> char const *


        Return a WKT representation of the dataset spatial reference.

        Returns
        -------
        str


        """
        return _gdal.Dataset_GetProjectionRef(self, *args)

    def GetRefCount(self, *args):
        r"""GetRefCount(self) -> int"""
        return _gdal.Dataset_GetRefCount(self, *args)

    def GetSummaryRefCount(self, *args):
        r"""GetSummaryRefCount(self) -> int"""
        return _gdal.Dataset_GetSummaryRefCount(self, *args)

    def GetSpatialRef(self, *args):
        r"""
        GetSpatialRef(self) -> SpatialReference


        Fetch the spatial reference for this dataset.

        Returns
        -------
        SpatialReference


        """
        return _gdal.Dataset_GetSpatialRef(self, *args)

    def SetProjection(self, *args):
        r"""
        SetProjection(self, prj) -> CPLErr


        Set the spatial reference system for this dataset.

        See :cpp:func:`GDALDataset::SetProjection`.

        Parameters
        ----------
        prj : str
           The projection string in OGC WKT or PROJ.4 format

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.


        """
        return _gdal.Dataset_SetProjection(self, *args)

    def SetSpatialRef(self, *args):
        r"""
        SetSpatialRef(self, srs) -> CPLErr


        Set the spatial reference system for this dataset.

        Parameters
        ----------
        srs : SpatialReference

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.


        """
        return _gdal.Dataset_SetSpatialRef(self, *args)

    def GetGeoTransform(self, *args, **kwargs):
        r"""
        GetGeoTransform(self, can_return_null=None)


        Fetch the affine transformation coefficients.

        See :cpp:func:`GDALGetGeoTransform`.

        Parameters
        ----------
        can_return_null : bool, default=False
            if ``True``, return ``None`` instead of the default transformation
            if the transformation for this :py:class:`Dataset` has not been defined.

        Returns
        -------
        tuple
            a 6-member tuple representing the transformation coefficients



        """
        return _gdal.Dataset_GetGeoTransform(self, *args, **kwargs)

    def SetGeoTransform(self, *args):
        r"""
        SetGeoTransform(self, argin) -> CPLErr


        Set the affine transformation coefficients.

        See :py:meth:`GetGeoTransform` for details on the meaning of the coefficients.

        Parameters
        ----------
        argin : tuple

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.


        """
        return _gdal.Dataset_SetGeoTransform(self, *args)

    def GetExtent(self, *args, **kwargs):
        r"""
        GetExtent(self, srs=None)

        Get the extent of the dataset.

        See :cpp:func:`GDALDataset::GetExtent`

        .. versionadded:: 3.12

        .. warning:: Check the return order of the bounds.

        Parameters
        ----------
        srs : SpatialReference, optional
           Optional spatial reference in which the bounds should be
           returned. Defaults to ``None``.

        Returns
        -------
        tuple or None
            tuple of (minx, maxx, miny, maxy) or None if the extent cannot be
            determined in the specified spatial reference system

        Examples
        --------
        >>> # Get extent in native SRS (NAD27 / UTM 11N)
        >>> with gdal.Open('byte.tif') as ds:
        ...     ds.GetExtent()
        (440720.0, 441920.0, 3750120.0, 3751320.0)

        >>> # Get extent in US National Atlas Equal Area
        >>> with gdal.Open('byte.tif') as ds:
        ...     ds.GetExtent(osr.SpatialReference(epsg=9311))
        ...
        (-1621603.0, -1620214.9, -1064263.1, -1062837.1)

        See Also
        --------
        :py:meth:`GetExtentWGS84LongLat`


        """
        return _gdal.Dataset_GetExtent(self, *args, **kwargs)

    def GetExtentWGS84LongLat(self, *args, **kwargs):
        r"""
        GetExtentWGS84LongLat(self)


        Return the extent of the dataset in WGS84, with the x-axis representing
        longitude and the y-axis representing latitude.

        See :cpp:func:`GDALDataset::GetExtentWGS84LongLat`

        .. versionadded:: 3.12

        .. warning:: Check the return order of the bounds.

        Returns
        -------
        tuple or None
            tuple of (minlon, maxlon, minlat, maxlat) or None if the extent cannot be
            determined in WGS84

        Examples
        --------
        >>> with gdal.Open('byte.tif') as ds:
        ...     ds.GetExtentWGS84LongLat()
        ...
        (-117.642, -117.629, 33.892, 33.902)

        See Also
        --------
        :py:meth:`GetExtent`



        """
        return _gdal.Dataset_GetExtentWGS84LongLat(self, *args, **kwargs)

    def BuildOverviews(self, *args, **kwargs):
        r"""
        BuildOverviews(self, resampling="NEAREST", overviewlist=0, callback=0, callback_data=None, options=None) -> int


        Build raster overview(s) for all bands.

        See :cpp:func:`GDALDataset::BuildOverviews`

        Parameters
        ----------
        resampling : str, optional
                     The resampling method to use. See :cpp:func:`GDALDataset::BuildOverviews`.
        overviewlist : list
                     A list of overview levels (decimation factors) to build, or an
                     empty list to clear existing overviews.
        callback : callable, optional
                     A progress callback function
        callback_data : any, optional
                     Optional data to be passed to callback function
        options : dict or list, optional
                     A dict or list of key=value options

        Returns
        -------
        int
            :py:const:`CE_Failure` if an error occurs, otherwise
            :py:const:`CE_None`.

        Examples
        --------
        >>> import numpy as np
        >>> ds = gdal.GetDriverByName('GTiff').Create('test.tif', 12, 12)
        >>> ds.GetRasterBand(1).WriteArray(np.arange(12*12).reshape((12, 12)))
        0
        >>> ds.BuildOverviews('AVERAGE', [2, 4])
        0
        >>> ds.GetRasterBand(1).GetOverviewCount()
        2
        >>> ds.BuildOverviews(overviewlist=[])
        0
        >>> ds.GetRasterBand(1).GetOverviewCount()
        0

        """
        return _gdal.Dataset_BuildOverviews(self, *args, **kwargs)

    def GetGCPCount(self, *args):
        r"""
        GetGCPCount(self) -> int


        Get number of GCPs. See :cpp:func:`GDALGetGCPCount`.

        Returns
        -------
        int


        """
        return _gdal.Dataset_GetGCPCount(self, *args)

    def GetGCPProjection(self, *args):
        r"""
        GetGCPProjection(self) -> char const *


        Return a WKT representation of the GCP spatial reference.

        Returns
        -------
        str


        """
        return _gdal.Dataset_GetGCPProjection(self, *args)

    def GetGCPSpatialRef(self, *args):
        r"""
        GetGCPSpatialRef(self) -> SpatialReference


        Get output spatial reference system for GCPs.

        See :cpp:func:`GDALGetGCPSpatialRef`


        """
        return _gdal.Dataset_GetGCPSpatialRef(self, *args)

    def GetGCPs(self, *args):
        r"""
        GetGCPs(self)


        Get the GCPs. See :cpp:func:`GDALGetGCPs`.

        Returns
        -------
        tuple
            a tuple of :py:class:`GCP` objects.


        """
        return _gdal.Dataset_GetGCPs(self, *args)

    def _SetGCPs(self, *args):
        r"""
        _SetGCPs(self, nGCPs, pszGCPProjection) -> CPLErr


        """
        return _gdal.Dataset__SetGCPs(self, *args)

    def _SetGCPs2(self, *args):
        r"""_SetGCPs2(self, nGCPs, hSRS) -> CPLErr"""
        return _gdal.Dataset__SetGCPs2(self, *args)

    def FlushCache(self, *args):
        r"""
        FlushCache(self) -> CPLErr


        Flush all write-cached data to disk.

        See :cpp:func:`GDALDataset::FlushCache`.

        Returns
        -------
        int
            `gdal.CE_None` in case of success

        """
        return _gdal.Dataset_FlushCache(self, *args)

    def AddBand(self, *args, **kwargs):
        r"""
        AddBand(self, datatype=GDT_Byte, options=None) -> CPLErr


        Adds a band to a :py:class:`Dataset`.

        Not supported by all drivers.

        Parameters
        ----------
        datatype : int
            the data type of the pixels in the new band
        options : dict or list, optional
            an optional dict or list of format-specific ``NAME=VALUE`` option strings.

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        Examples
        --------
        >>> ds=gdal.GetDriverByName('MEM').Create('', 10, 10)
        >>> ds.RasterCount
        1
        >>> ds.AddBand(gdal.GDT_Float32)
        0
        >>> ds.RasterCount
        2

        """
        return _gdal.Dataset_AddBand(self, *args, **kwargs)

    def CreateMaskBand(self, *args):
        r"""
        CreateMaskBand(self, nFlags) -> CPLErr


        Adds a mask band to the dataset.

        See :cpp:func:`GDALDataset::CreateMaskBand`.

        Parameters
        ----------
        flags : int

        Returns
        -------
        int
            :py:const:`CE_Failure` if an error occurs, otherwise :py:const:`CE_None`.


        """
        return _gdal.Dataset_CreateMaskBand(self, *args)

    def GetFileList(self, *args):
        r"""
        GetFileList(self) -> char **


        Returns a list of files believed to be part of this dataset.
        See :cpp:func:`GDALGetFileList`.


        """
        return _gdal.Dataset_GetFileList(self, *args)

    def WriteRaster(self, *args, **kwargs):
        r"""WriteRaster(self, xoff, yoff, xsize, ysize, buf_len, buf_xsize=None, buf_ysize=None, buf_type=None, band_list=0, buf_pixel_space=None, buf_line_space=None, buf_band_space=None) -> CPLErr"""
        return _gdal.Dataset_WriteRaster(self, *args, **kwargs)

    def AdviseRead(self, *args, **kwargs):
        r"""
        AdviseRead(self, xoff, yoff, xsize, ysize, buf_xsize=None, buf_ysize=None, buf_type=None, band_list=0, options=None) -> CPLErr


        Advise driver of upcoming read requests.

        See :cpp:func:`GDALDataset::AdviseRead`.


        """
        return _gdal.Dataset_AdviseRead(self, *args, **kwargs)

    def BeginAsyncReader(self, *args, **kwargs):
        r"""BeginAsyncReader(self, xOff, yOff, xSize, ySize, buf_len, buf_xsize, buf_ysize, bufType=(GDALDataType) 0, band_list=0, nPixelSpace=0, nLineSpace=0, nBandSpace=0, options=None) -> AsyncReader"""
        return _gdal.Dataset_BeginAsyncReader(self, *args, **kwargs)

    def EndAsyncReader(self, *args):
        r"""EndAsyncReader(self, ario)"""
        return _gdal.Dataset_EndAsyncReader(self, *args)

    def GetInterBandCovarianceMatrix(self,
                                 band_list=None,
                                 approx_ok=False,
                                 force=False,
                                 write_into_metadata=True,
                                 delta_degree_of_freedom=1,
                                 callback=None,
                                 callback_data=None):
        """
        Fetch or compute the covariance matrix between bands of this dataset.

        The covariance indicates the level to which two bands vary together.

        If we call :math:`v_i[y,x]` the value of pixel at row=y and column=x for band i,
        and :math:`mean_i` the mean value of all pixels of band i, then

        .. math::

            \\mathrm{cov}\\left[i,j\\right] =
            \\frac{
                \\sum_{y,x} \\left( v_{i}[y,x] - \\mathrm{mean}_{i} \\right)
                \\left( v_{j}[y,x] - \\mathrm{mean}_{j} \\right)
            }{
                \\mathrm{pixel\\_count} - \\mathrm{delta\\_degree\\_of\\_freedom}
            }

        When there are no nodata values, :math:`pixel\\_count = self.RasterXSize * self.RasterYSize`.
        We can see that :math:`cov[i,j] = cov[j,i]`, and consequently the returned matrix
        is symmetric.

        A value of delta_degree_of_freedom=1 (the default) will return a unbiased estimate
        if the pixels in bands are considered to be a sample of the whole population.
        This is consistent with the default of
        https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
        matrix is consistent with what can be obtained with

        .. code-block:: python

           numpy.cov(
              [ds.GetRasterBand(band_nr).ReadAsArray().ravel() for band_nr in band_list]
           )

        Otherwise a value of delta_degree_of_freedom=0 can be used if they are considered
        to be the whole population.

        If STATISTICS_COVARIANCES metadata items are available in band metadata,
        this method uses them.
        Otherwise, if bForce is true, :py:meth:`ComputeInterBandCovarianceMatrix` is called.
        Otherwise, if bForce is false, an empty vector is returned

        Parameters
        ----------
        band_list: list[int], optional
            If not specified, compute the covariance matrix of all bands of the dataset.
            Otherwise compute it on the subset of bands specified by band_list.
            Values in band_list must be between 1 and self.RasterCount.
        approx_ok : bool, optional
            Whether it is acceptable to use a subsample of values in
            :py:meth:`ComputeInterBandCovarianceMatrix`
        force : bool | None, optional
            Whether :py:meth:`ComputeInterBandCovarianceMatrix` should be called
            when the STATISTICS_COVARIANCES metadata items are missing.
        write_into_metadata : bool, optional
            Whether :py:meth:`ComputeInterBandCovarianceMatrix` must
            write STATISTICS_COVARIANCES band metadata items.
        delta_degree_of_freedom : int, optional
            Correction term to subtract in the final averaging phase of the covariance computation.
        callback : callable, optional
            A progress callback function
        callback_data : any, optional
            Optional data to be passed to callback function

        Returns
        -------
        List[List[float]]
            a list of len(band_list) of lists of len(band_list) values (where len(band_list) == self.RasterCount if band_list not set)

        Examples
        --------
        .. testsetup::
           >>> ds = gdal.Open('rgbsmall.tif')

        >>> print(ds.GetInterBandCovarianceMatrix(force=True))
        [[2241.7045363745387, 2898.8196128051163, 1009.979953581434], [2898.8196128051163, 3900.269159023618, 1248.65396718687], [1009.979953581434, 1248.65396718687, 602.4703641456648]] # rtol: 1e-6
        """

        if band_list is None:
            band_list = list(range(1, self.RasterCount + 1))
        if not band_list:
            return []
        return _gdal.Dataset_GetInterBandCovarianceMatrix(
                  self,
                  nBandCount=band_list,
                  approx_ok=approx_ok,
                  force=force,
                  write_into_metadata=write_into_metadata,
                  delta_degree_of_freedom=delta_degree_of_freedom,
                  callback=callback,
                  callback_data=callback_data)



    def ComputeInterBandCovarianceMatrix(self,
                                         band_list=None,
                                         approx_ok=False,
                                         write_into_metadata=True,
                                         delta_degree_of_freedom=1,
                                         callback=None,
                                         callback_data=None):
        """
        Compute the covariance matrix between bands of this dataset.

        The covariance indicates the level to which two bands vary together.

        If we call :math:`v_i[y,x]` the value of pixel at row=y and column=x for band i,
        and :math:`mean_i` the mean value of all pixels of band i, then

        .. math::

            \\mathrm{cov}\\left[i,j\\right] =
            \\frac{
                \\sum_{y,x} \\left( v_{i}[y,x] - \\mathrm{mean}_{i} \\right)
                \\left( v_{j}[y,x] - \\mathrm{mean}_{j} \\right)
            }{
                \\mathrm{pixel\\_count} - \\mathrm{delta\\_degree\\_of\\_freedom}
            }

        When there are no nodata values, :math:`pixel\\_count = self.RasterXSize * self.RasterYSize`.
        We can see that :math:`cov[i,j] = cov[j,i]`, and consequently the returned matrix
        is symmetric.

        A value of delta_degree_of_freedom=1 (the default) will return a unbiased estimate
        if the pixels in bands are considered to be a sample of the whole population.
        This is consistent with the default of
        https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
        matrix is consistent with what can be obtained with

        .. code-block:: python

           numpy.cov(
              [ds.GetRasterBand(band_nr).ReadAsArray().ravel() for band_nr in band_list]
           )

        Otherwise a value of delta_degree_of_freedom=0 can be used if they are considered
        to be the whole population.

        If STATISTICS_COVARIANCES metadata items are available in band metadata,
        this method uses them.
        Otherwise, if bForce is true, :py:meth:`ComputeInterBandCovarianceMatrix` is called.
        Otherwise, if bForce is false, an empty vector is returned

        Parameters
        ----------
        band_list: list[int], optional
            If not specified, compute the covariance matrix of all bands of the dataset.
            Otherwise compute it on the subset of bands specified by band_list.
            Values in band_list must be between 1 and self.RasterCount.
        approx_ok : bool, optional
            Whether it is acceptable to use a subsample of values
        write_into_metadata : bool, optional
            Whether this method must write STATISTICS_COVARIANCES band metadata items.
        delta_degree_of_freedom : int, optional
            Correction term to subtract in the final averaging phase of the covariance computation.
        callback : callable, optional
            A progress callback function
        callback_data : any, optional
            Optional data to be passed to callback function

        Returns
        -------
        List[List[float]]
            a list of len(band_list) of lists of len(band_list) values (where len(band_list) == self.RasterCount if band_list not set)

        Examples
        --------
        .. testsetup::
           >>> ds = gdal.Open('rgbsmall.tif')

        >>> print(ds.ComputeInterBandCovarianceMatrix())
        [[2241.7045363745387, 2898.8196128051163, 1009.979953581434], [2898.8196128051163, 3900.269159023618, 1248.65396718687], [1009.979953581434, 1248.65396718687, 602.4703641456648]] # rtol: 1e-6
        """

        if band_list is None:
            band_list = list(range(1, self.RasterCount + 1))
        if not band_list:
            return []
        return _gdal.Dataset_ComputeInterBandCovarianceMatrix(
                  self,
                  nBandCount=band_list,
                  approx_ok=approx_ok,
                  write_into_metadata=write_into_metadata,
                  delta_degree_of_freedom=delta_degree_of_freedom,
                  callback=callback,
                  callback_data=callback_data)



    def GetVirtualMem(self, *args, **kwargs):
        r"""GetVirtualMem(self, eRWFlag, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eBufType, band_list, bIsBandSequential, nCacheSize, nPageSizeHint, options=None) -> VirtualMem"""
        return _gdal.Dataset_GetVirtualMem(self, *args, **kwargs)

    def GetTiledVirtualMem(self, *args, **kwargs):
        r"""GetTiledVirtualMem(self, eRWFlag, nXOff, nYOff, nXSize, nYSize, nTileXSize, nTileYSize, eBufType, band_list, eTileOrganization, nCacheSize, options=None) -> VirtualMem"""
        return _gdal.Dataset_GetTiledVirtualMem(self, *args, **kwargs)

    def CreateLayer(self, *args, **kwargs):
        r"""
        CreateLayer(self, name, srs=None, geom_type=wkbUnknown, options=None) -> Layer


        Create a new layer in a vector Dataset.

        Parameters
        ----------
        name : str
               the name for the new layer.  This should ideally not
               match any existing layer on the datasource.
        srs : SpatialReference, optional
              The coordinate system to use for the new layer,
              or ``None`` if no coordinate system is available. Defaults to ``None``.
        geom_type : int, default = :py:const:`ogr.wkbUnknown`
              geometry type for the layer.  Use :py:const:`ogr.wkbUnknown` if there
              are no constraints on the types geometry to be written.
        options : dict or list, optional
              Driver-specific dict or list of name=value options

        Returns
        -------
        Layer or None
            The layer object if successful, or ``None`` on failure.


        Examples
        --------
        >>> ds = gdal.GetDriverByName('GPKG').Create('test.gpkg', 0, 0)
        >>> ds.GetLayerCount()
        0
        >>> lyr = ds.CreateLayer('poly', geom_type=ogr.wkbPolygon)
        >>> ds.GetLayerCount()
        1


        """
        val = _gdal.Dataset_CreateLayer(self, *args, **kwargs)

        self._add_child_ref(val)


        return val


    def CreateLayerFromGeomFieldDefn(self, *args):
        r"""CreateLayerFromGeomFieldDefn(self, name, geom_field, options=None) -> Layer"""
        return _gdal.Dataset_CreateLayerFromGeomFieldDefn(self, *args)

    def CopyLayer(self, *args, **kwargs):
        r"""
        CopyLayer(self, src_layer, new_name, options=None) -> Layer


        Duplicate an existing :py:class:`ogr.Layer`.

        See :cpp:func:`GDALDataset::CopyLayer`.

        Parameters
        ----------
        src_layer : Layer
                    source layer
        new_name : str
                   name of the layer to create
        options : dict or list
                  a dict or list of name=value driver-specific creation options

        Returns
        -------
        Layer or None
            A layer if successful, or ``None`` if an error occurs.

        """
        val = _gdal.Dataset_CopyLayer(self, *args, **kwargs)

        self._add_child_ref(val)


        return val


    def DeleteLayer(self, *args):
        r"""DeleteLayer(self, index) -> OGRErr"""
        return _gdal.Dataset_DeleteLayer(self, *args)

    def IsLayerPrivate(self, *args):
        r"""
        IsLayerPrivate(self, index) -> bool


        Parameters
        ----------
        index : int
                Index o layer to check

        Returns
        -------
        bool
             ``True`` if the layer is a private or system table, ``False`` otherwise



        """
        return _gdal.Dataset_IsLayerPrivate(self, *args)

    def GetNextFeature(self, *args, **kwargs):
        r"""
        GetNextFeature(self, include_layer=True, include_pct=False, callback=0, callback_data=None) -> Feature


        Fetch the next available feature from this dataset.

        This method is intended for the few drivers where
        :py:meth:`OGRLayer.GetNextFeature` is not efficient, but in general
        :py:meth:`OGRLayer.GetNextFeature` is a more natural API.

        See :cpp:func:`GDALDataset::GetNextFeature`.

        Returns
        -------
        Feature


        """
        return _gdal.Dataset_GetNextFeature(self, *args, **kwargs)

    def TestCapability(self, *args):
        r"""
        TestCapability(self, cap) -> bool


        Test if a capability is available.

        Parameters
        ----------
        cap : str
           Name of the capability (e.g., :py:const:`ogr.ODsCTransactions`)

        Returns
        -------
        bool
            ``True`` if the capability is available, ``False`` if invalid or unavailable

        Examples
        --------
        >>> ds = gdal.GetDriverByName('ESRI Shapefile').Create('test.shp', 0, 0, 0, gdal.GDT_Unknown)
        >>> ds.TestCapability(ogr.ODsCTransactions)
        False
        >>> ds.TestCapability(ogr.ODsCMeasuredGeometries)
        True
        >>> ds.TestCapability(gdal.GDsCAddRelationship)
        False


        """
        return _gdal.Dataset_TestCapability(self, *args)

    def ExecuteSQL(self, statement, spatialFilter=None, dialect="", keep_ref_on_ds=False):
        """ExecuteSQL(self, statement, spatialFilter: ogr.Geometry = None, dialect: Optional[str] = "", keep_ref_on_ds=False) -> ogr.Layer

        Execute a SQL statement against the dataset

        The result of a SQL query is:
          - None (or an exception if exceptions are enabled) for statements
            that are in error
          - or None for statements that have no results set,
          - or a :py:class:`ogr.Layer` handle representing a results set from the query.

        Note that this :py:class:`ogr.Layer` is in addition to the layers in the data store
        and must be released with :py:meth:`ReleaseResultSet` before the data source is closed
        (destroyed).

        Starting with GDAL 3.7, this method can also be used as a context manager,
        as a convenient way of automatically releasing the returned result layer.

        For more information on the SQL dialect supported internally by OGR
        review the OGR SQL document (:ref:`ogr_sql_sqlite_dialect`)
        Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through to the
        underlying RDBMS.

        The SQLITE dialect can also be used (:ref:`sql_sqlite_dialect`)

        Parameters
        ----------
        statement : str
            the SQL statement to execute (e.g "SELECT * FROM layer")
        spatialFilter : any
            a geometry which represents a spatial filter. Can be None
        dialect : str
            allows control of the statement dialect. If set to None or empty string,
            the OGR SQL engine will be used, except for RDBMS drivers that will
            use their dedicated SQL engine, unless OGRSQL is explicitly passed as
            the dialect. The SQLITE dialect can also be used.
        keep_ref_on_ds : bool
            whether the returned layer should keep a (strong) reference on
            the current dataset. Cf example 2 for a use case.

        Returns
        -------
        Layer
            a layer containing the results of the query, that will be
            automatically released when the context manager goes out of scope.

        Examples
        --------

        .. testsetup::

           >>> src_ds = gdal.OpenEx("poly.shp", gdal.OF_VECTOR)
           >>> ds = gdal.GetDriverByName("MEM").CreateVector("")
           >>> _ = ds.CopyLayer(src_ds.GetLayer(0), "layer")

        1. Use as a context manager:

        >>> with ds.ExecuteSQL("SELECT * FROM layer") as lyr:
        ...     print(lyr.GetFeatureCount())
        10

        2. Use keep_ref_on_ds=True to return an object that keeps a reference to its dataset:

        >>> def get_sql_lyr():
        ...     return gdal.OpenEx("poly.shp", gdal.OF_VECTOR).ExecuteSQL("SELECT * FROM poly", keep_ref_on_ds=True)
        ...
        >>> with get_sql_lyr() as lyr:
        ...     print(lyr.GetFeatureCount())
        10
        """

        class MyHandler:
            def __init__(self):
                self.errors = []

            def callback(self, err_type, err_no, err_msg):
                self.errors.append([err_type, err_no, err_msg])

        my_error_handler = MyHandler()
        if GetUseExceptions():
            with ExceptionMgr(useExceptions=False):
                PushErrorHandler(my_error_handler.callback)
                try:
                    sql_lyr = _gdal.Dataset_ExecuteSQL(self, statement, spatialFilter, dialect)
                finally:
                    PopErrorHandler()
        else:
            sql_lyr = _gdal.Dataset_ExecuteSQL(self, statement, spatialFilter, dialect)
        if sql_lyr:
            import weakref
            sql_lyr._to_release = True
            sql_lyr._dataset_weak_ref = weakref.ref(self)
            if keep_ref_on_ds:
                sql_lyr._dataset_strong_ref = self

        if my_error_handler.errors and my_error_handler.errors[-1][0] == CE_Failure:
            if sql_lyr:
                self.ReleaseResultSet(sql_lyr)
            raise RuntimeError(my_error_handler.errors[-1][2])

        elif my_error_handler.errors:
            for err_type, err_no, err_msg in my_error_handler.errors:
                if err_type == CE_Warning:
                    Error(err_type, err_no, err_msg)

        return sql_lyr



    def ReleaseResultSet(self, sql_lyr):
        """ReleaseResultSet(self, sql_lyr: ogr.Layer)

        Release :py:class:`ogr.Layer` returned by :py:meth:`ExecuteSQL` (when not called as a context manager)

        The sql_lyr object is invalidated after this call.

        Parameters
        ----------
        sql_lyr : Layer
            :py:class:`ogr.Layer` got with :py:meth:`ExecuteSQL`
        """

        if sql_lyr and not hasattr(sql_lyr, "_to_release"):
            raise Exception("This layer was not returned by ExecuteSQL() and should not be released with ReleaseResultSet()")
        _gdal.Dataset_ReleaseResultSet(self, sql_lyr)
    # Invalidates the layer
        if sql_lyr:
            sql_lyr.thisown = None
            sql_lyr.this = None



    def GetStyleTable(self, *args):
        r"""
        GetStyleTable(self) -> StyleTable


        Returns dataset style table.

        Returns
        -------
        StyleTable


        """
        return _gdal.Dataset_GetStyleTable(self, *args)

    def SetStyleTable(self, *args):
        r"""
        SetStyleTable(self, table)


        Set dataset style table

        Parameters
        ----------
        table : StyleTable

        """
        return _gdal.Dataset_SetStyleTable(self, *args)

    def GetLayerByIndex(self, *args):
        r"""
        GetLayerByIndex(self, index=0) -> Layer


        Fetch a layer by index.

        Parameters
        ----------
        index : int
            A layer number between 0 and ``GetLayerCount() - 1``

        Returns
        -------
        Layer or None
            An layer if successful, or ``None`` on error.

        """
        val = _gdal.Dataset_GetLayerByIndex(self, *args)

        self._add_child_ref(val)


        return val


    def GetLayerByName(self, *args):
        r"""GetLayerByName(self, layer_name) -> Layer"""

        _WarnIfUserHasNotSpecifiedIfUsingOgrExceptions()


        val = _gdal.Dataset_GetLayerByName(self, *args)

        self._add_child_ref(val)


        return val


    def ResetReading(self, *args):
        r"""
        ResetReading(self)


        Reset feature reading to start on the first feature.

        This affects :py:meth:`GetNextFeature`.

        Depending on drivers, this may also have the side effect of calling
        :py:meth:`OGRLayer.ResetReading` on the layers of this dataset.


        """
        return _gdal.Dataset_ResetReading(self, *args)

    def GetLayerCount(self, *args):
        r"""
        GetLayerCount(self) -> int


        Get the number of layers in this dataset.

        Returns
        -------
        int


        """
        return _gdal.Dataset_GetLayerCount(self, *args)

    def AbortSQL(self, *args):
        r"""
        AbortSQL(self) -> OGRErr


        Abort any SQL statement running in the data store.

        Not implemented by all drivers. See :cpp:func:`GDALDataset::AbortSQL`.

        Returns
        -------
        int
            :py:const:`ogr.OGRERR_NONE` on success, or
            :py:const:`ogr.OGRERR_UNSUPPORTED_OPERATION` if AbortSQL is not supported
            for this dataset.

        """
        return _gdal.Dataset_AbortSQL(self, *args)

    def StartTransaction(self, *args, **kwargs):
        r"""
        StartTransaction(self, force=FALSE) -> OGRErr


        Creates a transaction. See :cpp:func:`GDALDataset::StartTransaction`.

        Returns
        -------
        int
            If starting the transaction fails, will return
            :py:const:`ogr.OGRERR_FAILURE`. Datasources which do not support transactions will
            always return :py:const:`OGRERR_UNSUPPORTED_OPERATION`.


        """
        return _gdal.Dataset_StartTransaction(self, *args, **kwargs)

    def CommitTransaction(self, *args):
        r"""
        CommitTransaction(self) -> OGRErr

        Commits a transaction, for `Datasets` that support transactions.

        See :cpp:func:`GDALDataset::CommitTransaction`.

        """
        return _gdal.Dataset_CommitTransaction(self, *args)

    def RollbackTransaction(self, *args):
        r"""
        RollbackTransaction(self) -> OGRErr


        Roll back a Dataset to its state before the start of the current transaction.

        For datasets that support transactions.

        Returns
        -------
        int
            If no transaction is active, or the rollback fails, will return
            :py:const:`OGRERR_FAILURE`. Datasources which do not support transactions will
            always return :py:const:`OGRERR_UNSUPPORTED_OPERATION`.


        """
        return _gdal.Dataset_RollbackTransaction(self, *args)

    def ClearStatistics(self, *args):
        r"""
        ClearStatistics(self)


        Clear statistics

        See :cpp:func:`GDALDataset::ClearStatistics`.


        """
        return _gdal.Dataset_ClearStatistics(self, *args)

    def GetFieldDomainNames(self, *args):
        r"""
        GetFieldDomainNames(self, options=None) -> char **


        Get a list of the names of all field domains stored in the dataset.

        Parameters
        ----------
        options : dict or list, optional
                 Driver-specific options determining how attributes should
                 be retrieved.

        Returns
        -------
        list or None
            ``None`` if no field domains are stored in the dataset.

        """
        return _gdal.Dataset_GetFieldDomainNames(self, *args)

    def GetFieldDomain(self, *args):
        r"""
        GetFieldDomain(self, name) -> FieldDomain


        Get a field domain from its name.

        Parameters
        ----------
        name : str
              The name of the field domain

        Returns
        -------
        FieldDomain or None
            An FieldDomain instance if found, or ``None`` if it is not found.

        """
        return _gdal.Dataset_GetFieldDomain(self, *args)

    def AddFieldDomain(self, *args):
        r"""
        AddFieldDomain(self, fieldDomain) -> bool


        Add a :py:class:`ogr.FieldDomain` to the dataset.

        Only a few drivers support this operation. See :cpp:func:`GDALDataset::AddFieldDomain`.

        Parameters
        ----------
        fieldDomain : FieldDomain
            The field domain to add

        Returns
        -------
        bool
            ``True`` if the field domain was added, ``False`` in case of error.



        """
        return _gdal.Dataset_AddFieldDomain(self, *args)

    def DeleteFieldDomain(self, *args):
        r"""
        DeleteFieldDomain(self, name) -> bool


        Removes a field domain from the Dataset.

        Parameters
        ----------
        name : str
               Name of the field domain to delete

        Returns
        -------
        bool
             ``True`` if the field domain was removed, otherwise ``False``.


        """
        return _gdal.Dataset_DeleteFieldDomain(self, *args)

    def UpdateFieldDomain(self, *args):
        r"""
        UpdateFieldDomain(self, fieldDomain) -> bool


        Update an existing field domain by replacing its definition.

        The existing field domain with matching name will be replaced.

        Requires the :py:const:`ogr.ODsCUpdateFieldDomain` dataset capability.

        Parameters
        ----------
        fieldDomain : FieldDomain
            Updated field domain.

        Returns
        -------
        bool
            ``True`` in case of success


        """
        return _gdal.Dataset_UpdateFieldDomain(self, *args)

    def GetRelationshipNames(self, *args):
        r"""
        GetRelationshipNames(self, options=None) -> char **


        Get a list of the names of all relationships stored in the dataset.

        Parameters
        ----------
        options : dict or list, optional
            driver-specific options determining how the relationships should be retrieved


        """
        return _gdal.Dataset_GetRelationshipNames(self, *args)

    def GetRelationship(self, *args):
        r"""
        GetRelationship(self, name) -> Relationship


        Get a relationship from its name.

        Returns
        -------
        Relationship, or ``None`` if not found.

        """
        return _gdal.Dataset_GetRelationship(self, *args)

    def AddRelationship(self, *args):
        r"""
        AddRelationship(self, relationship) -> bool


        Add a :py:class:`Relationship` to the dataset.

        See :cpp:func:`GDALDataset::AddRelationship`.

        Parameters
        ----------
        relationship : Relationship
                       The relationship to add

        Returns
        -------
        bool
            ``True`` if the field domain was added, ``False`` in case of error.


        """
        return _gdal.Dataset_AddRelationship(self, *args)

    def DeleteRelationship(self, *args):
        r"""
        DeleteRelationship(self, name) -> bool


        Removes a relationship from the Dataset.

        Parameters
        ----------
        name : str
               Name of the relationship to remove.

        Returns
        -------
        bool
             ``True`` if the relationship  was removed, otherwise ``False``.



        """
        return _gdal.Dataset_DeleteRelationship(self, *args)

    def UpdateRelationship(self, *args):
        r"""
        UpdateRelationship(self, relationship) -> bool


        Update an existing relationship by replacing its definition.

        The existing relationship with matching name will be replaced.

        Requires the :py:const:`gdal.GDsCUpdateFieldDomain` dataset capability.

        Parameters
        ----------
        relationship : Relationship
            Updated relationship

        Returns
        -------
        bool
            ``True`` in case of success


        """
        return _gdal.Dataset_UpdateRelationship(self, *args)

    def AsMDArray(self, *args):
        r"""AsMDArray(self, options=None) -> MDArray"""
        return _gdal.Dataset_AsMDArray(self, *args)

    def ReadRaster1(self, *args, **kwargs):
        r"""ReadRaster1(self, xoff, yoff, xsize, ysize, buf_xsize=None, buf_ysize=None, buf_type=None, band_list=0, buf_pixel_space=None, buf_line_space=None, buf_band_space=None, resample_alg=GRIORA_NearestNeighbour, operate_in_buf_type=TRUE, callback=0, callback_data=None, inputOutputBuf=None) -> CPLErr"""
        return _gdal.Dataset_ReadRaster1(self, *args, **kwargs)


    def ReadAsMaskedArray(self, xoff=0, yoff=0, xsize=None, ysize=None,
                    buf_xsize=None, buf_ysize=None, buf_type=None,
                    resample_alg=gdalconst.GRIORA_NearestNeighbour,
                    mask_resample_alg=gdalconst.GRIORA_NearestNeighbour,
                    callback=None,
                    callback_data=None,
                    band_list=None):
        """
        Read a window from raster bands into a NumPy masked array.

        Values of the mask will be ``True`` where pixels are invalid.

        If resampling (``buf_xsize`` != ``xsize``, or ``buf_ysize`` != ``ysize``) the mask band will be resampled
        using the algorithm specified by ``mask_resample_alg``.

        See :py:meth:`ReadAsArray` for a description of additional arguments.
        """

        import numpy as np

        arr = self.ReadAsArray(xoff=xoff, yoff=yoff, xsize=xsize, ysize=ysize,
                               buf_xsize=buf_xsize, buf_ysize=buf_ysize, buf_type=buf_type,
                               resample_alg=resample_alg, band_list=band_list)

        if band_list is None:
            band_list = [i+1 for i in range(self.RasterCount)]

        all_valid = all(self.GetRasterBand(band).GetMaskFlags() == GMF_ALL_VALID for band in band_list)

        if all_valid:
            return np.ma.masked_array(arr, False)

        masks = [self.GetRasterBand(band).GetMaskBand().ReadAsArray(
                xoff=xoff, yoff=yoff,
                win_xsize=xsize, win_ysize=ysize,
                buf_xsize=buf_xsize, buf_ysize=buf_ysize,
                resample_alg=mask_resample_alg) != 255
                 for band in band_list]

        return np.ma.masked_array(arr, np.vstack(masks))


    def ReadAsArray(self, xoff=0, yoff=0, xsize=None, ysize=None, buf_obj=None,
                    buf_xsize=None, buf_ysize=None, buf_type=None,
                    resample_alg=gdalconst.GRIORA_NearestNeighbour,
                    operate_in_buf_type=True,
                    callback=None,
                    callback_data=None,
                    interleave='band',
                    band_list=None):
        """
        Read a window from raster bands into a NumPy array.

        Parameters
        ----------
        xoff : float, default=0
           The pixel offset to left side of the region of the band to
           be read. This would be zero to start from the left side.
        yoff : float, default=0
           The line offset to top side of the region of the band to
           be read. This would be zero to start from the top side.
        xsize : float, optional
             The number of pixels to read in the x direction. By default,
             equal to the number of columns in the raster.
        ysize : float, optional
             The number of rows to read in the y direction. By default,
             equal to the number of bands in the raster.
        buf_xsize : int, optional
             The number of columns in the returned array. If not equal
             to ``win_xsize``, the returned values will be determined
             by ``resample_alg``.
        buf_ysize : int, optional
             The number of rows in the returned array. If not equal
             to ``win_ysize``, the returned values will be determined
             by ``resample_alg``.
        buf_type : int, optional
             The data type of the returned array
        buf_obj : np.ndarray, optional
             Optional buffer into which values will be read. If ``buf_obj``
             is specified, then ``buf_xsize``/``buf_ysize``/``buf_type``
             should generally not be specified.
        resample_alg : int, default = :py:const:`gdal.GRIORA_NearestNeighbour`.
             Specifies the resampling algorithm to use when the size of
             the read window and the buffer are not equal.
        operate_in_buf_type : bool, default = True
             Whether the data type used for the operations (typically non-nearest-neighbour
             resampling) should be buf_type (operate_in_buf_type=True) or the
             data type of the band (operate_in_buf_type=False)
        callback : callable, optional
            A progress callback function
        callback_data : any, optional
            Optional data to be passed to callback function
        band_list : list, optional
            Indexes of bands from which data should be read. By default,
            data will be read from all bands.

        Returns
        -------
        np.ndarray

        Examples
        --------
        >>> ds = gdal.GetDriverByName("GTiff").Create("test.tif", 4, 4, bands=2)
        >>> ds.WriteArray(np.arange(32).reshape(2, 4, 4))
        0
        >>> ds.ReadAsArray()
        array([[[ 0,  1,  2,  3],
                [ 4,  5,  6,  7],
                [ 8,  9, 10, 11],
                [12, 13, 14, 15]],
               [[16, 17, 18, 19],
                [20, 21, 22, 23],
                [24, 25, 26, 27],
                [28, 29, 30, 31]]], dtype=uint8)
        >>> ds.ReadAsArray(xoff=2, yoff=2, xsize=2, ysize=2)
        array([[[10, 11],
                [14, 15]],
               [[26, 27],
                [30, 31]]], dtype=uint8)
        >>> ds.ReadAsArray(buf_xsize=2, buf_ysize=2, buf_type=gdal.GDT_Float64, resample_alg=gdal.GRIORA_Average)
        array([[[ 3.,  5.],
                [11., 13.]],
               [[19., 21.],
                [27., 29.]]])
        >>> buf = np.zeros((2,2,2))
        >>> ds.ReadAsArray(buf_obj=buf)
        array([[[ 5.,  7.],
                [13., 15.]],
               [[21., 23.],
                [29., 31.]]])
        >>> ds.ReadAsArray(band_list=[2,1])
        array([[[16, 17, 18, 19],
                [20, 21, 22, 23],
                [24, 25, 26, 27],
                [28, 29, 30, 31]],
               [[ 0,  1,  2,  3],
                [ 4,  5,  6,  7],
                [ 8,  9, 10, 11],
                [12, 13, 14, 15]]], dtype=uint8)
        """

        from osgeo import gdal_array
        return gdal_array.DatasetReadAsArray(self, xoff, yoff, xsize, ysize, buf_obj,
                                              buf_xsize, buf_ysize, buf_type,
                                              resample_alg=resample_alg,
                                              operate_in_buf_type=operate_in_buf_type,
                                              callback=callback,
                                              callback_data=callback_data,
                                              interleave=interleave,
                                              band_list=band_list)

    def WriteArray(self, array, xoff=0, yoff=0,
                   band_list=None,
                   interleave='band',
                   resample_alg=gdalconst.GRIORA_NearestNeighbour,
                   callback=None,
                   callback_data=None):
        """
        Write the contents of a NumPy array to a Dataset.

        Parameters
        ----------
        array : np.ndarray
            Two- or three-dimensional array containing values to write
        xoff : int, default=0
           The pixel offset to left side of the region of the band to
           be written. This would be zero to start from the left side.
        yoff : int, default=0
           The line offset to top side of the region of the band to
           be written. This would be zero to start from the top side.
        band_list : list, optional
            Indexes of bands to which data should be written. By default,
            it is assumed that the Dataset contains the same number of
            bands as levels in ``array``.
        interleave : str, default="band"
            Interleaving, "band" or "pixel". For band-interleaved writing,
            ``array`` should have shape ``(nband, ny, nx)``. For pixel-
            interleaved-writing, ``array`` should have shape
            ``(ny, nx, nbands)``.
        resample_alg : int, default = :py:const:`gdal.GRIORA_NearestNeighbour`
            Resampling algorithm. Placeholder argument, not currently supported.
        callback : callable, optional
            A progress callback function
        callback_data : any, optional
            Optional data to be passed to callback function

        Returns
        -------
        int
            Error code, or ``gdal.CE_None`` if no error occurred.

        Examples
        --------

        >>> import numpy as np
        >>>
        >>> nx = 4
        >>> ny = 3
        >>> nbands = 2
        >>> with gdal.GetDriverByName("GTiff").Create("band3_px.tif", nx, ny, bands=nbands) as ds:
        ...     data = np.arange(nx*ny*nbands).reshape(ny,nx,nbands)
        ...     ds.WriteArray(data, interleave="pixel")
        ...     ds.ReadAsArray()
        ...
        0
        array([[[ 0,  2,  4,  6],
                [ 8, 10, 12, 14],
                [16, 18, 20, 22]],
               [[ 1,  3,  5,  7],
                [ 9, 11, 13, 15],
                [17, 19, 21, 23]]], dtype=uint8)
        >>> with gdal.GetDriverByName("GTiff").Create("band3_band.tif", nx, ny, bands=nbands) as ds:
        ...     data = np.arange(nx*ny*nbands).reshape(nbands, ny, nx)
        ...     ds.WriteArray(data, interleave="band")
        ...     ds.ReadAsArray()
        ...
        0
        array([[[ 0,  1,  2,  3],
                [ 4,  5,  6,  7],
                [ 8,  9, 10, 11]],
               [[12, 13, 14, 15],
                [16, 17, 18, 19],
                [20, 21, 22, 23]]], dtype=uint8)
        """

        from osgeo import gdal_array

        return gdal_array.DatasetWriteArray(self, array, xoff, yoff,
                                            band_list=band_list,
                                            interleave=interleave,
                                            resample_alg=resample_alg,
                                            callback=callback,
                                            callback_data=callback_data)

    def WriteRaster(self, xoff, yoff, xsize, ysize,
                    buf_string,
                    buf_xsize=None, buf_ysize=None, buf_type=None,
                    band_list=None,
                    buf_pixel_space=None, buf_line_space=None, buf_band_space=None ):

        if buf_xsize is None:
            buf_xsize = xsize
        if buf_ysize is None:
            buf_ysize = ysize
        if band_list is None:
            band_list = list(range(1, self.RasterCount + 1))

    # Redirect to numpy-friendly WriteArray() if buf_string is a numpy array
    # and other arguments are compatible
        if type(buf_string).__name__ == 'ndarray' and \
           buf_xsize == xsize and buf_ysize == ysize and buf_type is None and \
           buf_pixel_space is None and buf_line_space is None and buf_band_space is None:
            return self.WriteArray(buf_string, xoff=xoff, yoff=yoff,
                                   band_list=band_list)
        if buf_type is None:
            buf_type = self.GetRasterBand(1).DataType

        return _gdal.Dataset_WriteRaster(self,
                 xoff, yoff, xsize, ysize,
                buf_string, buf_xsize, buf_ysize, buf_type, band_list,
                buf_pixel_space, buf_line_space, buf_band_space )

    def ReadRaster(self, xoff=0, yoff=0, xsize=None, ysize=None,
                   buf_xsize=None, buf_ysize=None, buf_type=None,
                   band_list=None,
                   buf_pixel_space=None, buf_line_space=None, buf_band_space=None,
                   resample_alg=gdalconst.GRIORA_NearestNeighbour,
                   operate_in_buf_type=True,
                   callback=None,
                   callback_data=None,
                   buf_obj=None):

        if xsize is None:
            xsize = self.RasterXSize
        if ysize is None:
            ysize = self.RasterYSize
        if band_list is None:
            band_list = list(range(1, self.RasterCount + 1))
        if buf_xsize is None:
            buf_xsize = xsize
        if buf_ysize is None:
            buf_ysize = ysize

        if buf_type is None:
            buf_type = self.GetRasterBand(1).DataType;

        return _gdal.Dataset_ReadRaster1(self, xoff, yoff, xsize, ysize,
                                            buf_xsize, buf_ysize, buf_type,
                                            band_list, buf_pixel_space, buf_line_space, buf_band_space,
                                          resample_alg, operate_in_buf_type, callback, callback_data, buf_obj )

    def GetVirtualMemArray(self, eAccess=gdalconst.GF_Read, xoff=0, yoff=0,
                           xsize=None, ysize=None, bufxsize=None, bufysize=None,
                           datatype=None, band_list=None, band_sequential = True,
                           cache_size = 10 * 1024 * 1024, page_size_hint = 0,
                           options=None):
        """Return a NumPy array for the dataset, seen as a virtual memory mapping.
           If there are several bands and band_sequential = True, an element is
           accessed with array[band][y][x].
           If there are several bands and band_sequential = False, an element is
           accessed with array[y][x][band].
           If there is only one band, an element is accessed with array[y][x].
           Any reference to the array must be dropped before the last reference to the
           related dataset is also dropped.
        """
        from osgeo import gdal_array
        if xsize is None:
            xsize = self.RasterXSize
        if ysize is None:
            ysize = self.RasterYSize
        if bufxsize is None:
            bufxsize = self.RasterXSize
        if bufysize is None:
            bufysize = self.RasterYSize
        if datatype is None:
            datatype = self.GetRasterBand(1).DataType
        if band_list is None:
            band_list = list(range(1, self.RasterCount + 1))
        if options is None:
            virtualmem = self.GetVirtualMem(eAccess, xoff, yoff, xsize, ysize, bufxsize, bufysize, datatype, band_list, band_sequential, cache_size, page_size_hint)
        else:
            virtualmem = self.GetVirtualMem(eAccess, xoff, yoff, xsize, ysize, bufxsize, bufysize, datatype, band_list, band_sequential, cache_size, page_size_hint,  options)
        return gdal_array.VirtualMemGetArray( virtualmem )

    def GetTiledVirtualMemArray(self, eAccess=gdalconst.GF_Read, xoff=0, yoff=0,
                           xsize=None, ysize=None, tilexsize=256, tileysize=256,
                           datatype=None, band_list=None, tile_organization=gdalconst.GTO_BSQ,
                           cache_size = 10 * 1024 * 1024, options=None):
        """Return a NumPy array for the dataset, seen as a virtual memory mapping with
           a tile organization.
           If there are several bands and tile_organization = gdal.GTO_TIP, an element is
           accessed with array[tiley][tilex][y][x][band].
           If there are several bands and tile_organization = gdal.GTO_BIT, an element is
           accessed with array[tiley][tilex][band][y][x].
           If there are several bands and tile_organization = gdal.GTO_BSQ, an element is
           accessed with array[band][tiley][tilex][y][x].
           If there is only one band, an element is accessed with array[tiley][tilex][y][x].
           Any reference to the array must be dropped before the last reference to the
           related dataset is also dropped.
        """
        from osgeo import gdal_array
        if xsize is None:
            xsize = self.RasterXSize
        if ysize is None:
            ysize = self.RasterYSize
        if datatype is None:
            datatype = self.GetRasterBand(1).DataType
        if band_list is None:
            band_list = list(range(1, self.RasterCount + 1))
        if options is None:
            virtualmem = self.GetTiledVirtualMem(eAccess, xoff, yoff, xsize, ysize, tilexsize, tileysize, datatype, band_list, tile_organization, cache_size)
        else:
            virtualmem = self.GetTiledVirtualMem(eAccess, xoff, yoff, xsize, ysize, tilexsize, tileysize, datatype, band_list, tile_organization, cache_size, options)
        return gdal_array.VirtualMemGetArray( virtualmem )

    def GetSubDatasets(self):
        """
        Return a list of Subdatasets.


        Returns
        -------
        list

        """
        sd_list = []

        sd = self.GetMetadata('SUBDATASETS')
        if sd is None:
            return sd_list

        i = 1
        while 'SUBDATASET_'+str(i)+'_NAME' in sd:
            sd_list.append((sd['SUBDATASET_'+str(i)+'_NAME'],
                            sd['SUBDATASET_'+str(i)+'_DESC']))
            i = i + 1
        return sd_list

    def BeginAsyncReader(self, xoff, yoff, xsize, ysize, buf_obj=None, buf_xsize=None, buf_ysize=None, buf_type=None, band_list=None, options=None):
        if band_list is None:
            band_list = list(range(1, self.RasterCount + 1))
        if buf_xsize is None:
            buf_xsize = 0;
        if buf_ysize is None:
            buf_ysize = 0;
        if buf_type is None:
            buf_type = gdalconst.GDT_Byte

        if buf_xsize <= 0:
            buf_xsize = xsize
        if buf_ysize <= 0:
            buf_ysize = ysize
        options = [] if options is None else options

        if buf_obj is None:
            from sys import version_info
            nRequiredSize = int(buf_xsize * buf_ysize * len(band_list) * _gdal.GetDataTypeSizeBytes(buf_type))
            if version_info >= (3, 0, 0):
                buf_obj_ar = [None]
                exec("buf_obj_ar[0] = b' ' * nRequiredSize")
                buf_obj = buf_obj_ar[0]
            else:
                buf_obj = ' ' * nRequiredSize
        return _gdal.Dataset_BeginAsyncReader(self, xoff, yoff, xsize, ysize, buf_obj, buf_xsize, buf_ysize, buf_type, band_list,  0, 0, 0, options)

    def GetLayer(self, iLayer=0):
        """
        Get the indicated layer from the Dataset

        Parameters
        ----------
        value : int or str
                Name or 0-based index of the layer to delete.

        Returns
        -------
        Layer
            A layer if successful, or ``None`` on error.
        """

        _WarnIfUserHasNotSpecifiedIfUsingOgrExceptions()

        if isinstance(iLayer, str):
            return self.GetLayerByName(str(iLayer))
        elif isinstance(iLayer, int):
            return self.GetLayerByIndex(iLayer)
        else:
            raise TypeError("Input %s is not of String or Int type" % type(iLayer))

    def DeleteLayer(self, value):
        """
        Delete the indicated layer from the Dataset.

        Parameters
        ----------
        value : int or str
                Name or 0-based index of the layer to delete.

        Returns
        -------
        int
            :py:const:`ogr.OGRERR_NONE` on success or
            :py:const:`ogr.OGRERR_UNSUPPORTED_OPERATION` if DeleteLayer is not supported
            for this dataset.
        """
        if isinstance(value, str):
            for i in range(self.GetLayerCount()):
                name = self.GetLayer(i).GetName()
                if name == value:
                    return _gdal.Dataset_DeleteLayer(self, i)
            raise ValueError("Layer %s not found to delete" % value)
        elif isinstance(value, int):
            return _gdal.Dataset_DeleteLayer(self, value)
        else:
            raise TypeError("Input %s is not of String or Int type" % type(value))

    def SetGCPs(self, gcps, wkt_or_spatial_ref):
        """
        Assign GCPs.

        See :cpp:func:`GDALSetGCPs`.

        Parameters
        ----------
        gcps : list
               a list of :py:class:`GCP` objects
        wkt_or_spatial_ref : str or SpatialReference
               spatial reference of the GCPs as a string, or a :py:class:`osr.SpatialReference`
        """

        if isinstance(wkt_or_spatial_ref, str):
            return self._SetGCPs(gcps, wkt_or_spatial_ref)
        else:
            return self._SetGCPs2(gcps, wkt_or_spatial_ref)

    def Destroy(self):
        import warnings
        warnings.warn("Destroy() is deprecated; use a context manager or Close() instead", DeprecationWarning)
        self._invalidate_children()
        try:
            return _gdal.Dataset_Close(self)
        finally:
            self.thisown = 0
            self.this = None

    def Release(self):
        import warnings
        warnings.warn("Release() is deprecated; use a context manager or Close() instead", DeprecationWarning)
        self._invalidate_children()
        try:
            return _gdal.Dataset_Close(self)
        finally:
            self.thisown = 0
            self.this = None

    def SyncToDisk(self):
        return self.FlushCache()

    def GetName(self):
        return self.GetDescription()

    def _add_child_ref(self, child):
        if child is None:
            return

        import weakref

        if not hasattr(self, '_child_references'):
            self._child_references = weakref.WeakSet()

        self._child_references.add(child)
        child._parent_ds = weakref.ref(self)

    def _invalidate_children(self):
        if hasattr(self, '_child_references'):
            for child in self._child_references:
                child.this = None

    def __del__(self):
        self._invalidate_children()

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.Close()

    def __bool__(self):
        return True

    def __len__(self):
        return self.RasterCount + self.GetLayerCount()

    def __iter__(self):
        if self.RasterCount:
            for band in range(1, self.RasterCount + 1):
                yield self[band]
        else:
            for layer in range(self.GetLayerCount()):
                yield self[layer]

    def __getitem__(self, value):
        """Support dictionary, list, and slice -like access to the datasource.
        ds[0] would return the first layer on the datasource.
        ds['aname'] would return the layer named "aname".
        ds[0:4] would return a list of the first four layers."""

        if self.RasterCount and self.GetLayerCount():
            raise ValueError("Cannot access slice of Dataset with both raster bands and vector layers")

        if self.GetLayerCount():
            get = self.GetLayer
            min = 0
            max = self.GetLayerCount() - 1
        else:
            get = self.GetRasterBand
            min = 1
            max = self.RasterCount

        if isinstance(value, slice):
            output = []
            step = value.step if value.step else 1
            for i in range(value.start, value.stop, step):
                lyr = self.GetLayer(i)
                if lyr is None:
                    return output
                output.append(lyr)
            return output

        if value < min or value > max:
    # Exception needed to make for _ in loop finish
            raise IndexError(value)

        return get(value)


# Register Dataset in _gdal:
_gdal.Dataset_swigregister(Dataset)
class RATDateTime(object):
    r"""Proxy of C++ GDALRATDateTime class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    nYear = property(_gdal.RATDateTime_nYear_get, _gdal.RATDateTime_nYear_set, doc=r"""nYear""")
    nMonth = property(_gdal.RATDateTime_nMonth_get, _gdal.RATDateTime_nMonth_set, doc=r"""nMonth""")
    nDay = property(_gdal.RATDateTime_nDay_get, _gdal.RATDateTime_nDay_set, doc=r"""nDay""")
    nHour = property(_gdal.RATDateTime_nHour_get, _gdal.RATDateTime_nHour_set, doc=r"""nHour""")
    nMinute = property(_gdal.RATDateTime_nMinute_get, _gdal.RATDateTime_nMinute_set, doc=r"""nMinute""")
    fSecond = property(_gdal.RATDateTime_fSecond_get, _gdal.RATDateTime_fSecond_set, doc=r"""fSecond""")
    nTimeZoneHour = property(_gdal.RATDateTime_nTimeZoneHour_get, _gdal.RATDateTime_nTimeZoneHour_set, doc=r"""nTimeZoneHour""")
    nTimeZoneMinute = property(_gdal.RATDateTime_nTimeZoneMinute_get, _gdal.RATDateTime_nTimeZoneMinute_set, doc=r"""nTimeZoneMinute""")
    bPositiveTimeZone = property(_gdal.RATDateTime_bPositiveTimeZone_get, _gdal.RATDateTime_bPositiveTimeZone_set, doc=r"""bPositiveTimeZone""")
    bIsValid = property(_gdal.RATDateTime_bIsValid_get, _gdal.RATDateTime_bIsValid_set, doc=r"""bIsValid""")

    def __init__(self, *args):
        r"""__init__(self) -> RATDateTime"""
        _gdal.RATDateTime_swiginit(self, _gdal.new_RATDateTime(*args))
    __swig_destroy__ = _gdal.delete_RATDateTime

# Register RATDateTime in _gdal:
_gdal.RATDateTime_swigregister(RATDateTime)
class RasterAttributeTable(object):
    r"""Proxy of C++ GDALRasterAttributeTableShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self) -> RasterAttributeTable"""
        _gdal.RasterAttributeTable_swiginit(self, _gdal.new_RasterAttributeTable(*args))
    __swig_destroy__ = _gdal.delete_RasterAttributeTable

    def Clone(self, *args):
        r"""
        Clone(self) -> RasterAttributeTable


        Create a copy of the RAT.

        Returns
        -------
        RasterAttributeTable
            A Python proxy of a :cpp:class:`GDALRasterAttributeTable`


        """
        return _gdal.RasterAttributeTable_Clone(self, *args)

    def GetColumnCount(self, *args):
        r"""
        GetColumnCount(self) -> int


        Return the number of columns in the RAT. 

        See :cpp:func:`GDALRasterAttributeTable::GetColumnCount`.

        Returns
        -------
        int
            The number of columns in the RAT

        Examples
        --------
        >>> with gdal.Open('testrat.tif') as ds:
        ...     ds.GetRasterBand(1).GetDefaultRAT().GetColumnCount()
        ... 
        9


        """
        return _gdal.RasterAttributeTable_GetColumnCount(self, *args)

    def GetNameOfCol(self, *args):
        r"""
        GetNameOfCol(self, iCol) -> char const *


        Get the name of a specified column (0-indexed).

        See :cpp:func:`GDALRasterAttributeTable::GetNameOfCol`.

        Parameters
        ----------
        iCol : int
            The index of the column (starting at 0)

        Returns
        -------
        str
            The name of the column

        Examples
        --------
        >>> ds = gdal.Open('testrat.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> [rat.GetNameOfCol(i) for i in range(rat.GetColumnCount())]
        ['VALUE', 'COUNT', 'CLASS', 'Red', 'Green', 'Blue', 'OtherInt', 'OtherReal', 'OtherStr']


        """
        return _gdal.RasterAttributeTable_GetNameOfCol(self, *args)

    def GetUsageOfCol(self, *args):
        r"""
        GetUsageOfCol(self, iCol) -> GDALRATFieldUsage


        Return the usage of a column in the RAT.

        See :cpp:func:`GDALRasterAttributeTable::GetUsageOfCol`.

        Parameters
        ----------
        iCol : int
            The index of the column (starting at 0)

        Returns
        -------
        int
            Usage code for the specified column

        Examples
        --------
        >>> ds = gdal.Open('testrat.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> [rat.GetUsageOfCol(i) for i in range(rat.GetColumnCount())]
        [5, 1, 2, 6, 7, 8, 0, 0, 0]
        >>> [rat.GetUsageOfCol(i) == gdal.GFU_Red for i in range(rat.GetColumnCount())]
        [False, False, False, True, False, False, False, False, False]


        """
        return _gdal.RasterAttributeTable_GetUsageOfCol(self, *args)

    def GetTypeOfCol(self, *args):
        r"""
        GetTypeOfCol(self, iCol) -> GDALRATFieldType


        Return the data type of a column in the RAT (one of :py:const:`GFT_Integer`, :py:const:`GFT_Real`, or :py:const:`GFT_String`).

        See :cpp:func:`GDALRasterAttributeTable::GetTypeOfCol`.

        Parameters
        ----------
        iCol : int
            The index of the column (starting at 0)

        Returns
        -------
        int
            type code for the specified column

        Examples
        --------
        >>> ds = gdal.Open('testrat.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> rat.GetTypeOfCol(2) == gdal.GFT_String
        True


        """
        return _gdal.RasterAttributeTable_GetTypeOfCol(self, *args)

    def GetColOfUsage(self, *args):
        r"""
        GetColOfUsage(self, eUsage) -> int


        Return the first column of a specified usage the a RAT.

        See :cpp:func:`GDALRasterAttributeTable::GetColOfUsage`.

        Parameters
        ----------
        eUsage : int
            Usage code such as :py:const:`gdal.GFU_Red`.

        Returns
        -------
        int
            Index of the column, or -1 if no such column can be found.

        Examples
        --------
        >>> ds = gdal.Open('testrat.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> rat.GetColOfUsage(gdal.GFU_Name)
        2
        >>> rat.GetColOfUsage(gdal.GFU_RedMin)
        -1


        """
        return _gdal.RasterAttributeTable_GetColOfUsage(self, *args)

    def GetRowCount(self, *args):
        r"""
        GetRowCount(self) -> int


        Return the number of rows in the RAT. 

        See :cpp:func:`GDALRasterAttributeTable::GetRowCount`.

        Returns
        -------
        int
            The number of rows in the RAT

        Examples
        --------
        >>> with gdal.Open('testrat.tif') as ds:
        ...     ds.GetRasterBand(1).GetDefaultRAT().GetRowCount()
        ... 
        2


        """
        return _gdal.RasterAttributeTable_GetRowCount(self, *args)

    def GetValueAsString(self, *args):
        r"""
        GetValueAsString(self, iRow, iCol) -> char const *


        Get the value of a single cell in the RAT.

        Parameters
        ----------
        iRow : int
            Row index (0-based)
        iCol : int
            Column index (0-based)

        """
        return _gdal.RasterAttributeTable_GetValueAsString(self, *args)

    def GetValueAsInt(self, *args):
        r"""
        GetValueAsInt(self, iRow, iCol) -> int


        Get the value of a single cell in the RAT.

        Parameters
        ----------
        iRow : int
            Row index (0-based)
        iCol : int
            Column index (0-based)

        """
        return _gdal.RasterAttributeTable_GetValueAsInt(self, *args)

    def GetValueAsDouble(self, *args):
        r"""
        GetValueAsDouble(self, iRow, iCol) -> double


        Get the value of a single cell in the RAT.

        Parameters
        ----------
        iRow : int
            Row index (0-based)
        iCol : int
            Column index (0-based)

        """
        return _gdal.RasterAttributeTable_GetValueAsDouble(self, *args)

    def GetValueAsBoolean(self, *args):
        r"""GetValueAsBoolean(self, iRow, iCol) -> bool"""
        return _gdal.RasterAttributeTable_GetValueAsBoolean(self, *args)

    def GetValueAsDateTime(self, *args):
        r"""GetValueAsDateTime(self, iRow, iCol) -> RATDateTime"""
        return _gdal.RasterAttributeTable_GetValueAsDateTime(self, *args)

    def GetValueAsWKBGeometry(self, *args):
        r"""GetValueAsWKBGeometry(self, iRow, iCol) -> CPLErr"""
        return _gdal.RasterAttributeTable_GetValueAsWKBGeometry(self, *args)

    def SetValueAsWKBGeometry(self, *args):
        r"""SetValueAsWKBGeometry(self, iRow, iCol, nLen) -> CPLErr"""
        return _gdal.RasterAttributeTable_SetValueAsWKBGeometry(self, *args)

    def ReadValuesIOAsString(self, *args):
        r"""
        ReadValuesIOAsString(self, iField, iStartRow, iLength) -> CPLErr


        Read a single column of a RAT into a list of strings.

        Parameters
        ----------
        iField : int
            The index of the column (starting at 0)
        iStartRow : int, default = 0
            The index of the first row to read (starting at 0)
        iLength : int, default = None
            The number of rows to read 

        Returns
        -------
        list

        Examples
        --------
        >>> ds = gdal.Open('testrat.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> rat.ReadValuesIOAsString(2, 0, 2)
        ['my class', 'my class2']

        See Also
        --------
        :py:meth:`ReadAsArray`


        """
        return _gdal.RasterAttributeTable_ReadValuesIOAsString(self, *args)

    def ReadValuesIOAsInteger(self, *args):
        r"""
        ReadValuesIOAsInteger(self, iField, iStartRow, iLength) -> CPLErr


        Read a single column of a RAT into a list of ints.

        Parameters
        ----------
        iField : int
            The index of the column (starting at 0)
        iStartRow : int, default = 0
            The index of the first row to read (starting at 0)
        iLength : int, default = None
            The number of rows to read 

        Returns
        -------
        list

        Examples
        --------
        >>> ds = gdal.Open('testrat.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> rat.ReadValuesIOAsInteger(3, 0, 2)
        [26, 26]

        See Also
        --------
        :py:meth:`ReadAsArray`


        """
        return _gdal.RasterAttributeTable_ReadValuesIOAsInteger(self, *args)

    def ReadValuesIOAsDouble(self, *args):
        r"""
        ReadValuesIOAsDouble(self, iField, iStartRow, iLength) -> CPLErr


        Read a single column of a RAT into a list of floats.

        Parameters
        ----------
        iField : int
            The index of the column (starting at 0)
        iStartRow : int, default = 0
            The index of the first row to read (starting at 0)
        iLength : int, default = None
            The number of rows to read 

        Returns
        -------
        list

        Examples
        --------
        >>> ds = gdal.Open('testrat.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> rat.ReadValuesIOAsDouble(3, 0, 2)
        [26.0, 26.0]

        See Also
        --------
        :py:meth:`ReadAsArray`


        """
        return _gdal.RasterAttributeTable_ReadValuesIOAsDouble(self, *args)

    def ReadValuesIOAsBoolean(self, *args):
        r"""ReadValuesIOAsBoolean(self, iField, iStartRow, iLength) -> CPLErr"""
        return _gdal.RasterAttributeTable_ReadValuesIOAsBoolean(self, *args)

    def SetValueAsString(self, *args):
        r"""
        SetValueAsString(self, iRow, iCol, pszValue)


        Set the value of a single cell in the RAT.

        If ``iRow`` is equal to the number of rows in the table, the table
        size will be increased by one. However, it is more efficient to
        call :py:meth:`SetRowCount` before repeated insertions.

        Parameters
        ----------
        iRow : int
            Row index (0-based)
        iCol : int
            Column index (0-based)
        pszValue : str
            Cell value

        """
        return _gdal.RasterAttributeTable_SetValueAsString(self, *args)

    def SetValueAsInt(self, *args):
        r"""
        SetValueAsInt(self, iRow, iCol, nValue)


        Set the value of a single cell in the RAT.

        If ``iRow`` is equal to the number of rows in the table, the table
        size will be increased by one. However, it is more efficient to
        call :py:meth:`SetRowCount` before repeated insertions.

        Parameters
        ----------
        iRow : int
            Row index (0-based)
        iCol : int
            Column index (0-based)
        nValue : int
            Cell value

        """
        return _gdal.RasterAttributeTable_SetValueAsInt(self, *args)

    def SetValueAsDouble(self, *args):
        r"""
        SetValueAsDouble(self, iRow, iCol, dfValue)


        Set the value of a single cell in the RAT.

        If ``iRow`` is equal to the number of rows in the table, the table
        size will be increased by one. However, it is more efficient to
        call :py:meth:`SetRowCount` before repeated insertions.

        Parameters
        ----------
        iRow : int
            Row index (0-based)
        iCol : int
            Column index (0-based)
        dfValue : float
            Cell value

        """
        return _gdal.RasterAttributeTable_SetValueAsDouble(self, *args)

    def SetValueAsBoolean(self, *args):
        r"""SetValueAsBoolean(self, iRow, iCol, value)"""
        return _gdal.RasterAttributeTable_SetValueAsBoolean(self, *args)

    def SetValueAsDateTime(self, *args):
        r"""SetValueAsDateTime(self, iRow, iCol, value)"""
        return _gdal.RasterAttributeTable_SetValueAsDateTime(self, *args)

    def SetRowCount(self, *args):
        r"""
        SetRowCount(self, nCount)


        Resizes the table to include the indicated number of rows. Newly created
        rows will be initialized to '' for strings and zero for numeric fields.

        See :cpp:func:`GDALRasterAttributeTable::SetRowCount`.

        Parameters
        ----------
        nCount : int
           The number of rows in the resized table


        """
        return _gdal.RasterAttributeTable_SetRowCount(self, *args)

    def CreateColumn(self, *args):
        r"""
        CreateColumn(self, pszName, eType, eUsage) -> int


        Create a new column in the RAT.

        If the table already has rows, all row values for the new column will
        be initialized to the default value ('', or zero).  The new column is
        always created as the last column.

        Parameters
        ----------
        pszName : str
            Name of the new column
        eType : int
            Data type of the new column (one of :py:const:`GFT_Integer`, :py:const:`GFT_Real`, or :py:const:`GFT_String`).
        eUsage : int
            Usage of the new column (see :cpp:enum:`GDALRATFieldUsage`)

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.


        """
        return _gdal.RasterAttributeTable_CreateColumn(self, *args)

    def GetLinearBinning(self, *args):
        r"""
        GetLinearBinning(self) -> bool


        Get linear binning information, if any.

        See :cpp:func:`GDALRasterAttributeTable::GetLinearBinning`.

        Returns
        -------
        list
           a three-element list indicating whether linear binning information
           is available, the minimum value associated with the smallest bin,
           and the size of each bin.


        """
        return _gdal.RasterAttributeTable_GetLinearBinning(self, *args)

    def SetLinearBinning(self, *args):
        r"""
        SetLinearBinning(self, dfRow0Min, dfBinSize) -> int


        Set linear binning information.

        This can be used to provide optimized table look-ups (via
        :py:meth:`GetRowOfValue`) when the rows of the table represent
        uniformly sized bins. 

        It is the responsibility of the user to actually define the 
        appropriate bins. If the bins do not correspond to the provided
        binning information, lookup values will be incorrect.

        See :cpp:func:`GDALRasterAttributeTable::SetLinearBinning`.

        Parameters
        ----------
        dfRow0Min : float
            Minimum value associated with the smallest bin   
        dfBinSize : float
            Size of each bin

        """
        return _gdal.RasterAttributeTable_SetLinearBinning(self, *args)

    def GetRowOfValue(self, *args):
        r"""
        GetRowOfValue(self, dfValue) -> int


        Return the index of the row that applies to a specific value,
        or -1 of no such row exists.

        See :cpp:func:`GDALRasterAttributeTable::GetRowOfValue`.

        Parameters
        ----------
        dfValue : float
            Value for which a row should be found

        Returns
        -------
        int
            Index of the row (0-based), or -1 of no row was found

        Examples
        --------
        >>> ds = gdal.Open('testrat.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> rat.GetValueAsString(rat.GetRowOfValue(2), 2)
        'my class2'
        >>> rat.GetValueAsString(rat.GetRowOfValue(802), 2)
        ''

        See Also
        --------
        :py:meth:`SetLinearBinning`


        """
        return _gdal.RasterAttributeTable_GetRowOfValue(self, *args)

    def ChangesAreWrittenToFile(self, *args):
        r"""ChangesAreWrittenToFile(self) -> int"""
        return _gdal.RasterAttributeTable_ChangesAreWrittenToFile(self, *args)

    def DumpReadable(self, *args):
        r"""
        DumpReadable(self)


        Return an XML representation of the RAT.

        Returns
        -------
        str


        """
        return _gdal.RasterAttributeTable_DumpReadable(self, *args)

    def SetTableType(self, *args):
        r"""
        SetTableType(self, eTableType)


        Set the type of the RAT (thematic or athematic).

        Parameters
        ----------
        eTableType : int
           Table type (:py:const:`GRTT_THEMATIC` or :py:const:`GRTT_ATHEMATIC`)    

        """
        return _gdal.RasterAttributeTable_SetTableType(self, *args)

    def GetTableType(self, *args):
        r"""
        GetTableType(self) -> GDALRATTableType


        Returns the type of the RAT (:py:const:`GRTT_THEMATIC` or :py:const:`GRTT_ATHEMATIC`).

        See :cpp:func:`GDALRasterAttributeTable::GetTableType`.

        Returns
        -------
        int
            table type code


        """
        return _gdal.RasterAttributeTable_GetTableType(self, *args)

    def RemoveStatistics(self, *args):
        r"""
        RemoveStatistics(self)


        Remove statistics information, such as a histogram, from the RAT.

        See :cpp:func:`GDALRasterAttributeTable::RemoveStatistics`.


        """
        return _gdal.RasterAttributeTable_RemoveStatistics(self, *args)



    def GetValueAsDateTime(self, iRow, iCol):
        """
        Fetch field value as a datetime.

        The value of the requested column in the requested row is returned
        as a Python datetime. Besides being called on a GFT_DateTime field, it
        is also possible to call this method on a string field that contains a
        ISO-8601 encoded datetime.

        Parameters
        ----------
        iRow : int
            The index of the row to read (starting at 0)
        iCol : int
            The index of the column to read (starting at 0)

        Returns
        -------
        datetime
            Datetime value, or None if it is invalid
        """

        import datetime
        import math
        RAT_dt = _gdal.RasterAttributeTable_GetValueAsDateTime(self, iRow, iCol)
        if not RAT_dt.bIsValid:
            return None
        delta = RAT_dt.nTimeZoneHour * 3600 + RAT_dt.nTimeZoneMinute * 60
        if not RAT_dt.bPositiveTimeZone:
            delta = -delta
        tz = datetime.timezone(datetime.timedelta(seconds=delta))
        return datetime.datetime(RAT_dt.nYear, RAT_dt.nMonth, RAT_dt.nDay,
                                 RAT_dt.nHour, RAT_dt.nMinute, int(RAT_dt.fSecond),
                                 int(math.fmod(RAT_dt.fSecond, 1) * 1e6 + 0.5),
                                 tz)

    def SetValueAsDateTime(self, iRow, iCol, dt):
        """
        Set field value from a datetime.

        The indicated field (column) on the indicated row is set from the
        passed value.  The value will be automatically converted for other field
        types, with a possible loss of precision.

        Parameters
        ----------
        iRow : int
            The index of the row to read (starting at 0)
        iCol : int
            The index of the column to read (starting at 0)
        dt : datetime | RATDateTime | None
            The datetime value
        """

        if dt is None:
            RAT_dt = RATDateTime()
            RAT_dt.bIsValid = False
        elif isinstance(dt, RATDateTime):
            RAT_dt = dt
        else:
            import datetime
            if not isinstance(dt, datetime.datetime):
                raise ValueError("dt is not a datetime.datetime instance")
            RAT_dt = RATDateTime()
            RAT_dt.nYear = dt.year
            RAT_dt.nMonth = dt.month
            RAT_dt.nDay = dt.day
            RAT_dt.nHour = dt.hour
            RAT_dt.nMinute = dt.minute
            RAT_dt.fSecond = dt.second + dt.microsecond * 1e-6
            RAT_dt.bPositiveTimeZone = False
            RAT_dt.nTimeZoneHour = 0
            RAT_dt.nTimeZoneMinute = 0
            RAT_dt.bIsValid = True
            tzinfo = dt.tzinfo
            if tzinfo:
                offset = tzinfo.utcoffset(dt)
                delta_minutes = offset.days * 24 * 60 + offset.seconds // 60
                if delta_minutes >= 0:
                    RAT_dt.bPositiveTimeZone = True
                else:
                    RAT_dt.bPositiveTimeZone = False
                    delta_minutes = -delta_minutes
                RAT_dt.nTimeZoneHour = delta_minutes // 60;
                RAT_dt.nTimeZoneMinute = delta_minutes % 60;

        _gdal.RasterAttributeTable_SetValueAsDateTime(self, iRow, iCol, RAT_dt)

    def WriteArray(self, array, field, start=0):
        """
        Write a NumPy array to a single column of a RAT.

        Parameters
        ----------
        array : np.ndarray
            One-dimensional array of values to write
        field : int
            The index of the column to write (starting at 0)
        start : int, default = 0
            The index of the first row to write (starting at 0)

        Returns
        -------
        int
            Error code, or ``gdal.CE_None`` if no error occurred.
        """
        from osgeo import gdal_array

        return gdal_array.RATWriteArray(self, array, field, start)

    def ReadAsArray(self, field, start=0, length=None):
        """
        Read a single column of a RAT into a NumPy array.

        Parameters
        ----------
        field : int
            The index of the column to read (starting at 0)
        start : int, default = 0
            The index of the first row to read (starting at 0)
        length : int, default = None
            The number of rows to read


        Returns
        -------
        np.ndarray

        Examples
        --------

        .. testsetup::
           >>> pytest.skip()

        >>> ds = gdal.Open('clc2018_v2020_20u1.tif')
        >>> rat = ds.GetRasterBand(1).GetDefaultRAT()
        >>> rat.ReadAsArray(0)
        array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
               18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
               35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 48], dtype=int32)
        >>> rat.ReadAsArray(0, 5, 3)
        array([6, 7, 8], dtype=int32)
        """

        from osgeo import gdal_array

        return gdal_array.RATReadArray(self, field, start, length)


# Register RasterAttributeTable in _gdal:
_gdal.RasterAttributeTable_swigregister(RasterAttributeTable)
GEDTST_NONE = _gdal.GEDTST_NONE

GEDTST_JSON = _gdal.GEDTST_JSON

class Group(object):
    r"""Proxy of C++ GDALGroupHS class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_Group

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.Group_GetName(self, *args)

    def GetFullName(self, *args):
        r"""GetFullName(self) -> char const *"""
        return _gdal.Group_GetFullName(self, *args)

    def GetMDArrayNames(self, options = []) -> "list[str]":
        ret = _gdal.Group_GetMDArrayNames(self, options)
        if ret is None:
            ret = []
        return ret



    def GetMDArrayFullNamesRecursive(self, *args):
        r"""GetMDArrayFullNamesRecursive(self, groupOptions=None, arrayOptions=None) -> char **"""
        return _gdal.Group_GetMDArrayFullNamesRecursive(self, *args)

    def OpenMDArray(self, *args):
        r"""OpenMDArray(self, name, options=None) -> MDArray"""
        return _gdal.Group_OpenMDArray(self, *args)

    def OpenMDArrayFromFullname(self, *args):
        r"""OpenMDArrayFromFullname(self, name, options=None) -> MDArray"""
        return _gdal.Group_OpenMDArrayFromFullname(self, *args)

    def ResolveMDArray(self, *args):
        r"""ResolveMDArray(self, name, starting_point, options=None) -> MDArray"""
        return _gdal.Group_ResolveMDArray(self, *args)

    def GetGroupNames(self, options = []) -> "list[str]":
        ret = _gdal.Group_GetGroupNames(self, options)
        if ret is None:
            ret = []
        return ret



    def OpenGroup(self, *args):
        r"""OpenGroup(self, name, options=None) -> Group"""
        return _gdal.Group_OpenGroup(self, *args)

    def OpenGroupFromFullname(self, *args):
        r"""OpenGroupFromFullname(self, name, options=None) -> Group"""
        return _gdal.Group_OpenGroupFromFullname(self, *args)

    def GetVectorLayerNames(self, *args):
        r"""GetVectorLayerNames(self, options=None) -> char **"""
        return _gdal.Group_GetVectorLayerNames(self, *args)

    def OpenVectorLayer(self, *args):
        r"""OpenVectorLayer(self, name, options=None) -> Layer"""
        return _gdal.Group_OpenVectorLayer(self, *args)

    def GetDimensions(self, *args):
        r"""GetDimensions(self, options=None)"""
        return _gdal.Group_GetDimensions(self, *args)

    def GetAttribute(self, *args):
        r"""GetAttribute(self, name) -> Attribute"""
        return _gdal.Group_GetAttribute(self, *args)

    def GetAttributes(self, *args):
        r"""GetAttributes(self, options=None)"""
        return _gdal.Group_GetAttributes(self, *args)

    def GetStructuralInfo(self, *args):
        r"""GetStructuralInfo(self) -> char **"""
        return _gdal.Group_GetStructuralInfo(self, *args)

    def CreateGroup(self, *args, **kwargs):
        r"""CreateGroup(self, name, options=None) -> Group"""
        return _gdal.Group_CreateGroup(self, *args, **kwargs)

    def DeleteGroup(self, *args):
        r"""DeleteGroup(self, name, options=None) -> CPLErr"""
        return _gdal.Group_DeleteGroup(self, *args)

    def CreateDimension(self, *args, **kwargs):
        r"""
        CreateDimension(self, name, dim_type, direction, size, options=None) -> Dimension


        Create a dimension within a :py:class:`Group`.

        See :cpp:func:`GDALGroup::CreateDimension`.

        Parameters
        ----------
        name : str
            Dimension name
        dim_type : str
            Dimension type (might be empty, and ignored by drivers)
        direction : str
            Dimension direction (might be empty, and ignored by drivers)
        size : int
            Number of values indexed by this dimension. Should be > 0
        options : dict or list, optional
            dict or list of driver specific ``NAME=VALUE`` option strings.

        Returns
        -------

        Dimension
            the new :py:class:`Dimension` or ``None`` on failure.

        Examples
        --------

        >>> drv = gdal.GetDriverByName('MEM')
        >>> mem_ds = drv.CreateMultiDimensional('myds')
        >>> rg = mem_ds.GetRootGroup()
        >>> dim_band = rg.CreateDimension('band', None, None, 3)
        >>> dim_x = rg.CreateDimension('X', None, None, 2)
        >>> dim_x.GetFullName()
        '/X'
        >>> lat = rg.CreateDimension('latitude', gdal.DIM_TYPE_HORIZONTAL_X, None, 2)
        >>> lat.GetType()
        'HORIZONTAL_X'

        """
        return _gdal.Group_CreateDimension(self, *args, **kwargs)

    def CreateMDArray(self, *args):
        r"""
        CreateMDArray(self, name, dimensions, data_type, options=None) -> MDArray


        Create a multidimensional array within a group.

        It is recommended that the GDALDimension objects passed in ``dimensions``
        belong to this group, either by retrieving them with :py:meth:`GetDimensions`
        or creating a new one with :py:meth:`CreateDimension`.

        See :cpp:func:`GDALGroup::CreateMDArray`.

        Parameters
        ----------
        name : str
            name
        dimensions : list
            List of dimensions, ordered from the slowest varying
            dimension first to the fastest varying dimension last.
            Might be empty for a scalar array (if supported by driver)
        data_type : :py:class:`ExtendedDataType`
            Array data type
        options : dict or list, optional
            dict or list of driver specific ``NAME=VALUE`` option strings.

        Returns
        -------

        MDArray
            the new :py:class:`MDArray` or ``None`` on failure.

        Examples
        --------
        >>> drv = gdal.GetDriverByName('MEM')
        >>> mem_ds = drv.CreateMultiDimensional('myds')
        >>> rg = mem_ds.GetRootGroup()
        >>> dimX = rg.CreateDimension('X', None, None, 3)
        >>> ar = rg.CreateMDArray('ar', [dimX], gdal.ExtendedDataType.Create(gdal.GDT_Byte))


        """
        return _gdal.Group_CreateMDArray(self, *args)

    def DeleteMDArray(self, *args):
        r"""DeleteMDArray(self, name, options=None) -> CPLErr"""
        return _gdal.Group_DeleteMDArray(self, *args)

    def CreateAttribute(self, *args):
        r"""
        CreateAttribute(self, name, dimensions, data_type, options=None) -> Attribute


        Create an attribute within a :py:class:`MDArray` or :py:class:`Group`.

        See :cpp:func:`GDALIHasAttribute::CreateAttribute`.

        Parameters
        ----------
        name : str
            name
        dimensions : list
            List of dimensions, ordered from the slowest varying
            dimension first to the fastest varying dimension last.
            Might be empty for a scalar array (if supported by driver)
        data_type : :py:class:`ExtendedDataType`
            Attribute data type
        options : dict or list, optional
            dict or list of driver specific ``NAME=VALUE`` option strings.

        Returns
        -------

        Attribute
            the new :py:class:`Attribute` or ``None`` on failure.

        Examples
        --------

        >>> drv = gdal.GetDriverByName('MEM')
        >>> mem_ds = drv.CreateMultiDimensional('myds')
        >>> rg = mem_ds.GetRootGroup()
        >>> dim = rg.CreateDimension('dim', None, None, 2)
        >>> ar = rg.CreateMDArray('ar_double', [dim], gdal.ExtendedDataType.Create(gdal.GDT_Float64))
        >>> numeric_attr = ar.CreateAttribute('numeric_attr', [], gdal.ExtendedDataType.Create(gdal.GDT_Float64))
        >>> string_attr = ar.CreateAttribute('string_attr', [], gdal.ExtendedDataType.CreateString())


        """
        return _gdal.Group_CreateAttribute(self, *args)

    def DeleteAttribute(self, *args):
        r"""DeleteAttribute(self, name, options=None) -> CPLErr"""
        return _gdal.Group_DeleteAttribute(self, *args)

    def Rename(self, *args):
        r"""Rename(self, newName) -> CPLErr"""
        return _gdal.Group_Rename(self, *args)

    def SubsetDimensionFromSelection(self, *args):
        r"""SubsetDimensionFromSelection(self, selection, options=None) -> Group"""
        return _gdal.Group_SubsetDimensionFromSelection(self, *args)

    def GetDataTypeCount(self, *args):
        r"""GetDataTypeCount(self) -> size_t"""
        return _gdal.Group_GetDataTypeCount(self, *args)

    def GetDataType(self, *args):
        r"""GetDataType(self, idx) -> ExtendedDataType"""
        return _gdal.Group_GetDataType(self, *args)

    def GetDataTypes(self):
        """Return data types associated with that group (typically enumerations)
        """
        return [self.GetDataType(i) for i in range(self.GetDataTypeCount())]


# Register Group in _gdal:
_gdal.Group_swigregister(Group)
class Statistics(object):
    r"""Proxy of C++ Statistics class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    min = property(_gdal.Statistics_min_get, doc=r"""min""")
    max = property(_gdal.Statistics_max_get, doc=r"""max""")
    mean = property(_gdal.Statistics_mean_get, doc=r"""mean""")
    std_dev = property(_gdal.Statistics_std_dev_get, doc=r"""std_dev""")
    valid_count = property(_gdal.Statistics_valid_count_get, doc=r"""valid_count""")
    __swig_destroy__ = _gdal.delete_Statistics

    def __init__(self, *args):
        r"""__init__(self) -> Statistics"""
        _gdal.Statistics_swiginit(self, _gdal.new_Statistics(*args))

# Register Statistics in _gdal:
_gdal.Statistics_swigregister(Statistics)
class RawBlockInfo(object):
    r"""Proxy of C++ GDALMDArrayRawBlockInfo class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_RawBlockInfo

    def GetOffset(self, *args):
        r"""GetOffset(self) -> GUIntBig"""
        return _gdal.RawBlockInfo_GetOffset(self, *args)

    def GetSize(self, *args):
        r"""GetSize(self) -> GUIntBig"""
        return _gdal.RawBlockInfo_GetSize(self, *args)

    def GetFilename(self, *args):
        r"""GetFilename(self) -> char const *"""
        return _gdal.RawBlockInfo_GetFilename(self, *args)

    def GetInfo(self, *args):
        r"""GetInfo(self) -> char **"""
        return _gdal.RawBlockInfo_GetInfo(self, *args)

    def GetInlineData(self, *args):
        r"""GetInlineData(self)"""
        return _gdal.RawBlockInfo_GetInlineData(self, *args)

    def __init__(self, *args):
        r"""__init__(self) -> RawBlockInfo"""
        _gdal.RawBlockInfo_swiginit(self, _gdal.new_RawBlockInfo(*args))

# Register RawBlockInfo in _gdal:
_gdal.RawBlockInfo_swigregister(RawBlockInfo)
class MDArray(object):
    r"""Proxy of C++ GDALMDArrayHS class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_MDArray

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.MDArray_GetName(self, *args)

    def GetFullName(self, *args):
        r"""GetFullName(self) -> char const *"""
        return _gdal.MDArray_GetFullName(self, *args)

    def GetTotalElementsCount(self, *args):
        r"""GetTotalElementsCount(self) -> GUIntBig"""
        return _gdal.MDArray_GetTotalElementsCount(self, *args)

    def GetDimensionCount(self, *args):
        r"""GetDimensionCount(self) -> size_t"""
        return _gdal.MDArray_GetDimensionCount(self, *args)

    def GetDimensions(self, *args):
        r"""GetDimensions(self)"""
        return _gdal.MDArray_GetDimensions(self, *args)

    def GetCoordinateVariables(self, *args):
        r"""GetCoordinateVariables(self)"""
        return _gdal.MDArray_GetCoordinateVariables(self, *args)

    def GetBlockSize(self, *args):
        r"""GetBlockSize(self)"""
        return _gdal.MDArray_GetBlockSize(self, *args)

    def GetProcessingChunkSize(self, *args):
        r"""GetProcessingChunkSize(self, nMaxChunkMemory)"""
        return _gdal.MDArray_GetProcessingChunkSize(self, *args)

    def GetDataType(self, *args):
        r"""GetDataType(self) -> ExtendedDataType"""
        return _gdal.MDArray_GetDataType(self, *args)

    def GetStructuralInfo(self, *args):
        r"""GetStructuralInfo(self) -> char **"""
        return _gdal.MDArray_GetStructuralInfo(self, *args)

    def Resize(self, *args):
        r"""Resize(self, newDimensions, options=None) -> CPLErr"""
        return _gdal.MDArray_Resize(self, *args)

    def Read(self, *args):
        r"""Read(self, nDims1, nDims2, nDims3, nDims4, buffer_datatype) -> CPLErr"""
        return _gdal.MDArray_Read(self, *args)

    def WriteStringArray(self, *args):
        r"""WriteStringArray(self, nDims1, nDims2, nDims3, buffer_datatype, options) -> CPLErr"""
        return _gdal.MDArray_WriteStringArray(self, *args)

    def Write(self, *args):
        r"""Write(self, nDims1, nDims2, nDims3, nDims4, buffer_datatype, buf_len) -> CPLErr"""
        return _gdal.MDArray_Write(self, *args)

    def AdviseRead(self, *args):
        r"""AdviseRead(self, nDims1, nDims2, options=None) -> CPLErr"""
        return _gdal.MDArray_AdviseRead(self, *args)

    def GetAttribute(self, *args):
        r"""GetAttribute(self, name) -> Attribute"""
        return _gdal.MDArray_GetAttribute(self, *args)

    def GetAttributes(self, *args):
        r"""GetAttributes(self, options=None)"""
        return _gdal.MDArray_GetAttributes(self, *args)

    def CreateAttribute(self, *args):
        r"""
        CreateAttribute(self, name, dimensions, data_type, options=None) -> Attribute


        Create an attribute within a :py:class:`MDArray` or :py:class:`Group`.

        See :cpp:func:`GDALIHasAttribute::CreateAttribute`.

        Parameters
        ----------
        name : str
            name
        dimensions : list
            List of dimensions, ordered from the slowest varying
            dimension first to the fastest varying dimension last.
            Might be empty for a scalar array (if supported by driver)
        data_type : :py:class:`ExtendedDataType`
            Attribute data type
        options : dict or list, optional
            dict or list of driver specific ``NAME=VALUE`` option strings.

        Returns
        -------

        Attribute
            the new :py:class:`Attribute` or ``None`` on failure.

        Examples
        --------

        >>> drv = gdal.GetDriverByName('MEM')
        >>> mem_ds = drv.CreateMultiDimensional('myds')
        >>> rg = mem_ds.GetRootGroup()
        >>> dim = rg.CreateDimension('dim', None, None, 2)
        >>> ar = rg.CreateMDArray('ar_double', [dim], gdal.ExtendedDataType.Create(gdal.GDT_Float64))
        >>> numeric_attr = ar.CreateAttribute('numeric_attr', [], gdal.ExtendedDataType.Create(gdal.GDT_Float64))
        >>> string_attr = ar.CreateAttribute('string_attr', [], gdal.ExtendedDataType.CreateString())


        """
        return _gdal.MDArray_CreateAttribute(self, *args)

    def DeleteAttribute(self, *args):
        r"""DeleteAttribute(self, name, options=None) -> CPLErr"""
        return _gdal.MDArray_DeleteAttribute(self, *args)

    def GetNoDataValueAsRaw(self, *args):
        r"""GetNoDataValueAsRaw(self) -> CPLErr"""
        return _gdal.MDArray_GetNoDataValueAsRaw(self, *args)

    def GetNoDataValueAsDouble(self, *args):
        r"""GetNoDataValueAsDouble(self)"""
        return _gdal.MDArray_GetNoDataValueAsDouble(self, *args)

    def GetNoDataValueAsInt64(self, *args):
        r"""GetNoDataValueAsInt64(self)"""
        return _gdal.MDArray_GetNoDataValueAsInt64(self, *args)

    def GetNoDataValueAsUInt64(self, *args):
        r"""GetNoDataValueAsUInt64(self)"""
        return _gdal.MDArray_GetNoDataValueAsUInt64(self, *args)

    def GetNoDataValueAsString(self, *args):
        r"""GetNoDataValueAsString(self) -> retStringAndCPLFree *"""
        return _gdal.MDArray_GetNoDataValueAsString(self, *args)

    def SetNoDataValueDouble(self, *args):
        r"""SetNoDataValueDouble(self, d) -> CPLErr"""
        return _gdal.MDArray_SetNoDataValueDouble(self, *args)

    def SetNoDataValueInt64(self, *args):
        r"""SetNoDataValueInt64(self, v) -> CPLErr"""
        return _gdal.MDArray_SetNoDataValueInt64(self, *args)

    def SetNoDataValueUInt64(self, *args):
        r"""SetNoDataValueUInt64(self, v) -> CPLErr"""
        return _gdal.MDArray_SetNoDataValueUInt64(self, *args)

    def SetNoDataValueString(self, *args):
        r"""SetNoDataValueString(self, nodata) -> CPLErr"""
        return _gdal.MDArray_SetNoDataValueString(self, *args)

    def SetNoDataValueRaw(self, *args):
        r"""SetNoDataValueRaw(self, nLen) -> CPLErr"""
        return _gdal.MDArray_SetNoDataValueRaw(self, *args)

    def DeleteNoDataValue(self, *args):
        r"""DeleteNoDataValue(self) -> CPLErr"""
        return _gdal.MDArray_DeleteNoDataValue(self, *args)

    def GetOffset(self, *args):
        r"""GetOffset(self)"""
        return _gdal.MDArray_GetOffset(self, *args)

    def GetOffsetStorageType(self, *args):
        r"""GetOffsetStorageType(self) -> GDALDataType"""
        return _gdal.MDArray_GetOffsetStorageType(self, *args)

    def GetScale(self, *args):
        r"""GetScale(self)"""
        return _gdal.MDArray_GetScale(self, *args)

    def GetScaleStorageType(self, *args):
        r"""GetScaleStorageType(self) -> GDALDataType"""
        return _gdal.MDArray_GetScaleStorageType(self, *args)

    def SetOffset(self, *args, **kwargs):
        r"""SetOffset(self, val, storageType=GDT_Unknown) -> CPLErr"""
        return _gdal.MDArray_SetOffset(self, *args, **kwargs)

    def SetScale(self, *args, **kwargs):
        r"""SetScale(self, val, storageType=GDT_Unknown) -> CPLErr"""
        return _gdal.MDArray_SetScale(self, *args, **kwargs)

    def SetUnit(self, *args):
        r"""SetUnit(self, unit) -> CPLErr"""
        return _gdal.MDArray_SetUnit(self, *args)

    def GetUnit(self, *args):
        r"""GetUnit(self) -> char const *"""
        return _gdal.MDArray_GetUnit(self, *args)

    def SetSpatialRef(self, *args):
        r"""SetSpatialRef(self, srs) -> OGRErr"""
        return _gdal.MDArray_SetSpatialRef(self, *args)

    def GetSpatialRef(self, *args):
        r"""GetSpatialRef(self) -> SpatialReference"""
        return _gdal.MDArray_GetSpatialRef(self, *args)

    def GetView(self, *args):
        r"""GetView(self, viewExpr) -> MDArray"""
        return _gdal.MDArray_GetView(self, *args)

    def Transpose(self, *args):
        r"""Transpose(self, axisMap) -> MDArray"""
        return _gdal.MDArray_Transpose(self, *args)

    def GetUnscaled(self, *args):
        r"""GetUnscaled(self) -> MDArray"""
        return _gdal.MDArray_GetUnscaled(self, *args)

    def GetMask(self, *args):
        r"""GetMask(self, options=None) -> MDArray"""
        return _gdal.MDArray_GetMask(self, *args)

    def GetGridded(self, *args, **kwargs):
        r"""GetGridded(self, pszGridOptions, xArray=None, yArray=None, options=None) -> MDArray"""
        return _gdal.MDArray_GetGridded(self, *args, **kwargs)

    def AsClassicDataset(self, *args):
        r"""AsClassicDataset(self, iXDim, iYDim, hRootGroup=None, options=None) -> Dataset"""
        return _gdal.MDArray_AsClassicDataset(self, *args)

    def GetRawBlockInfo(self, *args):
        r"""GetRawBlockInfo(self, nDims) -> RawBlockInfo"""
        return _gdal.MDArray_GetRawBlockInfo(self, *args)

    def GetStatistics(self, *args, **kwargs):
        r"""GetStatistics(self, approx_ok=FALSE, force=TRUE, callback=0, callback_data=None) -> Statistics"""
        return _gdal.MDArray_GetStatistics(self, *args, **kwargs)

    def ComputeStatistics(self, *args, **kwargs):
        r"""ComputeStatistics(self, approx_ok=FALSE, callback=0, callback_data=None, options=None) -> Statistics"""
        return _gdal.MDArray_ComputeStatistics(self, *args, **kwargs)

    def GetResampled(self, *args):
        r"""GetResampled(self, nDimensions, resample_alg, srs, options=None) -> MDArray"""
        return _gdal.MDArray_GetResampled(self, *args)

    @staticmethod
    def GetMeshGrid(*args):
        r"""GetMeshGrid(nInputArrays, options=None)"""
        return _gdal.MDArray_GetMeshGrid(*args)

    def Cache(self, *args):
        r"""Cache(self, options=None) -> bool"""
        return _gdal.MDArray_Cache(self, *args)

    def Rename(self, *args):
        r"""Rename(self, newName) -> CPLErr"""
        return _gdal.MDArray_Rename(self, *args)

    def GetOverviewCount(self, *args):
        r"""GetOverviewCount(self) -> int"""
        return _gdal.MDArray_GetOverviewCount(self, *args)

    def GetOverview(self, *args):
        r"""GetOverview(self, idx) -> MDArray"""
        return _gdal.MDArray_GetOverview(self, *args)

    def BuildOverviews(self, *args):
        r"""BuildOverviews(self, resampling="NEAREST", overviewlist=0, callback=0, callback_data=None, options=None) -> CPLErr"""
        return _gdal.MDArray_BuildOverviews(self, *args)

    def Read(self,
             array_start_idx = None,
             count = None,
             array_step = None,
             buffer_stride = None,
             buffer_datatype = None):
        if not array_start_idx:
          array_start_idx = [0] * self.GetDimensionCount()
        if not count:
          count = [ dim.GetSize() for dim in self.GetDimensions() ]
        if not array_step:
          array_step = [1] * self.GetDimensionCount()
        if not buffer_stride:
          stride = 1
          buffer_stride = []
    # To compute strides we must proceed from the fastest varying dimension
    # (the last one), and then reverse the result
          for cnt in reversed(count):
              buffer_stride.append(stride)
              stride *= cnt
          buffer_stride.reverse()
        if not buffer_datatype:
          buffer_datatype = self.GetDataType()
          if buffer_datatype.GetClass() == GEDTC_NUMERIC and buffer_datatype.GetNumericDataType() == gdalconst.GDT_Float16:
            buffer_datatype = ExtendedDataType.Create(GDT_Float32)
          elif buffer_datatype.GetClass() == GEDTC_NUMERIC and buffer_datatype.GetNumericDataType() == gdalconst.GDT_CFloat16:
            buffer_datatype = ExtendedDataType.Create(GDT_CFloat32)
        return _gdal.MDArray_Read(self, array_start_idx, count, array_step, buffer_stride, buffer_datatype)

    def ReadAsArray(self,
                    array_start_idx = None,
                    count = None,
                    array_step = None,
                    buffer_datatype = None,
                    buf_obj = None):

        from osgeo import gdal_array
        return gdal_array.MDArrayReadAsArray(self, array_start_idx, count, array_step, buffer_datatype, buf_obj)

    def AdviseRead(self, array_start_idx = None, count = None, options = []):
        if not array_start_idx:
          array_start_idx = [0] * self.GetDimensionCount()
        if not count:
          count = [ (self.GetDimensions()[i].GetSize() - array_start_idx[i]) for i in range (self.GetDimensionCount()) ]
        return _gdal.MDArray_AdviseRead(self, array_start_idx, count, options)

    def __getitem__(self, item):

          def stringify(v):
              if v == Ellipsis:
                  return '...'
              if isinstance(v, slice):
                  return ':'.join([str(x) if x is not None else '' for x in (v.start, v.stop, v.step)])
              if isinstance(v, str):
                  return v
              if isinstance(v, (int, type(12345678901234))):
                  return str(v)
              try:
                  import numpy as np
                  if v == np.newaxis:
                      return 'newaxis'
              except:
                  pass

              return str(v)

          if isinstance(item, str):
              return self.GetView('["' + item.replace('\\', '\\\\').replace('"', '\\"') + '"]')
          elif isinstance(item, slice):
              return self.GetView('[' + stringify(item) + ']')
          elif isinstance(item, tuple):
              return self.GetView('[' + ','.join([stringify(x) for x in item]) + ']')
          else:
              return self.GetView('[' + stringify(item) + ']')

    def Write(self,
             buffer,
             array_start_idx = None,
             count = None,
             array_step = None,
             buffer_stride = None,
             buffer_datatype = None):

        dimCount = self.GetDimensionCount()

    # Redirect to numpy-friendly WriteArray() if buffer is a numpy array
    # and other arguments are compatible
        if type(buffer).__name__ == 'ndarray' and \
           count is None and buffer_stride is None and buffer_datatype is None:
            return self.WriteArray(buffer, array_start_idx=array_start_idx, array_step=array_step)

    # Special case for buffer of type array and 1D arrays
        if dimCount == 1 and type(buffer).__name__ == 'array' and \
           count is None and buffer_stride is None and buffer_datatype is None:
            map_typecode_itemsize_to_gdal = {
               ('B', 1): GDT_Byte,
               ('b', 1): GDT_Int8,
               ('h', 2): GDT_Int16,
               ('H', 2): GDT_UInt16,
               ('i', 4): GDT_Int32,
               ('I', 4): GDT_UInt32,
               ('l', 4): GDT_Int32,
               ('q', 8): GDT_Int64,
               ('Q', 8): GDT_UInt64,
               ('e', 2): GDT_Float16,
               ('f', 4): GDT_Float32,
               ('d', 8): GDT_Float64,
    # ('E', 2): GDT_CFloat16,
               ('F', 4): GDT_CFloat32,
               ('D', 8): GDT_CFloat64
            }
            key = (buffer.typecode, buffer.itemsize)
            if key not in map_typecode_itemsize_to_gdal:
                raise Exception("unhandled type for buffer of type array")
            buffer_datatype = ExtendedDataType.Create(map_typecode_itemsize_to_gdal[key])

    # Special case for a list of numeric values and 1D arrays
        elif dimCount == 1 and type(buffer) == type([]) and len(buffer) != 0 \
             and self.GetDataType().GetClass() != GEDTC_STRING:
            buffer_datatype = GDT_Int32
            for v in buffer:
                if isinstance(v, int):
                    if v >= (1 << 31) or v < -(1 << 31):
                        buffer_datatype = GDT_Float64
                elif isinstance(v, float):
                    buffer_datatype = GDT_Float64
                else:
                    raise ValueError('Only lists with integer or float elements are supported')
            import array
            buffer = array.array('d' if buffer_datatype == GDT_Float64 else 'i', buffer)
            buffer_datatype = ExtendedDataType.Create(buffer_datatype)

        if not buffer_datatype:
          buffer_datatype = self.GetDataType()

        is_0d_or_1d_string = self.GetDataType().GetClass() == GEDTC_STRING and buffer_datatype.GetClass() == GEDTC_STRING and dimCount <= 1

        if not array_start_idx:
          array_start_idx = [0] * dimCount

        if not count:
          if is_0d_or_1d_string:
              assert type(buffer) == type([])
              count = [ len(buffer) ]
          else:
              count = [ dim.GetSize() for dim in self.GetDimensions() ]

        if not array_step:
          array_step = [1] * dimCount

        if not buffer_stride:
          stride = 1
          buffer_stride = []
    # To compute strides we must proceed from the fastest varying dimension
    # (the last one), and then reverse the result
          for cnt in reversed(count):
              buffer_stride.append(stride)
              stride *= cnt
          buffer_stride.reverse()

        if is_0d_or_1d_string:
            return _gdal.MDArray_WriteStringArray(self, array_start_idx, count, array_step, buffer_datatype, buffer)

        return _gdal.MDArray_Write(self, array_start_idx, count, array_step, buffer_stride, buffer_datatype, buffer)

    def WriteArray(self, array,
                    array_start_idx = None,
                    array_step = None):

        from osgeo import gdal_array
        return gdal_array.MDArrayWriteArray(self, array, array_start_idx, array_step)

    def ReadAsMaskedArray(self,
                    array_start_idx = None,
                    count = None,
                    array_step = None):
        """ Return a numpy masked array of ReadAsArray() with GetMask() """
        import numpy
        mask = self.GetMask()
        if mask is not None:
            array = self.ReadAsArray(array_start_idx, count, array_step)
            mask_array = mask.ReadAsArray(array_start_idx, count, array_step)
            bool_array = ~mask_array.astype(bool)
            return numpy.ma.array(array, mask=bool_array)
        else:
            return numpy.ma.array(self.ReadAsArray(array_start_idx, count, array_step), mask=None)

    def GetShape(self):
      """ Return the shape of the array """
      if not self.GetDimensionCount():
        return None
      shp = ()
      for dim in self.GetDimensions():
        shp += (dim.GetSize(),)
      return shp

    shape = property(fget=GetShape, doc='Returns the shape of the array.')


    def GetNoDataValue(self):
      """GetNoDataValue(MDArray self) -> value """

      dt = self.GetDataType()
      if dt.GetClass() == GEDTC_NUMERIC and dt.GetNumericDataType() == gdalconst.GDT_Int64:
          return _gdal.MDArray_GetNoDataValueAsInt64(self)

      if dt.GetClass() == GEDTC_NUMERIC and dt.GetNumericDataType() == gdalconst.GDT_UInt64:
          return _gdal.MDArray_GetNoDataValueAsUInt64(self)

      return _gdal.MDArray_GetNoDataValueAsDouble(self)


    def SetNoDataValue(self, value):
      """SetNoDataValue(MDArray self, value) -> CPLErr"""

      dt = self.GetDataType()
      if dt.GetClass() == GEDTC_NUMERIC and dt.GetNumericDataType() == gdalconst.GDT_Int64:
          return _gdal.MDArray_SetNoDataValueInt64(self, value)

      if dt.GetClass() == GEDTC_NUMERIC and dt.GetNumericDataType() == gdalconst.GDT_UInt64:
          return _gdal.MDArray_SetNoDataValueUInt64(self, value)

      return _gdal.MDArray_SetNoDataValueDouble(self, value)


# Register MDArray in _gdal:
_gdal.MDArray_swigregister(MDArray)
class Attribute(object):
    r"""Proxy of C++ GDALAttributeHS class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_Attribute

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.Attribute_GetName(self, *args)

    def GetFullName(self, *args):
        r"""GetFullName(self) -> char const *"""
        return _gdal.Attribute_GetFullName(self, *args)

    def GetTotalElementsCount(self, *args):
        r"""GetTotalElementsCount(self) -> GUIntBig"""
        return _gdal.Attribute_GetTotalElementsCount(self, *args)

    def GetDimensionCount(self, *args):
        r"""GetDimensionCount(self) -> size_t"""
        return _gdal.Attribute_GetDimensionCount(self, *args)

    def GetDimensionsSize(self, *args):
        r"""GetDimensionsSize(self)"""
        return _gdal.Attribute_GetDimensionsSize(self, *args)

    def GetDataType(self, *args):
        r"""GetDataType(self) -> ExtendedDataType"""
        return _gdal.Attribute_GetDataType(self, *args)

    def ReadAsRaw(self, *args):
        r"""ReadAsRaw(self) -> CPLErr"""
        return _gdal.Attribute_ReadAsRaw(self, *args)

    def ReadAsString(self, *args):
        r"""ReadAsString(self) -> char const *"""
        return _gdal.Attribute_ReadAsString(self, *args)

    def ReadAsInt(self, *args):
        r"""ReadAsInt(self) -> int"""
        return _gdal.Attribute_ReadAsInt(self, *args)

    def ReadAsInt64(self, *args):
        r"""ReadAsInt64(self) -> long long"""
        return _gdal.Attribute_ReadAsInt64(self, *args)

    def ReadAsDouble(self, *args):
        r"""ReadAsDouble(self) -> double"""
        return _gdal.Attribute_ReadAsDouble(self, *args)

    def ReadAsStringArray(self, *args):
        r"""ReadAsStringArray(self) -> char **"""
        return _gdal.Attribute_ReadAsStringArray(self, *args)

    def ReadAsIntArray(self, *args):
        r"""ReadAsIntArray(self)"""
        return _gdal.Attribute_ReadAsIntArray(self, *args)

    def ReadAsInt64Array(self, *args):
        r"""ReadAsInt64Array(self)"""
        return _gdal.Attribute_ReadAsInt64Array(self, *args)

    def ReadAsDoubleArray(self, *args):
        r"""ReadAsDoubleArray(self)"""
        return _gdal.Attribute_ReadAsDoubleArray(self, *args)

    def WriteRaw(self, *args):
        r"""WriteRaw(self, nLen) -> CPLErr"""
        return _gdal.Attribute_WriteRaw(self, *args)

    def WriteString(self, *args):
        r"""WriteString(self, val) -> CPLErr"""
        return _gdal.Attribute_WriteString(self, *args)

    def WriteStringArray(self, *args):
        r"""WriteStringArray(self, vals) -> CPLErr"""
        return _gdal.Attribute_WriteStringArray(self, *args)

    def WriteInt(self, *args):
        r"""WriteInt(self, val) -> CPLErr"""
        return _gdal.Attribute_WriteInt(self, *args)

    def WriteInt64(self, *args):
        r"""WriteInt64(self, val) -> CPLErr"""
        return _gdal.Attribute_WriteInt64(self, *args)

    def WriteDouble(self, *args):
        r"""WriteDouble(self, val) -> CPLErr"""
        return _gdal.Attribute_WriteDouble(self, *args)

    def WriteIntArray(self, *args):
        r"""WriteIntArray(self, nList) -> CPLErr"""
        return _gdal.Attribute_WriteIntArray(self, *args)

    def WriteInt64Array(self, *args):
        r"""WriteInt64Array(self, nList) -> CPLErr"""
        return _gdal.Attribute_WriteInt64Array(self, *args)

    def WriteDoubleArray(self, *args):
        r"""WriteDoubleArray(self, nList) -> CPLErr"""
        return _gdal.Attribute_WriteDoubleArray(self, *args)

    def Rename(self, *args):
        r"""Rename(self, newName) -> CPLErr"""
        return _gdal.Attribute_Rename(self, *args)


    def Read(self):
      """ Read an attribute and return it with the most appropriate type """
      dt = self.GetDataType()
      dt_class = dt.GetClass()
      if dt_class == GEDTC_STRING:
          if self.GetTotalElementsCount() == 1:
              s = self.ReadAsString()
              if dt.GetSubType() == GEDTST_JSON:
                  try:
                      import json
                      return json.loads(s)
                  except:
                      pass
              return s
          return self.ReadAsStringArray()
      if dt_class == GEDTC_NUMERIC:
          if dt.GetNumericDataType() in (GDT_Byte, GDT_UInt16,
                                         GDT_Int8, GDT_Int16, GDT_Int32):
              if self.GetTotalElementsCount() == 1:
                  return self.ReadAsInt()
              return self.ReadAsIntArray()
          if dt.GetNumericDataType() in (GDT_UInt32, GDT_Int64):
              if self.GetTotalElementsCount() == 1:
                  return self.ReadAsInt64()
              return self.ReadAsInt64Array()
          if self.GetTotalElementsCount() == 1:
              return self.ReadAsDouble()
          return self.ReadAsDoubleArray()
      return self.ReadAsRaw()

    def Write(self, val):
      if isinstance(val, (int, type(12345678901234))):
          if val >= -0x80000000 and val <= 0x7FFFFFFF:
              return self.WriteInt(val)
          if val >= -0x8000000000000000 and val <= 0x7FFFFFFFFFFFFFFF:
              return self.WriteInt64(val)
          return self.WriteDouble(val)
      if isinstance(val, float):
          return self.WriteDouble(val)
      if isinstance(val, str) and self.GetDataType().GetClass() != GEDTC_COMPOUND:
          return self.WriteString(val)
      if isinstance(val, list):
          if len(val) == 0:
              if self.GetDataType().GetClass() == GEDTC_STRING:
                  return self.WriteStringArray(val)
              return self.WriteDoubleArray(val)
          if isinstance(val[0], (int, type(12345678901234))):
              if all(v >= -0x80000000 and v <= 0x7FFFFFFF for v in val):
                  return self.WriteIntArray(val)
              if all(v >= -0x8000000000000000 and v <= 0x7FFFFFFFFFFFFFFF
                     for v in val):
                  return self.WriteInt64Array(val)
              return self.WriteDoubleArray(val)
          if isinstance(val[0], float):
              return self.WriteDoubleArray(val)
          if isinstance(val[0], str):
              return self.WriteStringArray(val)
      if (isinstance(val, dict) and
          self.GetDataType().GetSubType() == GEDTST_JSON):
          import json
          return self.WriteString(json.dumps(val))
      return self.WriteRaw(val)



# Register Attribute in _gdal:
_gdal.Attribute_swigregister(Attribute)
class Dimension(object):
    r"""Proxy of C++ GDALDimensionHS class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_Dimension

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.Dimension_GetName(self, *args)

    def GetFullName(self, *args):
        r"""GetFullName(self) -> char const *"""
        return _gdal.Dimension_GetFullName(self, *args)

    def GetType(self, *args):
        r"""GetType(self) -> char const *"""
        return _gdal.Dimension_GetType(self, *args)

    def GetDirection(self, *args):
        r"""GetDirection(self) -> char const *"""
        return _gdal.Dimension_GetDirection(self, *args)

    def GetSize(self, *args):
        r"""GetSize(self) -> GUIntBig"""
        return _gdal.Dimension_GetSize(self, *args)

    def GetIndexingVariable(self, *args):
        r"""GetIndexingVariable(self) -> MDArray"""
        return _gdal.Dimension_GetIndexingVariable(self, *args)

    def SetIndexingVariable(self, *args):
        r"""SetIndexingVariable(self, array) -> bool"""
        return _gdal.Dimension_SetIndexingVariable(self, *args)

    def Rename(self, *args):
        r"""Rename(self, newName) -> CPLErr"""
        return _gdal.Dimension_Rename(self, *args)

# Register Dimension in _gdal:
_gdal.Dimension_swigregister(Dimension)
GEDTC_NUMERIC = _gdal.GEDTC_NUMERIC

GEDTC_STRING = _gdal.GEDTC_STRING

GEDTC_COMPOUND = _gdal.GEDTC_COMPOUND

class ExtendedDataType(object):
    r"""Proxy of C++ GDALExtendedDataTypeHS class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_ExtendedDataType

    @staticmethod
    def Create(*args):
        r"""Create(dt) -> ExtendedDataType"""
        return _gdal.ExtendedDataType_Create(*args)

    @staticmethod
    def CreateString(*args):
        r"""CreateString(nMaxStringLength=0, eSubType=GEDTST_NONE) -> ExtendedDataType"""
        return _gdal.ExtendedDataType_CreateString(*args)

    @staticmethod
    def CreateCompound(*args):
        r"""CreateCompound(name, nTotalSize, nComps) -> ExtendedDataType"""
        return _gdal.ExtendedDataType_CreateCompound(*args)

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.ExtendedDataType_GetName(self, *args)

    def GetClass(self, *args):
        r"""GetClass(self) -> GDALExtendedDataTypeClass"""
        return _gdal.ExtendedDataType_GetClass(self, *args)

    def GetNumericDataType(self, *args):
        r"""GetNumericDataType(self) -> GDALDataType"""
        return _gdal.ExtendedDataType_GetNumericDataType(self, *args)

    def GetSize(self, *args):
        r"""GetSize(self) -> size_t"""
        return _gdal.ExtendedDataType_GetSize(self, *args)

    def GetMaxStringLength(self, *args):
        r"""GetMaxStringLength(self) -> size_t"""
        return _gdal.ExtendedDataType_GetMaxStringLength(self, *args)

    def GetSubType(self, *args):
        r"""GetSubType(self) -> GDALExtendedDataTypeSubType"""
        return _gdal.ExtendedDataType_GetSubType(self, *args)

    def GetRAT(self, *args):
        r"""GetRAT(self) -> RasterAttributeTable"""
        return _gdal.ExtendedDataType_GetRAT(self, *args)

    def GetComponents(self, *args):
        r"""GetComponents(self)"""
        return _gdal.ExtendedDataType_GetComponents(self, *args)

    def CanConvertTo(self, *args):
        r"""CanConvertTo(self, other) -> bool"""
        return _gdal.ExtendedDataType_CanConvertTo(self, *args)

    def Equals(self, *args):
        r"""Equals(self, other) -> bool"""
        return _gdal.ExtendedDataType_Equals(self, *args)


    def __eq__(self, other):
      return self.Equals(other)

    def __ne__(self, other):
      return not self.__eq__(other)


# Register ExtendedDataType in _gdal:
_gdal.ExtendedDataType_swigregister(ExtendedDataType)
class EDTComponent(object):
    r"""Proxy of C++ GDALEDTComponentHS class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_EDTComponent

    @staticmethod
    def Create(*args):
        r"""Create(name, offset, type) -> EDTComponent"""
        return _gdal.EDTComponent_Create(*args)

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.EDTComponent_GetName(self, *args)

    def GetOffset(self, *args):
        r"""GetOffset(self) -> size_t"""
        return _gdal.EDTComponent_GetOffset(self, *args)

    def GetType(self, *args):
        r"""GetType(self) -> ExtendedDataType"""
        return _gdal.EDTComponent_GetType(self, *args)

# Register EDTComponent in _gdal:
_gdal.EDTComponent_swigregister(EDTComponent)

def CreateRasterAttributeTableFromMDArrays(*args):
    r"""CreateRasterAttributeTableFromMDArrays(eTableType, nArrays, nUsages=0) -> RasterAttributeTable"""
    return _gdal.CreateRasterAttributeTableFromMDArrays(*args)
class Band(MajorObject):
    r"""


    Python proxy of a :cpp:class:`GDALRasterBand`.


    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    XSize = property(_gdal.Band_XSize_get, doc=r"""XSize""")
    YSize = property(_gdal.Band_YSize_get, doc=r"""YSize""")
    DataType = property(_gdal.Band_DataType_get, doc=r"""DataType""")

    def GetDataset(self, *args):
        r"""
        GetDataset(self) -> Dataset


        Fetch the :py:class:`Dataset` associated with this Band.
        See :cpp:func:`GDALRasterBand::GetDataset`.

        """
        return _gdal.Band_GetDataset(self, *args)

    def GetBand(self, *args):
        r"""
        GetBand(self) -> int


        Return the index of this band.
        See :cpp:func:`GDALRasterBand::GetBand`.

        Returns
        -------
        int
            the (1-based) index of this band

        """
        return _gdal.Band_GetBand(self, *args)

    def GetBlockSize(self, *args):
        r"""
        GetBlockSize(self)


        Fetch the natural block size of this band.
        See :cpp:func:`GDALRasterBand::GetBlockSize`.

        Returns
        -------
        list
            list with the x and y dimensions of a block

        """
        return _gdal.Band_GetBlockSize(self, *args)

    def GetActualBlockSize(self, *args):
        r"""
        GetActualBlockSize(self, nXBlockOff, nYBlockOff)


        Fetch the actual block size for a given block offset.
        See :cpp:func:`GDALRasterBand::GetActualBlockSize`.

        Parameters
        ----------
        nXBlockOff : int
            the horizontal block offset for which to calculate the
            number of valid pixels, with zero indicating the left most block, 1 the next
            block and so forth.
        nYBlockOff : int
            the vertical block offset, with zero indicating
            the top most block, 1 the next block and so forth.

        Returns
        -------
        tuple
            tuple with the x and y dimensions of the block

        """
        return _gdal.Band_GetActualBlockSize(self, *args)

    def GetColorInterpretation(self, *args):
        r"""
        GetColorInterpretation(self) -> GDALColorInterp


        Get the :cpp:enum:`GDALColorInterp` value for this band.
        See :cpp:func:`GDALRasterBand::GetColorInterpretation`.

        Returns
        -------
        int

        """
        return _gdal.Band_GetColorInterpretation(self, *args)

    def GetRasterColorInterpretation(self, *args):
        r"""
        GetRasterColorInterpretation(self) -> GDALColorInterp


        Return the color interpretation code for this band.
        See :cpp:func:`GDALRasterBand::GetColorInterpretation`.

        Returns
        -------
        int
            The color interpretation code (default :py:const:`gdal.GCI_Undefined`)


        """
        return _gdal.Band_GetRasterColorInterpretation(self, *args)

    def SetColorInterpretation(self, *args):
        r"""
        SetColorInterpretation(self, val) -> CPLErr


        Set color interpretation of the band
        See :cpp:func:`GDALRasterBand::SetColorInterpretation`.

        Parameters
        ----------
        val : int
            A color interpretation code such as :py:const:`gdal.GCI_RedBand`

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        """
        return _gdal.Band_SetColorInterpretation(self, *args)

    def SetRasterColorInterpretation(self, *args):
        r"""
        SetRasterColorInterpretation(self, val) -> CPLErr

        Deprecated.  Alternate name for :py:meth:`SetColorInterpretation`.

        """
        return _gdal.Band_SetRasterColorInterpretation(self, *args)

    def GetNoDataValue(self):
        """GetNoDataValue(Band self) -> value

        Fetch the nodata value for this band.
        Unlike :cpp:func:`GDALRasterBand::GetNoDataValue`, this
        method handles 64-bit integer data types.

        Returns
        -------
        float or int
            The nodata value, or ``None`` if it has not been set.
        """

        if self.DataType == gdalconst.GDT_Int64:
            return _gdal.Band_GetNoDataValueAsInt64(self)

        if self.DataType == gdalconst.GDT_UInt64:
            return _gdal.Band_GetNoDataValueAsUInt64(self)

        return _gdal.Band_GetNoDataValue(self)



    def GetNoDataValueAsInt64(self, *args):
        r"""
        GetNoDataValueAsInt64(self)


        Fetch the nodata value for this band.
        See :cpp:func:`GDALRasterBand::GetNoDataValueAsInt64`.

        Returns
        -------
        int
            The nodata value, or ``None`` if it has not been set or
            the data type of this band is not :py:const:`gdal.GDT_Int64`.


        """
        return _gdal.Band_GetNoDataValueAsInt64(self, *args)

    def GetNoDataValueAsUInt64(self, *args):
        r"""
        GetNoDataValueAsUInt64(self)


        Fetch the nodata value for this band.
        See :cpp:func:`GDALRasterBand::GetNoDataValueAsUInt64`.

        Returns
        -------
        int
            The nodata value, or ``None`` if it has not been set or
            the data type of this band is not :py:const:`gdal.GDT_UInt64`.


        """
        return _gdal.Band_GetNoDataValueAsUInt64(self, *args)

    def SetNoDataValue(self, value):
        """SetNoDataValue(Band self, value)

        Set the nodata value for this band.
        Unlike :cpp:func:`GDALRasterBand::SetNoDataValue`, this
        method handles 64-bit integer types.

        Parameters
        ----------
        value : float or int
            The nodata value to set

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        """

        if self.DataType == gdalconst.GDT_Int64:
            return _gdal.Band_SetNoDataValueAsInt64(self, value)

        if self.DataType == gdalconst.GDT_UInt64:
            return _gdal.Band_SetNoDataValueAsUInt64(self, value)

        return _gdal.Band_SetNoDataValue(self, value)



    def SetNoDataValueAsInt64(self, *args):
        r"""SetNoDataValueAsInt64(self, v) -> CPLErr"""
        return _gdal.Band_SetNoDataValueAsInt64(self, *args)

    def SetNoDataValueAsUInt64(self, *args):
        r"""SetNoDataValueAsUInt64(self, v) -> CPLErr"""
        return _gdal.Band_SetNoDataValueAsUInt64(self, *args)

    def DeleteNoDataValue(self, *args):
        r"""
        DeleteNoDataValue(self) -> CPLErr


        Remove the nodata value for this band.

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.


        """
        return _gdal.Band_DeleteNoDataValue(self, *args)

    def GetUnitType(self, *args):
        r"""
        GetUnitType(self) -> char const *


        Return a name for the units of this raster's values.
        See :cpp:func:`GDALRasterBand::GetUnitType`.

        Returns
        -------
        str

        Examples
        --------
        >>> ds = gdal.GetDriverByName('MEM').Create('', 10, 10)
        >>> ds.GetRasterBand(1).SetUnitType('ft')
        0
        >>> ds.GetRasterBand(1).GetUnitType()
        'ft'

        """
        return _gdal.Band_GetUnitType(self, *args)

    def SetUnitType(self, *args):
        r"""
        SetUnitType(self, val) -> CPLErr


        Set unit type.
        See :cpp:func:`GDALRasterBand::SetUnitType`.

        Parameters
        ----------
        val : str

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        """
        return _gdal.Band_SetUnitType(self, *args)

    def GetRasterCategoryNames(self, *args):
        r"""
        GetRasterCategoryNames(self) -> char **


        Fetch the list of category names for this band.
        See :cpp:func:`GDALRasterBand::GetCategoryNames`.

        Returns
        -------
        list
            The list of names, or ``None`` if no names exist.


        """
        return _gdal.Band_GetRasterCategoryNames(self, *args)

    def SetRasterCategoryNames(self, *args):
        r"""
        SetRasterCategoryNames(self, names) -> CPLErr

        Deprecated.  Alternate name for :py:meth:`SetCategoryNames`.

        """
        return _gdal.Band_SetRasterCategoryNames(self, *args)

    def GetMinimum(self, *args):
        r"""
        GetMinimum(self)


        Fetch a previously stored maximum value for this band.
        See :cpp:func:`GDALRasterBand::GetMinimum`.

        Returns
        -------
        float
            The stored minimum value, or ``None`` if no value
            has been stored.


        """
        return _gdal.Band_GetMinimum(self, *args)

    def GetMaximum(self, *args):
        r"""
        GetMaximum(self)


        Fetch a previously stored maximum value for this band.
        See :cpp:func:`GDALRasterBand::GetMaximum`.

        Returns
        -------
        float
            The stored maximum value, or ``None`` if no value
            has been stored.


        """
        return _gdal.Band_GetMaximum(self, *args)

    def GetOffset(self, *args):
        r"""
        GetOffset(self)


        Fetch the raster value offset.
        See :cpp:func:`GDALRasterBand::GetOffset`.

        Returns
        -------
        double
            The offset value, or ``0.0``.


        """
        return _gdal.Band_GetOffset(self, *args)

    def GetScale(self, *args):
        r"""
        GetScale(self)


        Fetch the band scale value.
        See :cpp:func:`GDALRasterBand::GetScale`.

        Returns
        -------
        double
            The scale value, or ``1.0``.

        """
        return _gdal.Band_GetScale(self, *args)

    def SetOffset(self, *args):
        r"""
        SetOffset(self, val) -> CPLErr


        Set scaling offset.
        See :cpp:func:`GDALRasterBand::SetOffset`.

        Parameters
        ----------
        val : float

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        See Also
        --------
        :py:meth:`SetScale`

        """
        return _gdal.Band_SetOffset(self, *args)

    def SetScale(self, *args):
        r"""
        SetScale(self, val) -> CPLErr

        Set scaling ratio.
        See :cpp:func:`GDALRasterBand::SetScale`.

        Parameters
        ----------
        val : float

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        See Also
        --------
        :py:meth:`SetOffset`

        """
        return _gdal.Band_SetScale(self, *args)

    def GetStatistics(self, *args):
        r"""
        GetStatistics(self, approx_ok, force) -> CPLErr


        Return the minimum, maximum, mean, and standard deviation of all pixel values
        in this band.
        See :cpp:func:`GDALRasterBand::GetStatistics`

        Parameters
        ----------
        approx_ok : bool
            If ``True``, allow overviews or a subset of image tiles to be used in
            computing the statistics.
        force : bool
            If ``False``, only return a result if it can be obtained without scanning
            the image, i.e. from pre-existing metadata.

        Returns
        -------
        list
           a list with the min, max, mean, and standard deviation of values
           in the Band.

        See Also
        --------
        :py:meth:`ComputeBandStats`
        :py:meth:`ComputeRasterMinMax`
        :py:meth:`GetMaximum`
        :py:meth:`GetMinimum`
        :py:meth:`GetStatistics`

        """
        return _gdal.Band_GetStatistics(self, *args)

    def ComputeStatistics(self, *args, **kwargs):
        """ComputeStatistics(Band self, bool approx_ok, callback=None, callback_data=None)

        Compute image statistics.
        See :cpp:func:`GDALRasterBand::ComputeStatistics`.

        Parameters
        ----------
        approx_ok : bool
                     If ``True``, compute statistics based on overviews or a
                     subset of tiles.
        callback : callable, optional
                     A progress callback function
        callback_data : any, optional
                     Optional data to be passed to callback function

        Returns
        -------
        list
           a list with the min, max, mean, and standard deviation of values
           in the Band.

        See Also
        --------
        :py:meth:`ComputeBandStats`
        :py:meth:`ComputeRasterMinMax`
        :py:meth:`GetMaximum`
        :py:meth:`GetMinimum`
        :py:meth:`GetStatistics`
        :py:meth:`SetStatistics`
        """

        if len(args) == 1:
            kwargs["approx_ok"] = args[0]
            args = ()

        if "approx_ok" in kwargs:
    # Compatibility with older signature that used int for approx_ok
            if kwargs["approx_ok"] == 0:
                kwargs["approx_ok"] = False
            elif kwargs["approx_ok"] == 1:
                kwargs["approx_ok"] = True
            elif isinstance(kwargs["approx_ok"], int):
                raise Exception("approx_ok value should be 0/1/False/True")

        return _gdal.Band_ComputeStatistics(self, *args, **kwargs)



    def SetStatistics(self, *args):
        r"""
        SetStatistics(self, min, max, mean, stddev) -> CPLErr


        Set statistics on band.
        See :cpp:func:`GDALRasterBand::SetStatistics`.

        Parameters
        ----------
        min : float
        max : float
        mean : float
        stdev : float

        Returns
        -------
        int
           :py:const:`CE_None` on apparent success or :py:const:`CE_Failure` on
           failure.  This method cannot detect whether metadata will be properly saved and
           so may return :py:const:`gdal.`CE_None` even if the statistics will never be
           saved.

        See Also
        --------
        :py:meth:`ComputeBandStats`
        :py:meth:`ComputeRasterMinMax`
        :py:meth:`ComputeStatistics`
        :py:meth:`GetMaximum`
        :py:meth:`GetMinimum`
        :py:meth:`GetStatistics`

        """
        return _gdal.Band_SetStatistics(self, *args)

    def GetOverviewCount(self, *args):
        r"""
        GetOverviewCount(self) -> int


        Return the number of overview layers available.
        See :cpp:func:`GDALRasterBand::GetOverviewCount`.

        Returns
        -------
        int


        """
        return _gdal.Band_GetOverviewCount(self, *args)

    def GetOverview(self, *args):
        r"""
        GetOverview(self, i) -> Band


        Fetch a raster overview.
        See :cpp:func:`GDALRasterBand::GetOverview`.

        Parameters
        ----------
        i : int
            Overview index between 0 and ``GetOverviewCount() - 1``.

        Returns
        -------
        Band


        """
        val = _gdal.Band_GetOverview(self, *args)

        if hasattr(self, '_parent_ds') and self._parent_ds():
            self._parent_ds()._add_child_ref(val)


        return val


    def GetSampleOverview(self, *args):
        r"""GetSampleOverview(self, nDesiredSamples) -> Band"""
        return _gdal.Band_GetSampleOverview(self, *args)

    def Checksum(self, *args, **kwargs):
        r"""
        Checksum(self, xoff=0, yoff=0, xsize=None, ysize=None) -> int


        Computes a checksum from a region of a RasterBand.
        See :cpp:func:`GDALChecksumImage`.

        Parameters
        ----------
        xoff : int, default=0
           The pixel offset to left side of the region of the band to
           be read. This would be zero to start from the left side.
        yoff : int, default=0
           The line offset to top side of the region of the band to
           be read. This would be zero to start from the top side.
        xsize : int, optional
             The number of pixels to read in the x direction. By default,
             equal to the number of columns in the raster.
        ysize : int, optional
             The number of rows to read in the y direction. By default,
             equal to the number of bands in the raster.

        Returns
        -------
        int
            checksum value, or -1 in case of error


        """
        return _gdal.Band_Checksum(self, *args, **kwargs)

    def ComputeRasterMinMax(self, *args, **kwargs):
        """ComputeRasterMinMax(Band self, bool approx_ok=False, bool can_return_none=False) -> (min, max) or None

        Computes the minimum and maximum values for this Band.
        See :cpp:func:`GDALComputeRasterMinMax`.

        Parameters
        ----------
        approx_ok : bool, default=False
            If ``False``, read all pixels in the band. If ``True``, check
            :py:meth:`GetMinimum`/:py:meth:`GetMaximum` or read a subsample.
        can_return_none : bool, default=False
            If ``True``, return ``None`` on error. Otherwise, return a tuple
            with NaN values.

        Returns
        -------
        tuple

        See Also
        --------
        :py:meth:`ComputeBandStats`
        :py:meth:`ComputeStatistics`
        :py:meth:`GetMaximum`
        :py:meth:`GetMinimum`
        :py:meth:`GetStatistics`
        :py:meth:`SetStatistics`
        """

        if len(args) == 1:
            kwargs["approx_ok"] = args[0]
            args = ()

        if "approx_ok" in kwargs:
    # Compatibility with older signature that used int for approx_ok
            if kwargs["approx_ok"] == 0:
                kwargs["approx_ok"] = False
            elif kwargs["approx_ok"] == 1:
                kwargs["approx_ok"] = True
            elif isinstance(kwargs["approx_ok"], int):
                raise Exception("approx_ok value should be 0/1/False/True")

    # can_return_null is used in other methods
        if "can_return_null" in kwargs:
            kwargs["can_return_none"] = kwargs["can_return_null"];
            del kwargs["can_return_null"]

        if "can_return_none" in kwargs and kwargs["can_return_none"]:
            try:
                return _gdal.Band_ComputeRasterMinMax(self, *args, **kwargs)
            except Exception:
                return None
        else:
            return _gdal.Band_ComputeRasterMinMax(self, *args, **kwargs)



    def ComputeBandStats(self, *args):
        r"""
        ComputeBandStats(self, samplestep=1)


        Computes the mean and standard deviation of values in this Band.
        See :cpp:func:`GDALComputeBandStats`.

        Parameters
        ----------
        samplestep : int, default=1
            Step between scanlines used to compute statistics.

        Returns
        -------
        tuple
            tuple of length 2 with value of mean and standard deviation

        See Also
        --------
        :py:meth:`ComputeRasterMinMax`
        :py:meth:`ComputeStatistics`
        :py:meth:`GetMaximum`
        :py:meth:`GetMinimum`
        :py:meth:`GetStatistics`
        :py:meth:`SetStatistics`

        """
        return _gdal.Band_ComputeBandStats(self, *args)

    def Fill(self, *args):
        r"""
        Fill(self, real_fill, imag_fill=0.0) -> CPLErr


        Fill this band with a constant value.
        See :cpp:func:`GDALRasterBand::Fill`.

        Parameters
        ----------
        real_fill : float
            real component of the fill value
        imag_fill : float, default = 0.0
            imaginary component of the fill value

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.


        """
        return _gdal.Band_Fill(self, *args)

    def WriteRaster(self, *args, **kwargs):
        r"""WriteRaster(self, xoff, yoff, xsize, ysize, buf_len, buf_xsize=None, buf_ysize=None, buf_type=None, buf_pixel_space=None, buf_line_space=None) -> CPLErr"""
        return _gdal.Band_WriteRaster(self, *args, **kwargs)

    def FlushCache(self, *args):
        r"""
        FlushCache(self)


        Flush raster data cache.
        See :cpp:func:`GDALRasterBand::FlushCache`.

        """
        return _gdal.Band_FlushCache(self, *args)

    def GetRasterColorTable(self, *args):
        r"""
        GetRasterColorTable(self) -> ColorTable


        Fetch the color table associated with this band.
        See :cpp:func:`GDALRasterBand::GetColorTable`.

        Returns
        -------
        ColorTable
            The :py:class:`ColorTable`, or ``None`` if it has not been defined.

        """
        return _gdal.Band_GetRasterColorTable(self, *args)

    def GetColorTable(self, *args):
        r"""
        GetColorTable(self) -> ColorTable


        Get the color table associated with this band.
        See :cpp:func:`GDALRasterBand::GetColorTable`.

        Returns
        -------
        ColorTable or ``None``

        """
        return _gdal.Band_GetColorTable(self, *args)

    def SetRasterColorTable(self, *args):
        r"""
        SetRasterColorTable(self, arg) -> int

        Deprecated. Alternate name for :py:meth:`SetColorTable`.

        """
        return _gdal.Band_SetRasterColorTable(self, *args)

    def SetColorTable(self, *args):
        r"""
        SetColorTable(self, arg) -> int


        Set the raster color table.
        See :cpp:func:`GDALRasterBand::SetColorTable`.

        Parameters
        ----------
        arg : ColorTable

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        """
        return _gdal.Band_SetColorTable(self, *args)

    def GetDefaultRAT(self, *args):
        r"""GetDefaultRAT(self) -> RasterAttributeTable"""
        return _gdal.Band_GetDefaultRAT(self, *args)

    def SetDefaultRAT(self, *args):
        r"""SetDefaultRAT(self, table) -> int"""
        return _gdal.Band_SetDefaultRAT(self, *args)

    def GetMaskBand(self, *args):
        r"""
        GetMaskBand(self) -> Band


        Return the mask band associated with this band.
        See :cpp:func:`GDALRasterBand::GetMaskBand`.

        Returns
        -------
        Band


        """
        val = _gdal.Band_GetMaskBand(self, *args)

        if hasattr(self, '_parent_ds') and self._parent_ds():
            self._parent_ds()._add_child_ref(val)


        return val


    def GetMaskFlags(self, *args):
        r"""
        GetMaskFlags(self) -> int


        Return the status flags of the mask band.
        See :cpp:func:`GDALRasterBand::GetMaskFlags`.

        Returns
        -------
        int

        Examples
        --------
        >>> import numpy as np
        >>> ds = gdal.GetDriverByName('MEM').Create('', 10, 10)
        >>> band = ds.GetRasterBand(1)
        >>> band.GetMaskFlags() == gdal.GMF_ALL_VALID
        True
        >>> band.SetNoDataValue(22)
        0
        >>> band.WriteArray(np.array([[22]]))
        0
        >>> band.GetMaskBand().ReadAsArray(win_xsize=2,win_ysize=2)
        array([[  0, 255],
               [255, 255]], dtype=uint8)
        >>> band.GetMaskFlags() == gdal.GMF_NODATA
        True


        """
        return _gdal.Band_GetMaskFlags(self, *args)

    def CreateMaskBand(self, *args):
        r"""
        CreateMaskBand(self, nFlags) -> CPLErr


        Add a mask band to the current band.
        See :cpp:func:`GDALRasterBand::CreateMaskBand`.

        Parameters
        ----------
        nFlags : int

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.


        """
        return _gdal.Band_CreateMaskBand(self, *args)

    def IsMaskBand(self, *args):
        r"""
        IsMaskBand(self) -> bool


        Returns whether the band is a mask band.
        See :cpp:func:`GDALRasterBand::IsMaskBand`.

        Returns
        -------
        bool

        """
        return _gdal.Band_IsMaskBand(self, *args)

    def GetHistogram(self, *args, **kwargs):
        r"""
        GetHistogram(self, min=-0.5, max=255.5, buckets=256, include_out_of_range=0, approx_ok=1, callback=0, callback_data=None) -> CPLErr


        Compute raster histogram.
        See :cpp:func:`GDALRasterBand::GetHistogram`.

        Parameters
        ----------
        min : float, default=-0.05
            the lower bound of the histogram
        max : float, default=255.5
            the upper bound of the histogram
        buckets : int, default=256
            the number of buckets int he histogram
        include_out_of_range : bool, default=False
            if ``True``, add out-of-range values into the first and last buckets
        approx_ok : bool, default=True
            if ``True``, compute an approximate histogram by using subsampling or overviews
        callback : callable, optional
                     A progress callback function
        callback_data : any, optional
                     Optional data to be passed to callback function

        Returns
        -------
        list
            list with length equal to ``buckets``. If ``approx_ok`` is ``False``, each
            the value of each list item will equal the number of pixels in that bucket.

        Examples
        --------
        >>> np.random.seed(123)
        >>> ds = gdal.GetDriverByName('MEM').Create('', 10, 10, eType=gdal.GDT_Float32)
        >>> ds.WriteArray(np.random.normal(size=100).reshape(10, 10))
        0
        >>> ds.GetRasterBand(1).GetHistogram(min=-3.5, max=3.5, buckets=13, approx_ok=False)
        [0, 2, 1, 6, 17, 18, 13, 14, 16, 8, 5, 0, 0]

        """
        return _gdal.Band_GetHistogram(self, *args, **kwargs)

    def GetDefaultHistogram(self, *args, **kwargs):
        r"""
        GetDefaultHistogram(self, min_ret=None, max_ret=None, buckets_ret=None, ppanHistogram=None, force=1, callback=0, callback_data=None) -> CPLErr


        Fetch the default histogram for this band.
        See :cpp:func:`GDALRasterBand::GetDefaultHistogram`.

        Returns
        -------
        list
            List with the following four elements:
            - lower bound of histogram
            - upper bound of histogram
            - number of buckets in histogram
            - tuple with counts for each bucket

        """
        return _gdal.Band_GetDefaultHistogram(self, *args, **kwargs)

    def SetDefaultHistogram(self, *args):
        r"""
        SetDefaultHistogram(self, min, max, buckets_in) -> CPLErr


        Set default histogram.
        See :cpp:func:`GDALRasterBand::SetDefaultHistogram`.

        Parameters
        ----------
        min : float
            minimum value
        max : float
            maximum value
        buckets_in : list
            list of pixel counts for each bucket

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        See Also
        --------
        :py:meth:`SetHistogram`

        """
        return _gdal.Band_SetDefaultHistogram(self, *args)

    def HasArbitraryOverviews(self, *args):
        r"""
        HasArbitraryOverviews(self) -> bool


        Check for arbitrary overviews.
        See :cpp:func:`GDALRasterBand::HasArbitraryOverviews`.

        Returns
        -------
        bool

        """
        return _gdal.Band_HasArbitraryOverviews(self, *args)

    def GetCategoryNames(self, *args):
        r"""
        GetCategoryNames(self) -> char **


        Fetch the list of category names for this raster.
        See :cpp:func:`GDALRasterBand::GetCategoryNames`.

        Returns
        -------
        list
            A list of category names, or ``None``

        """
        return _gdal.Band_GetCategoryNames(self, *args)

    def SetCategoryNames(self, *args):
        r"""
        SetCategoryNames(self, papszCategoryNames) -> CPLErr


        Set the category names for this band.
        See :cpp:func:`GDALRasterBand::SetCategoryNames`.

        Parameters
        ----------
        papszCategoryNames : list

        Returns
        -------
        int
           :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

        """
        return _gdal.Band_SetCategoryNames(self, *args)

    def GetVirtualMem(self, *args, **kwargs):
        r"""GetVirtualMem(self, eRWFlag, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eBufType, nCacheSize, nPageSizeHint, options=None) -> VirtualMem"""
        return _gdal.Band_GetVirtualMem(self, *args, **kwargs)

    def GetVirtualMemAuto(self, *args, **kwargs):
        r"""GetVirtualMemAuto(self, eRWFlag, options=None) -> VirtualMem"""
        return _gdal.Band_GetVirtualMemAuto(self, *args, **kwargs)

    def GetTiledVirtualMem(self, *args, **kwargs):
        r"""GetTiledVirtualMem(self, eRWFlag, nXOff, nYOff, nXSize, nYSize, nTileXSize, nTileYSize, eBufType, nCacheSize, options=None) -> VirtualMem"""
        return _gdal.Band_GetTiledVirtualMem(self, *args, **kwargs)

    def GetDataCoverageStatus(self, *args):
        r"""
        GetDataCoverageStatus(self, nXOff, nYOff, nXSize, nYSize, nMaskFlagStop=0) -> int


        Determine whether a sub-window of the Band contains only data, only empty blocks, or a mix of both.
        See :cpp:func:`GDALRasterBand::GetDataCoverageStatus`.

        Parameters
        ----------
        nXOff : int
        nYOff : int
        nXSize : int
        nYSize : int
        nMaskFlagStop : int, default=0

        Returns
        -------
        list
            First value represents a bitwise-or value of the following constants
            - :py:const:`gdalconst.GDAL_DATA_COVERAGE_STATUS_DATA`
            - :py:const:`gdalconst.GDAL_DATA_COVERAGE_STATUS_EMPTY`
            - :py:const:`gdalconst.GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED`
            Second value represents the approximate percentage in [0, 100] of pixels in the window that have valid values

        Examples
        --------
        >>> import numpy as np
        >>> # Create a raster with four blocks
        >>> ds = gdal.GetDriverByName('GTiff').Create('test.tif', 64, 64, options = {'SPARSE_OK':True, 'TILED':True, 'BLOCKXSIZE':32, 'BLOCKYSIZE':32})
        >>> band = ds.GetRasterBand(1)
        >>> # Write some data to upper-left block
        >>> band.WriteArray(np.array([[1, 2], [3, 4]]))
        0
        >>> # Check status of upper-left block
        >>> flags, pct = band.GetDataCoverageStatus(0, 0, 32, 32)
        >>> flags == gdal.GDAL_DATA_COVERAGE_STATUS_DATA
        True
        >>> pct
        100.0
        >>> # Check status of upper-right block
        >>> flags, pct = band.GetDataCoverageStatus(32, 0, 32, 32)
        >>> flags == gdal.GDAL_DATA_COVERAGE_STATUS_EMPTY
        True
        >>> pct
        0.0
        >>> # Check status of window touching all four blocks
        >>> flags, pct = band.GetDataCoverageStatus(16, 16, 32, 32)
        >>> flags == gdal.GDAL_DATA_COVERAGE_STATUS_DATA | gdal.GDAL_DATA_COVERAGE_STATUS_EMPTY
        True
        >>> pct
        25.0

        """
        return _gdal.Band_GetDataCoverageStatus(self, *args)

    def AdviseRead(self, *args, **kwargs):
        r"""AdviseRead(self, xoff, yoff, xsize, ysize, buf_xsize=None, buf_ysize=None, buf_type=None, options=None) -> CPLErr"""
        return _gdal.Band_AdviseRead(self, *args, **kwargs)

    def InterpolateAtPoint(self, *args, **kwargs):
        """Return the interpolated value at pixel and line raster coordinates.
           See :cpp:func:`GDALRasterBand::InterpolateAtPoint`.

           Parameters
           ----------
           pixel : float
           line : float
           interpolation : int
               Resampling algorithm to use. One of:

               - :py:const:`GRIORA_NearestNeighbour`
               - :py:const:`GRIORA_Bilinear`
               - :py:const:`GRIORA_Cubic`
               - :py:const:`GRIORA_CubicSpline`

           Returns
           -------
           float
               Interpolated value, or ``None`` if it has any error.
        """

        ret = _gdal.Band_InterpolateAtPoint(self, *args, **kwargs)
        if ret[0] != CE_None:
            return None

        from . import gdal
        if gdal.DataTypeIsComplex(self.DataType):
            return complex(ret[1], ret[2])
        else:
            return ret[1]



    def InterpolateAtGeolocation(self, *args, **kwargs):
        """Return the interpolated value at georeferenced coordinates.
           See :cpp:func:`GDALRasterBand::InterpolateAtGeolocation`.

           When srs is None, those georeferenced coordinates (geolocX, geolocY)
           must be in the "natural" SRS of the dataset, that is the one returned by
           GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
           GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
           array (generally WGS 84) if there is a geolocation array.
           If that natural SRS is a geographic one, geolocX must be a longitude, and
           geolocY a latitude. If that natural SRS is a projected one, geolocX must
           be a easting, and geolocY a northing.

           When srs is set to a non-None value, (geolocX, geolocY) must be
           expressed in that CRS, and that tuple must be conformant with the
           data-axis-to-crs-axis setting of srs, that is the one returned by
           the :py:func:`osgeo.osr.SpatialReference.GetDataAxisToSRSAxisMapping`.
           If you want to be sure of the axis order, then make sure to call
           ``srs.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)``
           before calling this method, and in that case, geolocX must be a longitude
           or an easting value, and geolocX a latitude or a northing value.

           Parameters
           ----------
           geolocX : float
               X coordinate of the position where interpolation should be done.
               Longitude or easting in "natural" CRS if `srs` is None,
               otherwise consistent with first axis of `srs`,
               taking into account the data-axis-to-crs-axis mapping
           geolocY : float
               Y coordinate of the position where interpolation should be done.
               Latitude or northing in "natural" CRS if `srs` is None,
               otherwise consistent with second axis of `srs`,
               taking into account the data-axis-to-crs-axis mapping
           srs : object
               :py:class:`osr.SpatialReference`. If set, override the natural CRS in which geolocX, geolocY are expressed
           interpolation : int
               Resampling algorithm to use. One of:

               - :py:const:`GRIORA_NearestNeighbour`
               - :py:const:`GRIORA_Bilinear`
               - :py:const:`GRIORA_Cubic`
               - :py:const:`GRIORA_CubicSpline`

           Returns
           -------
           float
               Interpolated value, or ``None`` if it has any error.

           Examples
           --------

           >>> longitude_degree = -117.64
           >>> latitude_degree = 33.90
           >>> with gdal.Open("byte.tif") as ds:
           ...    wgs84_srs = osr.SpatialReference("WGS84")
           ...    wgs84_srs.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
           ...    ds.GetRasterBand(1).InterpolateAtGeolocation(longitude_degree, latitude_degree, wgs84_srs, gdal.GRIORA_Bilinear)
           135.62  # interpolated value, rtol: 1e-3
        """

        ret = _gdal.Band_InterpolateAtGeolocation(self, *args, **kwargs)
        if ret[0] != CE_None:
            return None

        from . import gdal
        if gdal.DataTypeIsComplex(self.DataType):
            return complex(ret[1], ret[2])
        else:
            return ret[1]



    def ComputeMinMaxLocation(self, *args, **kwargs):
        """Compute the min/max values for a band, and their location.

           Pixels whose value matches the nodata value or are masked by the mask
           band are ignored.

           If the minimum or maximum value is hit in several locations, it is not
           specified which one will be returned.

           This is a mapping of :cpp:func:`GDALRasterBand::ComputeRasterMinMaxLocation`.

           Parameters
           ----------
           None

           Returns
           -------
           tuple or None
               a named tuple (min, max, minX, minY, maxX, maxY) or ``None``
               in case of error or no valid pixel.
        """

        ret = _gdal.Band_ComputeMinMaxLocation(self, *args, **kwargs)
        if ret[0] != CE_None:
            return None

        import collections
        tuple = collections.namedtuple('ComputeMinMaxLocationResult',
                ['min',
                 'max',
                 'minX',
                 'minY',
                 'maxX',
                 'maxY',
                 ])
        tuple.min = ret[1]
        tuple.max = ret[2]
        tuple.minX = ret[3]
        tuple.minY = ret[4]
        tuple.maxX = ret[5]
        tuple.maxY = ret[6]
        return tuple



    def AsMDArray(self, *args):
        r"""AsMDArray(self) -> MDArray"""
        return _gdal.Band_AsMDArray(self, *args)

    def _EnablePixelTypeSignedByteWarning(self, *args):
        r"""_EnablePixelTypeSignedByteWarning(self, b)"""
        return _gdal.Band__EnablePixelTypeSignedByteWarning(self, *args)

    def UnaryOp(self, *args):
        r"""UnaryOp(self, op) -> ComputedBand"""
        return _gdal.Band_UnaryOp(self, *args)

    def BinaryOpBand(self, *args):
        r"""BinaryOpBand(self, op, other) -> ComputedBand"""
        return _gdal.Band_BinaryOpBand(self, *args)

    def BinaryOpDouble(self, *args):
        r"""BinaryOpDouble(self, op, constant) -> ComputedBand"""
        return _gdal.Band_BinaryOpDouble(self, *args)

    @staticmethod
    def BinaryOpDoubleToBand(*args):
        r"""BinaryOpDoubleToBand(constant, op, band) -> ComputedBand"""
        return _gdal.Band_BinaryOpDoubleToBand(*args)

    @staticmethod
    def IfThenElse(*args):
        r"""IfThenElse(condBand, thenBand, elseBand) -> ComputedBand"""
        return _gdal.Band_IfThenElse(*args)

    def AsType(self, *args):
        r"""AsType(self, dt) -> ComputedBand"""
        return _gdal.Band_AsType(self, *args)

    @staticmethod
    def MaximumOfNBands(*args):
        r"""MaximumOfNBands(band_count) -> ComputedBand"""
        return _gdal.Band_MaximumOfNBands(*args)

    def MaxConstant(self, *args):
        r"""MaxConstant(self, constant) -> ComputedBand"""
        return _gdal.Band_MaxConstant(self, *args)

    @staticmethod
    def MinimumOfNBands(*args):
        r"""MinimumOfNBands(band_count) -> ComputedBand"""
        return _gdal.Band_MinimumOfNBands(*args)

    def MinConstant(self, *args):
        r"""MinConstant(self, constant) -> ComputedBand"""
        return _gdal.Band_MinConstant(self, *args)

    @staticmethod
    def MeanOfNBands(*args):
        r"""MeanOfNBands(band_count) -> ComputedBand"""
        return _gdal.Band_MeanOfNBands(*args)

    def ReadRaster1(self, *args, **kwargs):
        r"""ReadRaster1(self, xoff, yoff, xsize, ysize, buf_xsize=None, buf_ysize=None, buf_type=None, buf_pixel_space=None, buf_line_space=None, resample_alg=GRIORA_NearestNeighbour, operate_in_buf_type=TRUE, callback=0, callback_data=None, inputOutputBuf=None) -> CPLErr"""
        return _gdal.Band_ReadRaster1(self, *args, **kwargs)

    def ReadBlock(self, *args, **kwargs):
        r"""ReadBlock(self, xoff, yoff, buf_obj=None) -> CPLErr"""
        return _gdal.Band_ReadBlock(self, *args, **kwargs)


    def _add_parent_references(self, parents):
        if not hasattr(self, '_parent_references'):
            self._parent_references = set()
        for parent in parents:
            if hasattr(parent, '_parent_references'):
                for parent_of_parent in parent._parent_references:
                    if parent_of_parent not in self._parent_references:
                        parent_of_parent._add_child_ref(self)
                        self._parent_references.add(parent_of_parent)
            elif hasattr(parent, "_parent_ds"):
                parent_ds = parent._parent_ds()
                if parent_ds and parent_ds not in self._parent_references:
                    parent_ds._add_child_ref(self)
                    self._parent_references.add(parent_ds)
        return self

    @staticmethod
    def _get_as_band_if_possible(o):
          if hasattr(o, "shape"):
              from osgeo import gdal_array
              ds = gdal_array.OpenArray(o)
              if ds.RasterCount != 1:
                  raise ValueError("numpy array must hold a single band")
              band = ds.GetRasterBand(1)
              band._hard_ref_to_parent = ds
              return band
          else:
              return o

    def __key(self):
        return str(self)

    def __hash__(self):
        return hash(self.__key())

    def __add__(self, other):
        """Add this raster band to a raster band, a numpy array or a constant

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_ADD, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_ADD, other)._add_parent_references([self])

    def __radd__(self, constant):
        """Add a constant to this raster band

           The resulting band is lazily evaluated.
        """
        return _gdal.Band_BinaryOpDoubleToBand(constant, GRABO_ADD, self)._add_parent_references([self])

    def __sub__(self, other):
        """Subtract this raster band with a raster band, a numpy array or constant

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_SUB, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_SUB, other)._add_parent_references([self])

    def __rsub__(self, constant):
        """Subtract a constant with a raster band

           The resulting band is lazily evaluated.
        """
        return _gdal.Band_BinaryOpDoubleToBand(constant, GRABO_SUB, self)._add_parent_references([self])

    def __mul__(self, other):
        """Multiply this raster band with a raster band, a numpy array or a constant

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_MUL, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_MUL, other)._add_parent_references([self])

    def __rmul__(self, constant):
        """Multiply a constant with this raster band

           The resulting band is lazily evaluated.
        """
        return _gdal.Band_BinaryOpDoubleToBand(constant, GRABO_MUL, self)._add_parent_references([self])

    def __truediv__(self, other):
        """Divide this raster band by a raster band, a numpy array or a constant

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_DIV, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_DIV, other)._add_parent_references([self])

    def __rtruediv__(self, constant):
        """Divide a constant by a raster band

           The resulting band is lazily evaluated.
        """
        return _gdal.Band_BinaryOpDoubleToBand(constant, GRABO_DIV, self)._add_parent_references([self])

    def __gt__(self, other):
        """Return a band whose value is 1 if the pixel value of the left operand
           is greater than the pixel value of the right operand.

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_GT, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_GT, other)._add_parent_references([self])

    def __ge__(self, other):
        """Return a band whose value is 1 if the pixel value of the left operand
           is greater or equal to the pixel value of the right operand.

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_GE, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_GE, other)._add_parent_references([self])

    def __lt__(self, other):
        """Return a band whose value is 1 if the pixel value of the left operand
           is lesser than the pixel value of the right operand.

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_LT, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_LT, other)._add_parent_references([self])

    def __le__(self, other):
        """Return a band whose value is 1 if the pixel value of the left operand
           is lesser or equal to the pixel value of the right operand.

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_LE, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_LE, other)._add_parent_references([self])

    def __eq__(self, other):
        """Return a band whose value is 1 if the pixel value of the left operand
           is equal to the pixel value of the right operand.

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_EQ, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_EQ, other)._add_parent_references([self])

    def __ne__(self, other):
        """Return a band whose value is 1 if the pixel value of the left operand
           is not equal to the pixel value of the right operand.

           The resulting band is lazily evaluated.
        """
        other = Band._get_as_band_if_possible(other)
        if isinstance(other, Band):
            return _gdal.Band_BinaryOpBand(self, GRABO_NE, other)._add_parent_references([self, other])
        else:
            return _gdal.Band_BinaryOpDouble(self, GRABO_NE, other)._add_parent_references([self])

    def astype(self, dt):
        """Cast this band to the specified data type

           The data type can be one of the constant of the GDAL ``GDT_`` enumeration
           or a numpy dtype.

           The resulting band is lazily evaluated.
        """
        if not isinstance(dt, int):
            try:
                from osgeo import gdal_array
                dt = gdal_array.NumericTypeCodeToGDALTypeCode(dt)
            except Exception:
                raise ValueError( "Invalid dt value")

        return _gdal.Band_AsType(self, dt)._add_parent_references([self])

    def ReadRaster(self, xoff=0, yoff=0, xsize=None, ysize=None,
                   buf_xsize=None, buf_ysize=None, buf_type=None,
                   buf_pixel_space=None, buf_line_space=None,
                   resample_alg=gdalconst.GRIORA_NearestNeighbour,
                   operate_in_buf_type=True,
                   callback=None,
                   callback_data=None,
                   buf_obj=None):

        if xsize is None:
            xsize = self.XSize
        if ysize is None:
            ysize = self.YSize

        return _gdal.Band_ReadRaster1(self, xoff, yoff, xsize, ysize,
                                      buf_xsize, buf_ysize, buf_type,
                                      buf_pixel_space, buf_line_space,
                                      resample_alg, operate_in_buf_type,
                                      callback, callback_data,
                                      buf_obj)

    def WriteRaster(self, xoff, yoff, xsize, ysize,
                    buf_string,
                    buf_xsize=None, buf_ysize=None, buf_type=None,
                    buf_pixel_space=None, buf_line_space=None ):
        """
        Write the contents of a buffer to a dataset.

        """

        if buf_xsize is None:
            buf_xsize = xsize
        if buf_ysize is None:
            buf_ysize = ysize

    # Redirect to numpy-friendly WriteArray() if buf_string is a numpy array
    # and other arguments are compatible
        if type(buf_string).__name__ == 'ndarray' and \
           buf_xsize == xsize and buf_ysize == ysize and buf_type is None and \
           buf_pixel_space is None and buf_line_space is None:
            return self.WriteArray(buf_string, xoff=xoff, yoff=yoff)

        if buf_type is None:
            buf_type = self.DataType

        return _gdal.Band_WriteRaster(self,
                 xoff, yoff, xsize, ysize,
                buf_string, buf_xsize, buf_ysize, buf_type,
                buf_pixel_space, buf_line_space )

    def ReadAsMaskedArray(self, xoff=0, yoff=0, win_xsize=None, win_ysize=None,
                    buf_xsize=None, buf_ysize=None, buf_type=None,
                    resample_alg=gdalconst.GRIORA_NearestNeighbour,
                    operate_in_buf_type=True,
                    mask_resample_alg=gdalconst.GRIORA_NearestNeighbour,
                    callback=None,
                    callback_data=None):
        """
        Read a window of this raster band into a NumPy masked array.

        Values of the mask will be ``True`` where pixels are invalid.

        Starting in GDAL 3.11, if resampling (``buf_xsize`` != ``xsize``, or ``buf_ysize`` != ``ysize``) the mask
        band will be resampled using the algorithm specified by ``mask_resample_alg``.

        See :py:meth:`ReadAsArray` for a description of additional arguments.
        """
        import numpy
        array = self.ReadAsArray(xoff=xoff, yoff=yoff,
                                 win_xsize=win_xsize, win_ysize=win_ysize,
                                 buf_xsize=buf_xsize, buf_ysize=buf_ysize,
                                 buf_type=buf_type,
                                 resample_alg=resample_alg,
                                 operate_in_buf_type=operate_in_buf_type,
                                 callback=callback, callback_data=callback_data)

        if self.GetMaskFlags() != GMF_ALL_VALID:
            mask = self.GetMaskBand()
            mask_array = ~mask.ReadAsArray(xoff=xoff,
                                           yoff=yoff,
                                           win_xsize=win_xsize,
                                           win_ysize=win_ysize,
                                           buf_xsize=buf_xsize,
                                           buf_ysize=buf_ysize,
                                           resample_alg=mask_resample_alg).astype(bool)
        else:
            mask_array = None
        return numpy.ma.array(array, mask=mask_array)


    def ReadAsArray(self, xoff=0, yoff=0, win_xsize=None, win_ysize=None,
                    buf_xsize=None, buf_ysize=None, buf_type=None, buf_obj=None,
                    resample_alg=gdalconst.GRIORA_NearestNeighbour,
                    operate_in_buf_type=True,
                    callback=None,
                    callback_data=None):
        """
        Read a window of this raster band into a NumPy array.

        Parameters
        ----------
        xoff : float, default=0
           The pixel offset to left side of the region of the band to
           be read. This would be zero to start from the left side.
        yoff : float, default=0
           The line offset to top side of the region of the band to
           be read. This would be zero to start from the top side.
        win_xsize : float, optional
             The number of pixels to read in the x direction. By default,
             equal to the number of columns in the raster.
        win_ysize : float, optional
             The number of rows to read in the y direction. By default,
             equal to the number of bands in the raster.
        buf_xsize : int, optional
             The number of columns in the returned array. If not equal
             to ``win_xsize``, the returned values will be determined
             by ``resample_alg``.
        buf_ysize : int, optional
             The number of rows in the returned array. If not equal
             to ``win_ysize``, the returned values will be determined
             by ``resample_alg``.
        buf_type : int, optional
             The data type of the returned array
        buf_obj : np.ndarray, optional
             Optional buffer into which values will be read. If ``buf_obj``
             is specified, then ``buf_xsize``/``buf_ysize``/``buf_type``
             should generally not be specified.
        resample_alg : int, default = :py:const:`gdal.GRIORA_NearestNeighbour`.
             Specifies the resampling algorithm to use when the size of
             the read window and the buffer are not equal.
        operate_in_buf_type : bool, default = True
             Whether the data type used for the operations (typically non-nearest-neighbour
             resampling) should be buf_type (operate_in_buf_type=True) or the
             data type of the band (operate_in_buf_type=False)
        callback : callable, optional
            A progress callback function
        callback_data : any, optional
            Optional data to be passed to callback function

        Returns
        -------
        np.ndarray

        Examples
        --------
        >>> import numpy as np
        >>> ds = gdal.GetDriverByName("GTiff").Create("test.tif", 4, 4, eType=gdal.GDT_Float32)
        >>> ds.WriteArray(np.arange(16).reshape(4, 4))
        0
        >>> band = ds.GetRasterBand(1)
        >>> # Reading an entire band
        >>> band.ReadAsArray()
        array([[ 0.,  1.,  2.,  3.],
               [ 4.,  5.,  6.,  7.],
               [ 8.,  9., 10., 11.],
               [12., 13., 14., 15.]], dtype=float32)
        >>> # Reading a window of a band
        >>> band.ReadAsArray(xoff=2, yoff=2, win_xsize=2, win_ysize=2)
        array([[10., 11.],
               [14., 15.]], dtype=float32)
        >>> # Reading a band into a new buffer at higher resolution
        >>> band.ReadAsArray(xoff=0.5, yoff=0.5, win_xsize=2.5, win_ysize=2.5, buf_xsize=5, buf_ysize=5)
        array([[ 0.,  1.,  1.,  2.,  2.],
               [ 4.,  5.,  5.,  6.,  6.],
               [ 4.,  5.,  5.,  6.,  6.],
               [ 8.,  9.,  9., 10., 10.],
               [ 8.,  9.,  9., 10., 10.]], dtype=float32)
        >>> # Reading a band into an existing buffer at lower resolution
        >>> band.ReadAsArray(buf_xsize=2, buf_ysize=2, buf_type=gdal.GDT_Float64, resample_alg=gdal.GRIORA_Average)
        array([[ 2.5,  4.5],
               [10.5, 12.5]])
        >>> buf = np.zeros((2,2))
        >>> band.ReadAsArray(buf_obj=buf)
        array([[ 5.,  7.],
               [13., 15.]])
        """
        from osgeo import gdal_array

        return gdal_array.BandReadAsArray(self, xoff, yoff,
                                           win_xsize, win_ysize,
                                           buf_xsize, buf_ysize, buf_type, buf_obj,
                                           resample_alg=resample_alg,
                                           operate_in_buf_type=operate_in_buf_type,
                                           callback=callback,
                                           callback_data=callback_data)

    def WriteArray(self, array, xoff=0, yoff=0,
                   resample_alg=gdalconst.GRIORA_NearestNeighbour,
                   callback=None,
                   callback_data=None):
        """
        Write the contents of a NumPy array to a Band.

        Parameters
        ----------
        array : np.ndarray
            Two-dimensional array containing values to write
        xoff : int, default=0
           The pixel offset to left side of the region of the band to
           be written. This would be zero to start from the left side.
        yoff : int, default=0
           The line offset to top side of the region of the band to
           be written. This would be zero to start from the top side.
        resample_alg : int, default = :py:const:`gdal.GRIORA_NearestNeighbour`
           Resampling algorithm. Placeholder argument, not currently supported.
        callback : callable, optional
            A progress callback function
        callback_data : any, optional
            Optional data to be passed to callback function

        Returns
        -------
        int
            Error code, or ``gdal.CE_None`` if no error occurred.
        """
        from osgeo import gdal_array

        return gdal_array.BandWriteArray(self, array, xoff, yoff,
                                          resample_alg=resample_alg,
                                          callback=callback,
                                          callback_data=callback_data)

    def GetVirtualMemArray(self, eAccess=gdalconst.GF_Read, xoff=0, yoff=0,
                           xsize=None, ysize=None, bufxsize=None, bufysize=None,
                           datatype=None,
                           cache_size = 10 * 1024 * 1024, page_size_hint = 0,
                           options=None):
          """Return a NumPy array for the band, seen as a virtual memory mapping.
             An element is accessed with array[y][x].
             Any reference to the array must be dropped before the last reference to the
             related dataset is also dropped.
          """
          from osgeo import gdal_array
          if xsize is None:
              xsize = self.XSize
          if ysize is None:
              ysize = self.YSize
          if bufxsize is None:
              bufxsize = self.XSize
          if bufysize is None:
              bufysize = self.YSize
          if datatype is None:
              datatype = self.DataType
          if options is None:
              virtualmem = self.GetVirtualMem(eAccess, xoff, yoff, xsize, ysize, bufxsize, bufysize, datatype, cache_size, page_size_hint)
          else:
              virtualmem = self.GetVirtualMem(eAccess, xoff, yoff, xsize, ysize, bufxsize, bufysize, datatype, cache_size, page_size_hint, options)
          return gdal_array.VirtualMemGetArray(virtualmem)

    def GetVirtualMemAutoArray(self, eAccess=gdalconst.GF_Read, options=None):
          """Return a NumPy array for the band, seen as a virtual memory mapping.
             An element is accessed with array[y][x].
             Any reference to the array must be dropped before the last reference to the
             related dataset is also dropped.
          """
          from osgeo import gdal_array
          if options is None:
              virtualmem = self.GetVirtualMemAuto(eAccess)
          else:
              virtualmem = self.GetVirtualMemAuto(eAccess, options)
          return gdal_array.VirtualMemGetArray( virtualmem )

    def GetTiledVirtualMemArray(self, eAccess=gdalconst.GF_Read, xoff=0, yoff=0,
                             xsize=None, ysize=None, tilexsize=256, tileysize=256,
                             datatype=None,
                             cache_size = 10 * 1024 * 1024, options=None):
          """Return a NumPy array for the band, seen as a virtual memory mapping with
             a tile organization.
             An element is accessed with array[tiley][tilex][y][x].
             Any reference to the array must be dropped before the last reference to the
             related dataset is also dropped.
          """
          from osgeo import gdal_array
          if xsize is None:
              xsize = self.XSize
          if ysize is None:
              ysize = self.YSize
          if datatype is None:
              datatype = self.DataType
          if options is None:
              virtualmem = self.GetTiledVirtualMem(eAccess, xoff, yoff, xsize, ysize, tilexsize, tileysize, datatype, cache_size)
          else:
              virtualmem = self.GetTiledVirtualMem(eAccess, xoff, yoff, xsize, ysize, tilexsize, tileysize, datatype, cache_size, options)
          return gdal_array.VirtualMemGetArray( virtualmem )

    def BlockWindows(self):
         """Yield a window ``(xOff, yOff, xSize, ySize)`` corresponding to
         each block in this ``Band``. Iteration order is from left to right,
         then from top to bottom.

         Examples
         --------
         .. testsetup::
            >>> src_ds = gdal.Open("byte.tif")
            >>> dst_ds = gdal.GetDriverByName("MEM").Create("", 20, 20)
            >>> src_band = src_ds.GetRasterBand(1)
            >>> dst_band = dst_ds.GetRasterBand(1)

         >>> for window in src_band.BlockWindows():
         ...    values = src_band.ReadAsArray(*window)
         ...    dst_band.WriteArray(values + 20, window.xoff, window.yoff)
         0
         """
         import math
         blockXSize, blockYSize = self.GetBlockSize()
         nBlocksX = math.ceil(self.XSize / blockXSize)
         nBlocksY = math.ceil(self.YSize / blockYSize)
         for winrow in range(0, nBlocksY):
             yOff = winrow * blockYSize
             ySize = min(blockYSize, self.YSize - yOff)
             for wincol in range(0, nBlocksX):
                 xOff = wincol * blockXSize
                 xSize = min(blockXSize, self.XSize - xOff)
                 yield Window(xOff, yOff, xSize, ySize)




# Register Band in _gdal:
_gdal.Band_swigregister(Band)

del Band.UnaryOp
del Band.BinaryOpBand
del Band.BinaryOpDouble
del Band.BinaryOpDoubleToBand
del Band.AsType
del Band.MinimumOfNBands
del Band.MinConstant
del Band.MaximumOfNBands
del Band.MaxConstant
del Band.MeanOfNBands
del Band.IfThenElse

class ComputedBand(Band):
    r"""Proxy of C++ GDALComputedRasterBandShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_ComputedBand

# Register ComputedBand in _gdal:
_gdal.ComputedBand_swigregister(ComputedBand)
class ColorTable(object):
    r"""Proxy of C++ GDALColorTableShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args, **kwargs):
        r"""__init__(self, palette=GPI_RGB) -> ColorTable"""
        _gdal.ColorTable_swiginit(self, _gdal.new_ColorTable(*args, **kwargs))
    __swig_destroy__ = _gdal.delete_ColorTable

    def Clone(self, *args):
        r"""Clone(self) -> ColorTable"""
        return _gdal.ColorTable_Clone(self, *args)

    def GetPaletteInterpretation(self, *args):
        r"""GetPaletteInterpretation(self) -> GDALPaletteInterp"""
        return _gdal.ColorTable_GetPaletteInterpretation(self, *args)

    def GetCount(self, *args):
        r"""GetCount(self) -> int"""
        return _gdal.ColorTable_GetCount(self, *args)

    def GetColorEntry(self, *args):
        r"""GetColorEntry(self, entry) -> ColorEntry"""
        return _gdal.ColorTable_GetColorEntry(self, *args)

    def GetColorEntryAsRGB(self, *args):
        r"""GetColorEntryAsRGB(self, entry, centry) -> int"""
        return _gdal.ColorTable_GetColorEntryAsRGB(self, *args)

    def SetColorEntry(self, *args):
        r"""SetColorEntry(self, entry, centry)"""
        return _gdal.ColorTable_SetColorEntry(self, *args)

    def CreateColorRamp(self, *args):
        r"""CreateColorRamp(self, nStartIndex, startcolor, nEndIndex, endcolor)"""
        return _gdal.ColorTable_CreateColorRamp(self, *args)

# Register ColorTable in _gdal:
_gdal.ColorTable_swigregister(ColorTable)
class SubdatasetInfo(object):
    r"""Proxy of C++ GDALSubdatasetInfoShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_SubdatasetInfo

    def GetPathComponent(self, *args):
        r"""GetPathComponent(self) -> retStringAndCPLFree *"""
        return _gdal.SubdatasetInfo_GetPathComponent(self, *args)

    def GetSubdatasetComponent(self, *args):
        r"""GetSubdatasetComponent(self) -> retStringAndCPLFree *"""
        return _gdal.SubdatasetInfo_GetSubdatasetComponent(self, *args)

    def ModifyPathComponent(self, *args):
        r"""ModifyPathComponent(self, pszNewFileName) -> retStringAndCPLFree *"""
        return _gdal.SubdatasetInfo_ModifyPathComponent(self, *args)

# Register SubdatasetInfo in _gdal:
_gdal.SubdatasetInfo_swigregister(SubdatasetInfo)

def GetSubdatasetInfo(*args):
    r"""GetSubdatasetInfo(pszFileName) -> GDALSubdatasetInfoShadow *"""
    return _gdal.GetSubdatasetInfo(*args)
class Relationship(object):
    r"""Proxy of C++ GDALRelationshipShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, name, leftTableName, rightTableName, cardinality) -> Relationship"""
        _gdal.Relationship_swiginit(self, _gdal.new_Relationship(*args))
    __swig_destroy__ = _gdal.delete_Relationship

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.Relationship_GetName(self, *args)

    def GetCardinality(self, *args):
        r"""GetCardinality(self) -> GDALRelationshipCardinality"""
        return _gdal.Relationship_GetCardinality(self, *args)

    def GetLeftTableName(self, *args):
        r"""GetLeftTableName(self) -> char const *"""
        return _gdal.Relationship_GetLeftTableName(self, *args)

    def GetRightTableName(self, *args):
        r"""GetRightTableName(self) -> char const *"""
        return _gdal.Relationship_GetRightTableName(self, *args)

    def GetMappingTableName(self, *args):
        r"""GetMappingTableName(self) -> char const *"""
        return _gdal.Relationship_GetMappingTableName(self, *args)

    def SetMappingTableName(self, *args):
        r"""SetMappingTableName(self, pszName)"""
        return _gdal.Relationship_SetMappingTableName(self, *args)

    def GetLeftTableFields(self, *args):
        r"""GetLeftTableFields(self) -> char **"""
        return _gdal.Relationship_GetLeftTableFields(self, *args)

    def GetRightTableFields(self, *args):
        r"""GetRightTableFields(self) -> char **"""
        return _gdal.Relationship_GetRightTableFields(self, *args)

    def SetLeftTableFields(self, *args):
        r"""SetLeftTableFields(self, pFields)"""
        return _gdal.Relationship_SetLeftTableFields(self, *args)

    def SetRightTableFields(self, *args):
        r"""SetRightTableFields(self, pFields)"""
        return _gdal.Relationship_SetRightTableFields(self, *args)

    def GetLeftMappingTableFields(self, *args):
        r"""GetLeftMappingTableFields(self) -> char **"""
        return _gdal.Relationship_GetLeftMappingTableFields(self, *args)

    def GetRightMappingTableFields(self, *args):
        r"""GetRightMappingTableFields(self) -> char **"""
        return _gdal.Relationship_GetRightMappingTableFields(self, *args)

    def SetLeftMappingTableFields(self, *args):
        r"""SetLeftMappingTableFields(self, pFields)"""
        return _gdal.Relationship_SetLeftMappingTableFields(self, *args)

    def SetRightMappingTableFields(self, *args):
        r"""SetRightMappingTableFields(self, pFields)"""
        return _gdal.Relationship_SetRightMappingTableFields(self, *args)

    def GetType(self, *args):
        r"""GetType(self) -> GDALRelationshipType"""
        return _gdal.Relationship_GetType(self, *args)

    def SetType(self, *args):
        r"""SetType(self, type)"""
        return _gdal.Relationship_SetType(self, *args)

    def GetForwardPathLabel(self, *args):
        r"""GetForwardPathLabel(self) -> char const *"""
        return _gdal.Relationship_GetForwardPathLabel(self, *args)

    def SetForwardPathLabel(self, *args):
        r"""SetForwardPathLabel(self, pszLabel)"""
        return _gdal.Relationship_SetForwardPathLabel(self, *args)

    def GetBackwardPathLabel(self, *args):
        r"""GetBackwardPathLabel(self) -> char const *"""
        return _gdal.Relationship_GetBackwardPathLabel(self, *args)

    def SetBackwardPathLabel(self, *args):
        r"""SetBackwardPathLabel(self, pszLabel)"""
        return _gdal.Relationship_SetBackwardPathLabel(self, *args)

    def GetRelatedTableType(self, *args):
        r"""GetRelatedTableType(self) -> char const *"""
        return _gdal.Relationship_GetRelatedTableType(self, *args)

    def SetRelatedTableType(self, *args):
        r"""SetRelatedTableType(self, pszType)"""
        return _gdal.Relationship_SetRelatedTableType(self, *args)

# Register Relationship in _gdal:
_gdal.Relationship_swigregister(Relationship)

def TermProgress_nocb(*args, **kwargs):
    r"""TermProgress_nocb(dfProgress, pszMessage=None, pData=None) -> int"""
    return _gdal.TermProgress_nocb(*args, **kwargs)
TermProgress = _gdal.TermProgress


def ComputeMedianCutPCT(*args, **kwargs):
    r"""ComputeMedianCutPCT(red, green, blue, num_colors, colors, callback=0, callback_data=None) -> int"""
    return _gdal.ComputeMedianCutPCT(*args, **kwargs)

def DitherRGB2PCT(*args, **kwargs):
    r"""DitherRGB2PCT(red, green, blue, target, colors, callback=0, callback_data=None) -> int"""
    return _gdal.DitherRGB2PCT(*args, **kwargs)

def ReprojectImage(*args, **kwargs):
    r"""
    ReprojectImage(src_ds, dst_ds, src_wkt=None, dst_wkt=None, eResampleAlg=GRA_NearestNeighbour, WarpMemoryLimit=0.0, maxerror=0.0, callback=0, callback_data=None, options=None) -> CPLErr


    Reproject image.

    See :cpp:func:`GDALReprojectImage`.

    Consider using :py:func:`osgeo.gdal.Warp` and :py:func:`osgeo.gdal.WarpOptions` instead

    """
    return _gdal.ReprojectImage(*args, **kwargs)

def ComputeProximity(*args, **kwargs):
    r"""ComputeProximity(srcBand, proximityBand, options=None, callback=0, callback_data=None) -> int"""
    return _gdal.ComputeProximity(*args, **kwargs)

def RasterizeLayer(*args, **kwargs):
    r"""RasterizeLayer(dataset, bands, layer, pfnTransformer=None, pTransformArg=None, burn_values=0, options=None, callback=0, callback_data=None) -> int"""
    return _gdal.RasterizeLayer(*args, **kwargs)

def Polygonize(*args, **kwargs):
    r"""Polygonize(srcBand, maskBand, outLayer, iPixValField, options=None, callback=0, callback_data=None) -> int"""
    return _gdal.Polygonize(*args, **kwargs)

def FPolygonize(*args, **kwargs):
    r"""FPolygonize(srcBand, maskBand, outLayer, iPixValField, options=None, callback=0, callback_data=None) -> int"""
    return _gdal.FPolygonize(*args, **kwargs)

def FillNodata(*args, **kwargs):
    r"""
    FillNodata(targetBand, maskBand, maxSearchDist, smoothingIterations, options=None, callback=0, callback_data=None) -> int


    Fill selected raster regions by interpolation from the edges.

    This algorithm will interpolate values for all designated
    nodata pixels (marked by zeros in ``maskBand``). For each pixel
    a four direction conic search is done to find values to interpolate
    from (using inverse distance weighting by default). Once all values are
    interpolated, zero or more smoothing iterations (3x3 average
    filters on interpolated pixels) are applied to smooth out
    artifacts.

    This algorithm is generally suitable for interpolating missing
    regions of fairly continuously varying rasters (such as elevation
    models for instance). It is also suitable for filling small holes
    and cracks in more irregularly varying images (like airphotos). It
    is generally not so great for interpolating a raster from sparse
    point data. See :py:func:`Grid` for that case.

    See :cpp:func:`GDALFillNodata`.

    Parameters
    ----------
    targetBand : Band
        Band containing values to fill. Will be modified in-place.
    maskBand : Band
        Mask band with a value of 0 indicating values that should be filled.
        If not specified, the mask band associated with ``targetBand`` will be used.
    maxSearchDist : float
        the maximum number of pixels to search in all directions to find values to interpolate from.
    smoothingIterations : int
        the number of 3x3 smoothing filter passes to run (0 or more)
    options : dict or list, optional
        A dict or list of name=value options. Available options are
        described in :cpp:func:`GDALFillNodata`.
    callback : callable, optional
       A progress callback function
    callback_data : any, optional
       Optional data to be passed to callback function

    Returns
    -------
    int
       :py:const:`CE_None` on success or :py:const:`CE_Failure` on failure.

    Examples
    --------
    >>> import numpy as np
    >>> data = np.array([[1, 2], [9, 9], [9, 9], [3, 4]], dtype=np.float32)
    >>> ds = gdal.GetDriverByName('MEM').Create('', 2, 4, eType=gdal.GDT_Float32)
    >>> ds.WriteArray(data)
    0
    >>> mask = data != 9  # replace pixels with value = 9
    >>> mask_ds = gdal.GetDriverByName('MEM').Create('', 2, 4, eType=gdal.GDT_Byte)
    >>> mask_ds.WriteArray(mask)
    0
    >>> gdal.FillNodata(ds.GetRasterBand(1), mask_ds.GetRasterBand(1), 5, 0)
    0
    >>> ds.ReadAsArray()
    array([[1.       , 2.       ],
           [2.1485982, 2.6666667],
           [2.721169 , 3.3333333],
           [3.       , 4.       ]], dtype=float32)
    >>> gdal.FillNodata(ds.GetRasterBand(1), mask_ds.GetRasterBand(1), 5, 0, {'INTERPOLATION':'NEAREST'})
    0
    >>> ds.ReadAsArray()
    array([[1., 2.],
           [1., 2.],
           [3., 4.],
           [3., 4.]], dtype=float32)


    """
    return _gdal.FillNodata(*args, **kwargs)

def SieveFilter(*args, **kwargs):
    r"""SieveFilter(srcBand, maskBand, dstBand, threshold, connectedness=4, options=None, callback=0, callback_data=None) -> int"""
    return _gdal.SieveFilter(*args, **kwargs)

def RegenerateOverviews(*args, **kwargs):
    r"""RegenerateOverviews(srcBand, overviewBandCount, resampling="average", callback=0, callback_data=None) -> int"""
    return _gdal.RegenerateOverviews(*args, **kwargs)

def RegenerateOverview(*args, **kwargs):
    r"""RegenerateOverview(srcBand, overviewBand, resampling="average", callback=0, callback_data=None) -> int"""
    return _gdal.RegenerateOverview(*args, **kwargs)

def ContourGenerate(*args, **kwargs):
    r"""ContourGenerate(srcBand, contourInterval, contourBase, fixedLevelCount, useNoData, noDataValue, dstLayer, idField, elevField, callback=0, callback_data=None) -> int"""
    return _gdal.ContourGenerate(*args, **kwargs)

def ContourGenerateEx(*args, **kwargs):
    r"""ContourGenerateEx(srcBand, dstLayer, options=None, callback=0, callback_data=None) -> int"""
    return _gdal.ContourGenerateEx(*args, **kwargs)
GVM_Diagonal = _gdal.GVM_Diagonal

GVM_Edge = _gdal.GVM_Edge

GVM_Max = _gdal.GVM_Max

GVM_Min = _gdal.GVM_Min

GVOT_NORMAL = _gdal.GVOT_NORMAL

GVOT_MIN_TARGET_HEIGHT_FROM_DEM = _gdal.GVOT_MIN_TARGET_HEIGHT_FROM_DEM

GVOT_MIN_TARGET_HEIGHT_FROM_GROUND = _gdal.GVOT_MIN_TARGET_HEIGHT_FROM_GROUND


def ViewshedGenerate(*args, **kwargs):
    r"""ViewshedGenerate(srcBand, driverName, targetRasterName, creationOptions, observerX, observerY, observerHeight, targetHeight, visibleVal, invisibleVal, outOfRangeVal, noDataVal, dfCurvCoeff, mode, maxDistance, callback=0, callback_data=None, heightMode=GVOT_NORMAL, options=None) -> Dataset"""
    return _gdal.ViewshedGenerate(*args, **kwargs)

def IsLineOfSightVisible(*args, **kwargs):
    r"""
    IsLineOfSightVisible(band, xA, yA, zA, xB, yB, zB, options=None)


    Check Line of Sight between two points.
    Both input coordinates must be within the raster coordinate bounds.

     See :cpp:func:`GDALIsLineOfSightVisible`.

    .. versionadded:: 3.9

    Parameters
    ----------
    band : Band
        The band to read the DEM data from. This must NOT be null.
    xA : int
        The X location (raster column) of the first point to check on the raster.
    yA : int
        The Y location (raster row) of the first point to check on the raster.
    zA : float
        The Z location (height) of the first point to check.
    xB : int
        The X location (raster column) of the second point to check on the raster.
    yB : int
        The Y location (raster row) of the second point to check on the raster.
    zB : float
        The Z location (height) of the second point to check.
    options : dict or list, optional
        A dict or list of name=value of options for the line of sight algorithm (currently ignored).

    Returns
    -------
    tuple
        A named tuple with the following fields:

        - ``is_visible`` (bool): True if the two points are within Line of Sight.
        - ``col_intersection`` (int): Raster column index where the LOS line intersects terrain.
        - ``row_intersection`` (int): Raster row index where the LOS line intersects terrain.

    """
    val = _gdal.IsLineOfSightVisible(*args, **kwargs)

    is_visible, col_intersection, row_intersection = val
    import collections
    tuple = collections.namedtuple('IsLineOfSightVisibleResult', ['is_visible', 'col_intersection', 'row_intersection'])
    tuple.is_visible = is_visible
    tuple.col_intersection = col_intersection
    tuple.row_intersection = row_intersection
    val = tuple


    return val

def AutoCreateWarpedVRT(*args):
    r"""AutoCreateWarpedVRT(src_ds, src_wkt=None, dst_wkt=None, eResampleAlg=GRA_NearestNeighbour, maxerror=0.0) -> Dataset"""
    return _gdal.AutoCreateWarpedVRT(*args)

def CreatePansharpenedVRT(*args):
    r"""CreatePansharpenedVRT(pszXML, panchroBand, nInputSpectralBands) -> Dataset"""
    return _gdal.CreatePansharpenedVRT(*args)

def GetTranformerOptionList(*args):
    r"""GetTranformerOptionList() -> char const *"""
    return _gdal.GetTranformerOptionList(*args)
class GDALTransformerInfoShadow(object):
    r"""Proxy of C++ GDALTransformerInfoShadow class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_GDALTransformerInfoShadow

    def TransformPoint(self, *args):
        r"""
        TransformPoint(self, bDstToSrc, inout) -> int
        TransformPoint(self, bDstToSrc, x, y, z=0.0) -> int
        """
        return _gdal.GDALTransformerInfoShadow_TransformPoint(self, *args)

    def TransformPoints(self, *args):
        r"""TransformPoints(self, bDstToSrc, nCount) -> int"""
        return _gdal.GDALTransformerInfoShadow_TransformPoints(self, *args)

    def TransformGeolocations(self, *args, **kwargs):
        r"""TransformGeolocations(self, xBand, yBand, zBand, callback=0, callback_data=None, options=None) -> int"""
        return _gdal.GDALTransformerInfoShadow_TransformGeolocations(self, *args, **kwargs)

# Register GDALTransformerInfoShadow in _gdal:
_gdal.GDALTransformerInfoShadow_swigregister(GDALTransformerInfoShadow)

def Transformer(*args):
    r"""Transformer(src, dst, options) -> GDALTransformerInfoShadow"""
    return _gdal.Transformer(*args)

def WarpGetOptionList(*args):
    r"""WarpGetOptionList() -> char const *"""
    return _gdal.WarpGetOptionList(*args)
class SuggestedWarpOutputRes(object):
    r"""Proxy of C++ SuggestedWarpOutputRes class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    width = property(_gdal.SuggestedWarpOutputRes_width_get, doc=r"""width""")
    height = property(_gdal.SuggestedWarpOutputRes_height_get, doc=r"""height""")
    xmin = property(_gdal.SuggestedWarpOutputRes_xmin_get, doc=r"""xmin""")
    ymin = property(_gdal.SuggestedWarpOutputRes_ymin_get, doc=r"""ymin""")
    xmax = property(_gdal.SuggestedWarpOutputRes_xmax_get, doc=r"""xmax""")
    ymax = property(_gdal.SuggestedWarpOutputRes_ymax_get, doc=r"""ymax""")
    __swig_destroy__ = _gdal.delete_SuggestedWarpOutputRes

    def GetGeotransform(self, *args):
        r"""GetGeotransform(self)"""
        return _gdal.SuggestedWarpOutputRes_GetGeotransform(self, *args)

    geotransform = property(_gdal.SuggestedWarpOutputRes_GetGeotransform, doc=r"""geotransform : double[6]""")


# Register SuggestedWarpOutputRes in _gdal:
_gdal.SuggestedWarpOutputRes_swigregister(SuggestedWarpOutputRes)

def SuggestedWarpOutputFromTransformer(*args):
    r"""SuggestedWarpOutputFromTransformer(src, transformer) -> SuggestedWarpOutputRes"""
    return _gdal.SuggestedWarpOutputFromTransformer(*args)

def SuggestedWarpOutputFromOptions(*args):
    r"""SuggestedWarpOutputFromOptions(src, options) -> SuggestedWarpOutputRes"""
    return _gdal.SuggestedWarpOutputFromOptions(*args)


def SuggestedWarpOutput(*args):
    """
    Suggest output dataset size and extent.

    SuggestedWarpOutput(src: Dataset, transformer: Transformer) -> SuggestedWarpOutputRes
    SuggestedWarpOutput(src: Dataset, options: list[str]) -> SuggestedWarpOutputRes

    This function is used to suggest the size, and georeferenced extents
    appropriate given the indicated transformation and input file.  It walks
    the edges of the input file (approximately 20 sample points along each
    edge) transforming into output coordinates in order to get an extents box.

    Then a resolution is computed with the intent that the length of the
    distance from the top left corner of the output imagery to the bottom right
    corner would represent the same number of pixels as in the source image.
    Note that if the image is somewhat rotated the diagonal taken isn't of the
    whole output bounding rectangle, but instead of the locations where the
    top/left and bottom/right corners transform.  The output pixel size is
    always square.  This is intended to approximately preserve the resolution
    of the input data in the output file.

    There are 2 forms of this method:

    - one that takes the output of gdal.Transformer(src, dst, options) as the second argument.
      The src argument of the gdal.Transformer() call should nominally be the src
      argument passed to this function.
      The dst argument of the gdal.Transformer() call should nominally be None
      The third argument of the gdal.Transformer() call should be a list of strings,
      that are transforming options accepted by
      :cpp:func:`GDALCreateGenImgProjTransformer2` (e.g ``DST_SRS``)

    - one that takes a list of strings as the second argument. Those strings
      are the transforming options accepted by
      :cpp:func:`GDALCreateGenImgProjTransformer2` (e.g ``DST_SRS``)

    Parameters
    ----------

    src : Dataset
        Source dataset
    transformer : Transformer
        The return value of gdal.Transformer(src, None, options)
        (exclusive with below options parameter)
    options : list[str]
        List of strings that are the transforming options accepted by
        :cpp:func:`GDALCreateGenImgProjTransformer2` (e.g ``DST_SRS``)
        (exclusive with above transformer parameter)

    Returns
    -------
    SuggestedWarpOutputRes
        An instance of the SuggestedWarpOutputRes class with the following members:

        - ``width`` (int): Number of pixels in width of the output dataset.
        - ``height`` (int): Number of pixels in height of the output dataset.
        - ``xmin`` (float): Minimum value of the georeferenced X coordinates.
        - ``ymin`` (float): Minimum value of the georeferenced Y coordinates.
        - ``xmax`` (float): Maximum value of the georeferenced X coordinates.
        - ``ymax`` (float): Maximum value of the georeferenced Y coordinates.
        - ``geotransform`` (tuple of 6 floats): Affine geotransformation matrix.

    Examples
    --------

    >>> ds = gdal.Open("byte.tif")
    >>> res = gdal.SuggestedWarpOutput(ds, ["DST_SRS=EPSG:4326"])
    >>> print(res.width, res.height, res.xmin, res.ymin, res.xmax, res.ymax, res.geotransform)
        22 18 -117.642 33.891 -117.629 33.902 (-117.642, 0.000598, 0.0, 33.902, 0.0, -0.000598)

    """
    if isinstance(args[1], GDALTransformerInfoShadow):
        return _gdal.SuggestedWarpOutputFromTransformer(*args)
    else:
        return _gdal.SuggestedWarpOutputFromOptions(*args)


def _ApplyVerticalShiftGrid(*args, **kwargs):
    r"""_ApplyVerticalShiftGrid(src_ds, grid_ds, inverse=False, srcUnitToMeter=1.0, dstUnitToMeter=1.0, options=None) -> Dataset"""
    return _gdal._ApplyVerticalShiftGrid(*args, **kwargs)

def GetGlobalAlgorithmRegistry(*args):
    r"""
    GetGlobalAlgorithmRegistry() -> AlgorithmRegistry


    Return the default algorithm registry.

    Returns
    -------
    AlgorithmRegistry


    """
    return _gdal.GetGlobalAlgorithmRegistry(*args)

def AlgorithmArgTypeIsList(*args):
    r"""
    AlgorithmArgTypeIsList(type) -> bool


    Test whether an argument type represents a list.

    Parameters
    ----------
    type : int

    Returns
    -------
    bool

    Examples
    --------
    >>> gdal.AlgorithmArgTypeIsList(gdal.GAAT_REAL)
    False
    >>> gdal.AlgorithmArgTypeIsList(gdal.GAAT_REAL_LIST)
    True


    """
    return _gdal.AlgorithmArgTypeIsList(*args)

def AlgorithmArgTypeName(*args):
    r"""
    AlgorithmArgTypeName(type) -> char const *


    Return a text representation of an argument type code.

    Parameters
    ----------
    type : int

    Returns
    -------
    str

    Examples
    --------
    >>> gdal.AlgorithmArgTypeName(gdal.GAAT_REAL)
    'real'


    """
    return _gdal.AlgorithmArgTypeName(*args)
class AlgorithmArg(object):
    r"""Proxy of C++ GDALAlgorithmArgHS class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_AlgorithmArg

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.AlgorithmArg_GetName(self, *args)

    def GetType(self, *args):
        r"""GetType(self) -> GDALAlgorithmArgType"""
        return _gdal.AlgorithmArg_GetType(self, *args)

    def GetDescription(self, *args):
        r"""GetDescription(self) -> char const *"""
        return _gdal.AlgorithmArg_GetDescription(self, *args)

    def GetShortName(self, *args):
        r"""GetShortName(self) -> char const *"""
        return _gdal.AlgorithmArg_GetShortName(self, *args)

    def GetAliases(self, *args):
        r"""GetAliases(self) -> char **"""
        return _gdal.AlgorithmArg_GetAliases(self, *args)

    def GetMetaVar(self, *args):
        r"""GetMetaVar(self) -> char const *"""
        return _gdal.AlgorithmArg_GetMetaVar(self, *args)

    def GetCategory(self, *args):
        r"""GetCategory(self) -> char const *"""
        return _gdal.AlgorithmArg_GetCategory(self, *args)

    def IsPositional(self, *args):
        r"""IsPositional(self) -> bool"""
        return _gdal.AlgorithmArg_IsPositional(self, *args)

    def IsRequired(self, *args):
        r"""IsRequired(self) -> bool"""
        return _gdal.AlgorithmArg_IsRequired(self, *args)

    def GetMinCount(self, *args):
        r"""GetMinCount(self) -> int"""
        return _gdal.AlgorithmArg_GetMinCount(self, *args)

    def GetMaxCount(self, *args):
        r"""GetMaxCount(self) -> int"""
        return _gdal.AlgorithmArg_GetMaxCount(self, *args)

    def GetPackedValuesAllowed(self, *args):
        r"""GetPackedValuesAllowed(self) -> bool"""
        return _gdal.AlgorithmArg_GetPackedValuesAllowed(self, *args)

    def GetRepeatedArgAllowed(self, *args):
        r"""GetRepeatedArgAllowed(self) -> bool"""
        return _gdal.AlgorithmArg_GetRepeatedArgAllowed(self, *args)

    def GetChoices(self, *args):
        r"""GetChoices(self) -> char **"""
        return _gdal.AlgorithmArg_GetChoices(self, *args)

    def GetMetadataItem(self, *args):
        r"""GetMetadataItem(self, item) -> char **"""
        return _gdal.AlgorithmArg_GetMetadataItem(self, *args)

    def IsExplicitlySet(self, *args):
        r"""IsExplicitlySet(self) -> bool"""
        return _gdal.AlgorithmArg_IsExplicitlySet(self, *args)

    def HasDefaultValue(self, *args):
        r"""HasDefaultValue(self) -> bool"""
        return _gdal.AlgorithmArg_HasDefaultValue(self, *args)

    def GetDefaultAsBoolean(self, *args):
        r"""GetDefaultAsBoolean(self) -> bool"""
        return _gdal.AlgorithmArg_GetDefaultAsBoolean(self, *args)

    def GetDefaultAsString(self, *args):
        r"""GetDefaultAsString(self) -> char const *"""
        return _gdal.AlgorithmArg_GetDefaultAsString(self, *args)

    def GetDefaultAsInteger(self, *args):
        r"""GetDefaultAsInteger(self) -> int"""
        return _gdal.AlgorithmArg_GetDefaultAsInteger(self, *args)

    def GetDefaultAsDouble(self, *args):
        r"""GetDefaultAsDouble(self) -> double"""
        return _gdal.AlgorithmArg_GetDefaultAsDouble(self, *args)

    def GetDefaultAsStringList(self, *args):
        r"""GetDefaultAsStringList(self) -> char **"""
        return _gdal.AlgorithmArg_GetDefaultAsStringList(self, *args)

    def GetDefaultAsIntegerList(self, *args):
        r"""GetDefaultAsIntegerList(self)"""
        return _gdal.AlgorithmArg_GetDefaultAsIntegerList(self, *args)

    def GetDefaultAsDoubleList(self, *args):
        r"""GetDefaultAsDoubleList(self)"""
        return _gdal.AlgorithmArg_GetDefaultAsDoubleList(self, *args)

    def IsHidden(self, *args):
        r"""IsHidden(self) -> bool"""
        return _gdal.AlgorithmArg_IsHidden(self, *args)

    def IsHiddenForCLI(self, *args):
        r"""IsHiddenForCLI(self) -> bool"""
        return _gdal.AlgorithmArg_IsHiddenForCLI(self, *args)

    def IsHiddenForAPI(self, *args):
        r"""IsHiddenForAPI(self) -> bool"""
        return _gdal.AlgorithmArg_IsHiddenForAPI(self, *args)

    def IsAvailableInPipelineStep(self, *args):
        r"""IsAvailableInPipelineStep(self) -> bool"""
        return _gdal.AlgorithmArg_IsAvailableInPipelineStep(self, *args)

    def IsInput(self, *args):
        r"""IsInput(self) -> bool"""
        return _gdal.AlgorithmArg_IsInput(self, *args)

    def IsOutput(self, *args):
        r"""IsOutput(self) -> bool"""
        return _gdal.AlgorithmArg_IsOutput(self, *args)

    def GetDatasetType(self, *args):
        r"""GetDatasetType(self) -> int"""
        return _gdal.AlgorithmArg_GetDatasetType(self, *args)

    def GetDatasetInputFlags(self, *args):
        r"""GetDatasetInputFlags(self) -> int"""
        return _gdal.AlgorithmArg_GetDatasetInputFlags(self, *args)

    def GetDatasetOutputFlags(self, *args):
        r"""GetDatasetOutputFlags(self) -> int"""
        return _gdal.AlgorithmArg_GetDatasetOutputFlags(self, *args)

    def GetMutualExclusionGroup(self, *args):
        r"""GetMutualExclusionGroup(self) -> char const *"""
        return _gdal.AlgorithmArg_GetMutualExclusionGroup(self, *args)

    def GetMutualDependencyGroup(self, *args):
        r"""GetMutualDependencyGroup(self) -> char const *"""
        return _gdal.AlgorithmArg_GetMutualDependencyGroup(self, *args)

    def GetDirectDependencies(self, *args):
        r"""GetDirectDependencies(self) -> char **"""
        return _gdal.AlgorithmArg_GetDirectDependencies(self, *args)

    def GetAsBoolean(self, *args):
        r"""GetAsBoolean(self) -> bool"""
        return _gdal.AlgorithmArg_GetAsBoolean(self, *args)

    def GetAsString(self, *args):
        r"""GetAsString(self) -> char const *"""
        return _gdal.AlgorithmArg_GetAsString(self, *args)

    def GetAsInteger(self, *args):
        r"""GetAsInteger(self) -> int"""
        return _gdal.AlgorithmArg_GetAsInteger(self, *args)

    def GetAsDouble(self, *args):
        r"""GetAsDouble(self) -> double"""
        return _gdal.AlgorithmArg_GetAsDouble(self, *args)

    def GetAsDatasetValue(self, *args):
        r"""GetAsDatasetValue(self) -> ArgDatasetValue"""
        return _gdal.AlgorithmArg_GetAsDatasetValue(self, *args)

    def GetAsStringList(self, *args):
        r"""GetAsStringList(self) -> char **"""
        return _gdal.AlgorithmArg_GetAsStringList(self, *args)

    def GetAsIntegerList(self, *args):
        r"""GetAsIntegerList(self)"""
        return _gdal.AlgorithmArg_GetAsIntegerList(self, *args)

    def GetAsDoubleList(self, *args):
        r"""GetAsDoubleList(self)"""
        return _gdal.AlgorithmArg_GetAsDoubleList(self, *args)

    def SetAsBoolean(self, *args):
        r"""SetAsBoolean(self, value) -> bool"""
        return _gdal.AlgorithmArg_SetAsBoolean(self, *args)

    def SetAsString(self, *args):
        r"""SetAsString(self, value) -> bool"""
        return _gdal.AlgorithmArg_SetAsString(self, *args)

    def SetAsInteger(self, *args):
        r"""SetAsInteger(self, value) -> bool"""
        return _gdal.AlgorithmArg_SetAsInteger(self, *args)

    def SetAsDouble(self, *args):
        r"""SetAsDouble(self, value) -> bool"""
        return _gdal.AlgorithmArg_SetAsDouble(self, *args)

    def SetAsDatasetValue(self, *args):
        r"""SetAsDatasetValue(self, value) -> bool"""
        return _gdal.AlgorithmArg_SetAsDatasetValue(self, *args)

    def SetAsStringList(self, *args):
        r"""SetAsStringList(self, value) -> bool"""
        return _gdal.AlgorithmArg_SetAsStringList(self, *args)

    def SetAsIntegerList(self, *args):
        r"""SetAsIntegerList(self, nList) -> bool"""
        return _gdal.AlgorithmArg_SetAsIntegerList(self, *args)

    def SetAsDoubleList(self, *args):
        r"""SetAsDoubleList(self, nList) -> bool"""
        return _gdal.AlgorithmArg_SetAsDoubleList(self, *args)

    def SetDataset(self, *args):
        r"""SetDataset(self, ds) -> bool"""
        return _gdal.AlgorithmArg_SetDataset(self, *args)

    def SetDatasets(self, *args):
        r"""SetDatasets(self, object_list_count) -> bool"""
        return _gdal.AlgorithmArg_SetDatasets(self, *args)

    def SetDatasetNames(self, *args):
        r"""SetDatasetNames(self, names) -> bool"""
        return _gdal.AlgorithmArg_SetDatasetNames(self, *args)


    def Get(self):
        """Return the argument value in its native type.

           Note: using the ``[]`` operator of Algorithm is also a convenient
           way of getting the value of an argument.

           Examples
           --------
           >>> alg = gdal.Algorithm("raster convert")
           >>> arg = alg.GetArg("output")
           >>> arg.Get()
           <osgeo.gdal.ArgDatasetValue; proxy of <Swig Object of type 'GDALArgDatasetValueHS *' at 0x...> >
        """

        type = self.GetType()
        if type == GAAT_BOOLEAN:
            return self.GetAsBoolean()
        if type == GAAT_STRING:
            return self.GetAsString()
        if type == GAAT_INTEGER:
            return self.GetAsInteger()
        if type == GAAT_REAL:
            return self.GetAsDouble()
        if type == GAAT_DATASET:
            return self.GetAsDatasetValue()
        if type == GAAT_STRING_LIST:
            return self.GetAsStringList()
        if type == GAAT_INTEGER_LIST:
            return self.GetAsIntegerList()
        if type == GAAT_REAL_LIST:
            return self.GetAsDoubleList()

    # should not happen
        raise RuntimeError("Unhandled algorithm argument data type")

    def Set(self, value):
        """Sets the value of an argument.

           Note: using the ``[]`` operator of Algorithm is also a convenient
           way of setting the value of an argument.

           Returns
           -------
           bool
               ``True`` if the argument was successfully set

           Examples
           --------
           >>> alg = gdal.Algorithm("raster info")
           >>> arg = alg.GetArg("input")
           >>> arg.Set("in.tif")
           True
        """

        arg_type = self.GetType()

        def ToInt(v):
            if int(v) == v:
                return int(v)
            raise TypeError(f"{v} is not an integer")

        if arg_type == GAAT_BOOLEAN:
            if value in (1, "1", "yes", "YES", "true", "True", "TRUE", "on", "ON"):
                return self.SetAsBoolean(True)
            elif value in (0, "0", "no", "NO", "false", "False", "FALSE", "off", "OFF"):
                return self.SetAsBoolean(False)
            else:
                return self.SetAsBoolean(value)

        if arg_type == GAAT_STRING:
            if isinstance(value, int):
                metadata_item = self.GetMetadataItem("type")
                if metadata_item and ("GDALDataType" in metadata_item) and value >= GDT_Byte and value < GDT_TypeCount:
                    return self.SetAsString(GetDataTypeName(value))
                else:
                    return self.SetAsString(str(value))
            elif isinstance(value, str) or isinstance(value, float) or isinstance(value, os.PathLike):
                return self.SetAsString(str(value))
            elif isinstance(value, osr.SpatialReference):
                return self.SetAsString(value.ExportToWkt(["FORMAT=WKT2_2019"]))
            elif isinstance(value, list) and len(value) >= 1 and (isinstance(value[0], str) or isinstance(value[0], int) or isinstance(value[0], float) or isinstance(value[0], os.PathLike)):
                if len(value) > 1:
                    raise RuntimeError("Only one value supported for an argument of type String")
                return self.Set(value[0])
            raise TypeError("Unexpected value type %s for an argument of type String" % str(type(value)))

        if arg_type == GAAT_INTEGER:
            if isinstance(value, int):
                return self.SetAsInteger(value)
            elif isinstance(value, str):
                return self.SetAsInteger(int(value))
            elif isinstance(value, float):
                return self.SetAsInteger(ToInt(value))
            elif isinstance(value, list) and len(value) >= 1 and (isinstance(value[0], str) or isinstance(value[0], int) or isinstance(value[0], float)):
                if len(value) > 1:
                    raise RuntimeError("Only one value supported for an argument of type Integer")
                return self.Set(value[0])
            raise TypeError("Unexpected value type %s for an argument of type Integer" % str(type(value)))

        if arg_type == GAAT_REAL:
            if isinstance(value, str):
                return self.SetAsDouble(float(value))
            elif isinstance(value, int) or isinstance(value, float):
                return self.SetAsDouble(value)
            elif isinstance(value, list) and len(value) >= 1 and (isinstance(value[0], str) or isinstance(value[0], int) or isinstance(value[0], float)):
                if len(value) > 1:
                        raise RuntimeError("Only one value supported for an argument of type Real")
                return self.Set(value[0])
            raise TypeError("Unexpected value type %s for an argument of type Real" % str(type(value)))

        if arg_type == GAAT_DATASET:
            if isinstance(value, str) or isinstance(value, os.PathLike):
                self.GetAsDatasetValue().SetName(str(value))
                return True
            elif isinstance(value, Dataset):
                self.GetAsDatasetValue().SetDataset(value)
                return True
            elif isinstance(value, list) and len(value) >= 1 and (isinstance(value[0], str) or isinstance(value[0], os.PathLike) or isinstance(value[0], Dataset) or isinstance(value[0], ArgDatasetValue)):
                if len(value) > 1:
                    raise RuntimeError("Only one value supported for an argument of type Dataset")
                return self.Set(value[0])
            elif isinstance(value, ArgDatasetValue):
                return self.SetAsDatasetValue(value)
            raise TypeError("Unexpected value type %s for an argument of type Dataset" % str(type(value)))

        if arg_type == GAAT_STRING_LIST:
            if isinstance(value, list):
                if self.GetName() == "gcp" and len(value) >= 1 and \
                   isinstance(value[0], list) and len(value[0]) >= 4 and \
                   (isinstance(value[0][0], int) or isinstance(value[0][0], float)):
                    return self.SetAsStringList([','.join(["%.17g" % x for x in v]) for v in value])
                elif self.GetName() == "gcp" and len(value) >= 1 and isinstance(value[0], GCP):
                    return self.SetAsStringList(["%.17g,%.17g,%.17g,%.17g,%.17g" % (gcp.GCPPixel, gcp.GCPLine, gcp.GCPX, gcp.GCPY, gcp.GCPZ) for gcp in value])
                elif self.GetName() == "kernel" and len(value) >= 1 and isinstance(value[0], list) and len(value[0]) >= 1 and (isinstance(value[0][0], int) or isinstance(value[0][0], float)):
                    return self.SetAsStringList(["[" + ",".join(["[" + ",".join([str(v) for v in row]) + "]" for row in value]) + "]"])
                elif self.GetName() == "kernel" and len(value) >= 1 and isinstance(value[0], list) and len(value[0]) >= 1 and isinstance(value[0][0], list) and len(value[0][0]) >= 1 and (isinstance(value[0][0][0], int) or isinstance(value[0][0][0], float)):
                    return self.SetAsStringList([("[" + ",".join(["[" + ",".join([str(v) for v in row]) + "]" for row in it]) + "]") for it in value])
                else:
                    return self.SetAsStringList([str(v) for v in value])
            elif isinstance(value, dict):
                return self.SetAsStringList([f"{k}={str(value[k])}" for k in value])
            else:
                return self.SetAsStringList([str(value)])

        if arg_type == GAAT_INTEGER_LIST:
            if isinstance(value, int):
                return self.SetAsIntegerList([value])
            elif isinstance(value, float):
                return self.SetAsIntegerList([ToInt(value)])
            elif isinstance(value, str):
                return self.SetAsIntegerList([int(value)])
            elif isinstance(value, list) and len(value) >= 1 and isinstance(value[0], str):
                return self.SetAsIntegerList([int(v) for v in value])
            elif isinstance(value, list) and len(value) >= 1 and isinstance(value[0], float):
                return self.SetAsIntegerList([ToInt(v) for v in value])
            else:
                return self.SetAsIntegerList(value)

        if arg_type == GAAT_REAL_LIST:
            if isinstance(value, int) or isinstance(value, float) or isinstance(value, str):
                return self.SetAsDoubleList([float(value)])
            elif isinstance(value, list) and len(value) >= 1 and isinstance(value[0], str):
                return self.SetAsDoubleList([float(v) for v in value])
            else:
                return self.SetAsDoubleList(value)

        if arg_type == GAAT_DATASET_LIST:
            if isinstance(value, list) and len(value) > 0 and (isinstance(value[0], str) or isinstance(value[0], os.PathLike)):
                return self.SetDatasetNames([str(v) for v in value])
            elif isinstance(value, list) and (len(value) == 0 or isinstance(value[0], Dataset)):
                return self.SetDatasets(value)
            elif isinstance(value, str) or isinstance(value, os.PathLike):
                return self.SetDatasetNames([str(value)])
            elif isinstance(value, Dataset):
                return self.SetDatasets([value])
            else:
                raise TypeError("Unexpected value type %s for an argument of type DatasetList" % str(type(value)))

    # should not happen
        raise RuntimeError("Unhandled algorithm argument data type")



# Register AlgorithmArg in _gdal:
_gdal.AlgorithmArg_swigregister(AlgorithmArg)
class Algorithm(object):
    r"""


    Python proxy of a ``GDALAlgorithm``.


    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_Algorithm

    def GetName(self, *args):
        r"""
        GetName(self) -> char const *


        Get the name of the algorithm.

        Returns
        -------
        str

        Examples
        --------
        >>> gdal.Algorithm("raster", "info").GetName()
        'info'


        """
        return _gdal.Algorithm_GetName(self, *args)

    def GetDescription(self, *args):
        r"""
        GetDescription(self) -> char const *


        Get a human-readable description of the Algorithm.

        Returns
        -------
        str

        Examples
        --------
        >>> alg = gdal.Algorithm("raster", "convert")
        >>> alg.GetDescription()
        'Convert a raster dataset.'


        """
        return _gdal.Algorithm_GetDescription(self, *args)

    def GetLongDescription(self, *args):
        r"""
        GetLongDescription(self) -> char const *


        :meta private:


        """
        return _gdal.Algorithm_GetLongDescription(self, *args)

    def GetHelpFullURL(self, *args):
        r"""
        GetHelpFullURL(self) -> char const *


        Get a URL for the algorithm's documentation.

        Returns
        -------
        str

        Examples
        --------
        >>> alg = gdal.Algorithm("raster", "convert")
        >>> alg.GetHelpFullURL()
        'https://gdal.org/programs/gdal_raster_convert.html'


        """
        return _gdal.Algorithm_GetHelpFullURL(self, *args)

    def HasSubAlgorithms(self, *args):
        r"""
        HasSubAlgorithms(self) -> bool


        Returns whether the algorithm has sub-algorithms.

        Returns
        -------
        bool

        Examples
        --------
        >>> alg = gdal.Algorithm("raster")
        >>> alg.HasSubAlgorithms()
        True
        >>> subalg = alg.InstantiateSubAlgorithm("convert")
        >>> subalg.HasSubAlgorithms()
        False


        """
        return _gdal.Algorithm_HasSubAlgorithms(self, *args)

    def GetSubAlgorithmNames(self, *args):
        r"""
        GetSubAlgorithmNames(self) -> char **


        Return a list of names of sub-algorithms.

        Returns
        -------
        list or None

        Examples
        --------
        >>> alg = gdal.Algorithm("raster")
        >>> alg.GetSubAlgorithmNames()
        ['as-features', 'aspect', ..., 'viewshed', 'zonal-stats']


        """
        return _gdal.Algorithm_GetSubAlgorithmNames(self, *args)

    def InstantiateSubAlgorithm(self, *args):
        r"""
        InstantiateSubAlgorithm(self, algName) -> Algorithm


        Instantiate a sub-algorithm if available.

        Returns
        -------
        Algorithm or None

        Examples
        --------
        >>> alg = gdal.Algorithm("raster")
        >>> alg.InstantiateSubAlgorithm("convert")
        <osgeo.gdal.Algorithm; proxy of <Swig Object of type 'GDALAlgorithmHS *' at ...> >
        >>> subalg = alg.InstantiateSubAlgorithm("does_not_exist")


        """
        return _gdal.Algorithm_InstantiateSubAlgorithm(self, *args)

    def ParseCommandLineArguments(self, *args):
        r"""
        ParseCommandLineArguments(self, args) -> bool


        Parse a list of arguments for the algorithm, setting the appropriate parameters. May only be called once per algorithm.

        Parameters
        ----------
        args : list
            List of named or positional arguments

        Returns
        -------
        bool
            Whether the arguments were successfully parsed

        Examples
        --------
        >>> alg = gdal.Algorithm("vector", "info")
        >>> alg.ParseCommandLineArguments(['poly.shp', '--format', 'text'])
        True


        """

            # Convert PathLike to str
        import copy
        args = copy.deepcopy(args)
        if isinstance(args[0], list):
            for i in range(len(args[0])):
                args[0][i] = str(args[0][i])



        return _gdal.Algorithm_ParseCommandLineArguments(self, *args)


    def GetArgDependencies(self, *args):
        r"""GetArgDependencies(self, argName) -> char **"""
        return _gdal.Algorithm_GetArgDependencies(self, *args)

    def GetActualAlgorithm(self, *args):
        r"""
        GetActualAlgorithm(self) -> Algorithm


        Return the actual algorithm that is going to be invoked, if the
        current algorithm has sub-algorithms.

        Returns
        -------
        Algorithm

        Examples
        --------
        >>> alg = gdal.GetGlobalAlgorithmRegistry().InstantiateAlg("raster")
        >>> alg.ParseCommandLineArguments(["convert" ,"--input", "byte.tif", "--output",  "/tmp/byte.png"])
        True
        >>> alg.GetActualAlgorithm().GetDescription()
        'Convert a raster dataset.'


        """
        return _gdal.Algorithm_GetActualAlgorithm(self, *args)

    def Run(self, *args):
        r"""Run(self, callback=0, callback_data=None) -> bool"""

        self.has_run = True


        return _gdal.Algorithm_Run(self, *args)


    def Finalize(self, *args):
        r"""
        Finalize(self) -> bool


        Close any dataset arguments or outputs of the algorithm.

        Returns
        -------
        bool


        """
        return _gdal.Algorithm_Finalize(self, *args)

    def ParseRunAndFinalize(self, *args):
        r"""
        ParseRunAndFinalize(self, args, callback=0, callback_data=None) -> bool


        Convenience method that calls :py:meth:`ParseCommandLineArguments`, :py:meth:`Run`, and :py:meth:`Finalize`.

        This method must be called at most once per instance.

        Parameters
        ----------
        args : list
            List of command line arguments
        callback : callable, optional
            Optional progress callback function
        callback_data
            Optional value to be provided as final argument to callback function

        Returns
        -------
        bool
            ``True`` if the algorithm succeeded, ``False`` otherwise


        """

            # Convert PathLike to str
        import copy
        args = copy.deepcopy(args)
        if isinstance(args[0], list):
            for i in range(len(args[0])):
                args[0][i] = str(args[0][i])



        return _gdal.Algorithm_ParseRunAndFinalize(self, *args)


    def GetUsageAsJSON(self, *args):
        r"""
        GetUsageAsJSON(self) -> retStringAndCPLFree *


        Returns a JSON representation of an algorithm's usage information, serialized to a string.

        Returns
        -------
        str

        Examples
        --------
        >>> import json
        >>> import pprint
        >>> usage = json.loads(gdal.Algorithm("vector", "info").GetUsageAsJSON())
        >>> pprint.pprint(usage)
        {'description': 'Return information on a vector dataset.',
         'full_path': ['gdal', 'vector', 'info'],
         'input_arguments': [{'category': 'Base',
                              'choices': ['json', 'text'],
                              'description': 'Output format',
                              'name': 'output-format',
                              'required': False,
                              'type': 'string'},
                             {'category': 'Advanced',
                              'description': 'Open options',
                              'max_count': 2147483647,
                              'metavar': '<KEY>=<VALUE>',
                              'min_count': 0,
                              'name': 'open-option',
                              'packed_values_allowed': False,
                              'repeated_arg_allowed': True,
                              'required': False,
                              'type': 'string_list'},
                             {'category': 'Advanced',
                              'description': 'Input formats',
                              'max_count': 2147483647,
                              'metadata': {'required_capabilities': ['DCAP_VECTOR']},
                              'min_count': 0,
                              'name': 'input-format',
                              'packed_values_allowed': True,
                              'repeated_arg_allowed': True,
                              'required': False,
                              'type': 'string_list'},
                             {'category': 'Base',
                              'dataset_type': ['vector'],
                              'description': 'Input vector datasets',
                              'input_flags': ['name', 'dataset'],
                              'max_count': 2147483647,
                              'min_count': 0,
                              'name': 'input',
                              'packed_values_allowed': False,
                              'repeated_arg_allowed': True,
                              'required': True,
                              'type': 'dataset_list'},
                             {'category': 'Base',
                              'description': 'Input layer name',
                              'max_count': 2147483647,
                              'min_count': 0,
                              'mutual_exclusion_group': 'layer-sql',
                              'name': 'input-layer',
                              'packed_values_allowed': True,
                              'repeated_arg_allowed': True,
                              'required': False,
                              'type': 'string_list'},
                             {'category': 'Base',
                              'description': 'List all features (beware of RAM '
                                             'consumption on large layers)',
                              'mutual_exclusion_group': 'summary-features',
                              'name': 'features',
                              'required': False,
                              'type': 'boolean'},
                             {'category': 'Base',
                              'description': 'List the layer names and the geometry '
                                             'type',
                              'mutual_exclusion_group': 'summary-features',
                              'name': 'summary',
                              'required': False,
                              'type': 'boolean'},
                             {'category': 'Base',
                              'description': 'Limit the number of features per layer '
                                             '(implies --features)',
                              'metavar': 'FEATURE-COUNT',
                              'min_value': 0,
                              'min_value_is_included': True,
                              'name': 'limit',
                              'required': False,
                              'type': 'integer'},
                             {'category': 'Base',
                              'description': 'Execute the indicated SQL statement and '
                                             'return the result',
                              'metavar': '<statement>|@<filename>',
                              'mutual_exclusion_group': 'layer-sql',
                              'name': 'sql',
                              'required': False,
                              'type': 'string'},
                             {'category': 'Base',
                              'description': 'Attribute query in a restricted form of '
                                             'the queries used in the SQL WHERE '
                                             'statement',
                              'metavar': '<WHERE>|@<filename>',
                              'name': 'where',
                              'required': False,
                              'type': 'string'},
                             {'category': 'Base',
                              'description': 'Feature identifier',
                              'mutual_exclusion_group': 'layer-sql',
                              'name': 'fid',
                              'required': False,
                              'type': 'integer'},
                             {'category': 'Base',
                              'description': 'SQL dialect',
                              'name': 'dialect',
                              'required': False,
                              'type': 'string'},
                             {'category': 'Esoteric',
                              'choices': ['AUTO', 'WKT2', 'PROJJSON'],
                              'default': 'AUTO',
                              'description': 'Which format to use to report CRS',
                              'name': 'crs-format',
                              'required': False,
                              'type': 'string'}],
         'input_output_arguments': [],
         'name': 'info',
         'output_arguments': [{'category': 'Base',
                               'description': 'Output string, in which the result is '
                                              'placed',
                               'name': 'output-string',
                               'required': False,
                               'type': 'string'}],
         'short_url': '/programs/gdal_vector_info.html',
         'sub_algorithms': [],
         'supports_streamed_output': True,
         'url': 'https://gdal.org/programs/gdal_vector_info.html'}


        """
        return _gdal.Algorithm_GetUsageAsJSON(self, *args)

    def GetArgNames(self, *args):
        r"""
        GetArgNames(self) -> char **


        Get a list of arguments understood by the Algorithm.

        Returns
        -------
        list

        Examples
        --------
        >>> alg = gdal.Algorithm("raster", "convert")
        >>> sorted(alg.GetArgNames())
        ['append', 'config', 'creation-option', ..., 'progress', 'quiet']



        """
        return _gdal.Algorithm_GetArgNames(self, *args)

    def GetArg(self, *args):
        r"""
        GetArg(self, argName) -> AlgorithmArg


        Get an :py:class:`AlgorithmArg` object that can be queried for information about an argument.

        Parameters
        ----------
        argName : str

        Returns
        -------
        AlgorithmArg

        Examples
        --------
        >>> alg = gdal.Algorithm("raster", "polygonize")
        >>> arg = alg.GetArg("connect-diagonal-pixels")
        >>> arg.GetDescription()
        'Consider diagonal pixels as connected'


        """
        return _gdal.Algorithm_GetArg(self, *args)

    def GetArgNonConst(self, *args):
        r"""
        GetArgNonConst(self, argName) -> AlgorithmArg


        :meta private:


        """
        return _gdal.Algorithm_GetArgNonConst(self, *args)


    def __init__(self, *path):

        """Instantiate an existing GDAL algorithm from its path.

           .. versionadded:: 3.11

           Parameters
           ----------
           path : str, list[str] or tuple[str]
                Path to the algorithm. For example "raster info", ["raster", "info"] or "raster", "info"

           Returns
           -------
           any
                An algorithm

           Examples
           --------

           >>> alg = gdal.Algorithm("raster", "info")
           >>> # or alg = gdal.Algorithm(["raster", "info"])
           >>> # or alg = gdal.Algorithm("raster info")
           >>> alg["input"] = "byte.tif"
           >>> alg.Run()
           True
           >>> print(alg.Output()["bands"])
           [{'band': 1, 'block': [20, 20], 'type': 'Byte', 'colorInterpretation': 'Gray', 'metadata': {}}]
        """

        alg = None
        if len(path) == 1:
            if isinstance(path[0], list):
                alg = GetGlobalAlgorithmRegistry()
                alg_is_registry = True
                for i, v in enumerate(path[0]):
                    if i == 0 and v == "gdal":
                        continue
                    alg_is_registry = False
                    alg = alg[v]
                if alg_is_registry:
                    alg = alg["gdal"]
            elif isinstance(path[0], str):
                alg = GetGlobalAlgorithmRegistry()
                alg_is_registry = True
                for v in path[0].lstrip("gdal ").split(' '):
                    alg_is_registry = False
                    alg = alg[v]
                if alg_is_registry:
                    alg = alg["gdal"]
        elif len(path) > 1:
            alg = GetGlobalAlgorithmRegistry()
            for i, v in enumerate(path):
                if i == 0 and v == "gdal":
                    continue
                alg = alg[v]
        if not alg:
            raise RuntimeError("Wrong type for algorithm path. Expected string or list of strings")

        self.this = alg.this
        self.thisown = True


    def __enter__(self):
        return self

    def __exit__(self, *args):
        if hasattr(self, "has_run") and not self.Finalize():
    # We go here only if gdal.UseExceptions() has not been called
            raise RuntimeError("Algorithm.Finalize() failed: %s" % GetLastErrorMsg())

    def _get_arg_value(self, arg, parse_json):
        val = arg.Get()
        if parse_json and arg.GetType() == GAAT_STRING and \
           ((val.startswith('{') and (val.endswith('}') or val.endswith('}\n'))) or \
           (val.startswith('[') and (val.endswith(']') or val.endswith(']\n')))):
            import json
            try:
                return json.loads(val)
            except Exception:
                return val
        elif arg.GetType() == GAAT_DATASET:
            return val.GetDataset()
        else:
            return val


    def Output(self, parse_json=True):
        """Return the single output value of this algorithm, after it has been run.

           If there are multiple output values, this method will raise an exception,
           and the :py:meth:`Outputs` (plural) method should be called instead.

           Arguments of type GAAT_DATASET are returned as a
           :py:class:`osgeo.gdal.Dataset` instance.

           Parameters
           ----------
           parse_json : bool, default=True
               Whether a JSON string should be returned as a dict or list (instead of a string).

           Returns
           -------
           any
               The single output argument value.

           Examples
           --------
           >>> with gdal.Run("raster", "info", input="byte.tif") as alg:
           ...    print(alg.Output()["bands"])
           [{'band': 1, 'block': [20, 20], 'type': 'Byte', 'colorInterpretation': 'Gray', 'metadata': {}}]
        """

        if not hasattr(self, "has_run"):
            raise RuntimeError("Algorithm.Run() must be called before")

        output_args = []
        output_args_set = []
        for name in self.GetArgNames():
            arg = self.GetArg(name)
            if arg.IsOutput():
                output_args.append(arg)
                if arg.IsExplicitlySet():
                    output_args_set.append(arg)

        if len(output_args) == 1:
            return self._get_arg_value(output_args[0], parse_json)
        elif len(output_args_set) == 1:
            return self._get_arg_value(output_args_set[0], parse_json)
        elif len(output_args) >= 2:
            raise RuntimeError("Cannot use 'output' method on this algorithm as it supports multiple output arguments. Use 'Outputs' (plural) instead")
        else:
            return None


    def Outputs(self, parse_json=True):
        """Return the output value(s) of this algorithm as a dict, after it has been run.

           Most algorithms only return a single output, in which case the :py:meth:`Output`
           method (singular) is preferable for easier use.

           Arguments of type GAAT_DATASET are returned as a
           :py:class:`osgeo.gdal.Dataset` instance.

           Parameters
           ----------
           parse_json : bool, default=True
               Whether a JSON string should be returned as a dict or list (instead of a string).

           Returns
           -------
           dict
               A dict whose keys are arguments that have outputs and whose values
               are the argument values.

           Examples
           --------
           >>> with gdal.Run("raster", "reproject", input="byte.tif", output_format="MEM", dst_crs="EPSG:4326") as alg:
           ...    print(alg.Outputs()["output"].ReadAsArray())
           [[107 123 132 ... 115 99 107]]
        """

        if not hasattr(self, "has_run"):
            raise RuntimeError("Algorithm.Run() must be called before")

        res = {}
        for name in self.GetArgNames():
            arg = self.GetArg(name)
            if arg.IsOutput():
                res[name] = self._get_arg_value(arg, parse_json)
        return res


    def __getitem__(self, key):
        """Get the value of an argument.

           Shortcut for self.GetActualAlgorithm().GetArg(key).Get()
           or self.InstantiateSubAlgorithm(key) for a non-leaf algorithm

           Parameters
           ----------
           key : str
               Name of a known argument of the algorithm
           value : any
               Value of the argument

           Examples
           --------
           >>> alg = gdal.Algorithm("raster convert")
           >>> alg["output"].GetName()
           ''
           >>> alg["output"].GetDataset()
        """

        if self.HasSubAlgorithms():
            subalg = self.InstantiateSubAlgorithm(key.replace('_', '-'))
            if not subalg:
                raise RuntimeError(f"'{key}' is not a valid sub-algorithm of '{self.GetName()}'")
            return subalg
        else:
            actual_alg = self.GetActualAlgorithm()
            arg = actual_alg.GetArg(key.replace('_', '-'))
            if not arg:
                raise RuntimeError(f"'{key}' is not a valid argument of '{actual_alg.GetName()}'")
            return arg.Get()


    def __setitem__(self, key, value):
        """Set the value of an argument.

           Shortcut for self.GetArg(key).Set(value)

           Parameters
           ----------
           key : str
               Name of a known argument of the algorithm
           value : any
               Value of the argument

           Examples
           --------
           >>> alg = gdal.Algorithm("vector clip")
           >>> alg["bbox"] = [2, 49, 3, 50]

           >>> alg = gdal.Algorithm("vector filter")
           >>> alg["where"] = "country = 'France'"

           >>> alg = gdal.Algorithm("raster reproject")
           >>> alg["input"] = "byte.tif"
           >>> alg["input"] = gdal.Open("byte.tif")
           >>> alg["target-aligned-pixels"] = True

           >>> # Multiple input datasets
           >>> alg = gdal.Algorithm("raster mosaic")
           >>> alg["input"] = ["one.tif", "two.tif"]
           >>> one_ds = gdal.Open("byte.tif")
           >>> two_ds = gdal.Open("byte.tif")
           >>> alg["input"] = [one_ds, two_ds]
        """

        arg = self.GetArgNonConst(key.replace('_', '-'))
        if not arg:
            raise RuntimeError(f"'{key}' is not a valid argument of '{self.GetName()}'")
        if not arg.Set(value):
            raise RuntimeError(f"Cannot set argument '{key}' to '{value}'")


# Register Algorithm in _gdal:
_gdal.Algorithm_swigregister(Algorithm)
class AlgorithmRegistry(object):
    r"""


    Python proxy of a ``GDALAlgorithmRegistry``.
    Typically, the global algorithm registry is used (accessed via :py:func:`GetGlobalAlgorithmRegistry`.)


    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_AlgorithmRegistry

    def GetAlgNames(self, *args):
        r"""
        GetAlgNames(self) -> char **


        Return the names of available algorithms.

        Returns
        -------
        list

        Examples
        --------
        >>> gdal.GetGlobalAlgorithmRegistry().GetAlgNames()
        ['convert', 'dataset', 'info', 'mdim', 'pipeline', 'raster', 'vector', 'vsi']


        """
        return _gdal.AlgorithmRegistry_GetAlgNames(self, *args)

    def InstantiateAlg(self, *args):
        r"""
        InstantiateAlg(self, algName) -> Algorithm


        Instantiate an :py:class:`Algorithm`.

        Most useful algorithms are accessed as a sub-algorithm of another algorithm.
        For example, ``polygonize`` is a sub-algorithm of ``raster`` and can be
        instantiated by first instantiating the primary algorithm, then using
        :py:meth:`Algorithm.InstantiateSubAlgorithm`.

        Returns
        -------
        Algorithm

        Examples
        --------

        >>> alg = gdal.GetGlobalAlgorithmRegistry().InstantiateAlg('pipeline')    # or alg= gdal.Algorithm("pipeline")
        >>> alg.GetName()
        'pipeline'
        >>> alg.GetArgNames()
        ['help', 'help-doc', 'json-usage', 'config', 'quiet', 'progress', 'input', 'output', 'output-format', 'pipeline', 'output-string', 'stdout']

        >>> subalg = gdal.GetGlobalAlgorithmRegistry().InstantiateAlg('raster').InstantiateSubAlgorithm('polygonize')
        >>> subalg.GetArgNames()
        ['help', 'help-doc', 'json-usage', 'config', 'quiet', 'progress', 'input-format', 'open-option', 'input', 'output-format', 'output-open-option', 'output', 'creation-option', 'layer-creation-option', 'overwrite', 'update', 'overwrite-layer', 'append', 'output-layer', 'band', 'attribute-name', 'connect-diagonal-pixels', 'commit-interval']


        """
        return _gdal.AlgorithmRegistry_InstantiateAlg(self, *args)


    def __getitem__(self, key):
        """Instantiate an algorithm

           Shortcut for self.InstantiateAlg(key)

           Examples
           --------
           >>> gdal.GetGlobalAlgorithmRegistry()["raster"]
           <osgeo.gdal.Algorithm; proxy of <Swig Object of type 'GDALAlgorithmHS *' at 0x...> >
        """

        alg = self.InstantiateAlg(key)
        if not alg:
            raise RuntimeError(f"'{key}' is not a valid algorithm")
        return alg


# Register AlgorithmRegistry in _gdal:
_gdal.AlgorithmRegistry_swigregister(AlgorithmRegistry)
class ArgDatasetValue(object):
    r"""Proxy of C++ GDALArgDatasetValueHS class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr
    __swig_destroy__ = _gdal.delete_ArgDatasetValue

    def GetName(self, *args):
        r"""GetName(self) -> char const *"""
        return _gdal.ArgDatasetValue_GetName(self, *args)

    def GetDataset(self, *args):
        r"""GetDataset(self) -> Dataset"""
        return _gdal.ArgDatasetValue_GetDataset(self, *args)

    def SetName(self, *args):
        r"""SetName(self, name)"""
        return _gdal.ArgDatasetValue_SetName(self, *args)

    def SetDataset(self, *args):
        r"""SetDataset(self, ds)"""
        return _gdal.ArgDatasetValue_SetDataset(self, *args)

# Register ArgDatasetValue in _gdal:
_gdal.ArgDatasetValue_swigregister(ArgDatasetValue)

def ApplyGeoTransform(*args):
    r"""
    ApplyGeoTransform(padfGeoTransform, dfPixel, dfLine)


    Apply a geotransform to convert a (col, row) location
    into a georeferenced (x, y) coordinate. To perform the
    inverse transformation, see :py:func:`InvGeoTransform`.

    See :cpp:func:`GDALApplyGeoTransform`.

    Parameters
    ----------
    gt : tuple
       Geotransform array, as described in :ref:`geotransforms_tut`.
    dfPixel : float
       (Fractional) column in image coordinates (0.0 at the left edge of the image)
    dfLine : float
       (Fractional) row in image coordinates (0.0 at the top of the image)

    Returns
    -------
    List
       x, y values corresponding to the input location

    Examples
    --------
    >>> ds = gdal.Open('byte.tif')
    >>> gt = ds.GetGeoTransform()
    >>> gdal.ApplyGeoTransform(gt, 5, 7)
    [441020.0, 3750900.0]


    """
    return _gdal.ApplyGeoTransform(*args)

def InvGeoTransform(*args):
    r"""
    InvGeoTransform(gt_in) -> RETURN_NONE


    Invert a geotransform array so that it represents a conversion
    from georeferenced (x, y) coordinates to image (col, row) coordinates.

    Parameters
    ----------
    gt : tuple
       Geotransform array, as described in :ref:`geotransforms_tut`.

    Returns
    -------
    tuple
       Geotransform array representing the inverse transformation

    Examples
    --------
    >>> ds = gdal.Open('byte.tif')
    >>> inv_gt = gdal.InvGeoTransform(ds.GetGeoTransform())
    >>> inv_gt
    (-7345.333333333333, 0.016666666666666666, 0.0, 62522.0, 0.0, -0.016666666666666666)
    >>> gdal.ApplyGeoTransform(inv_gt, 441020, 3750900)
    [5.0, 7.0]


    """
    return _gdal.InvGeoTransform(*args)

def ApplyHomography(*args):
    r"""ApplyHomography(padfHomography, dfPixel, dfLine) -> int"""
    return _gdal.ApplyHomography(*args)

def InvHomography(*args):
    r"""InvHomography(h_in) -> RETURN_NONE"""
    return _gdal.InvHomography(*args)

def VersionInfo(*args):
    r"""VersionInfo(request="VERSION_NUM") -> char const *"""
    return _gdal.VersionInfo(*args)

def AllRegister(*args):
    r"""
    AllRegister()


    Register all known configured GDAL drivers.
    Automatically called when the :py:mod:`gdal` module is loaded.
    Does not need to be called in user code unless a driver was
    deregistered and needs to be re-registered.
    See :cpp:func:`GDALAllRegister`.

    See Also
    --------
    :py:func:`Driver.Register`

    """
    return _gdal.AllRegister(*args)

def GDALDestroyDriverManager(*args):
    r"""GDALDestroyDriverManager()"""
    return _gdal.GDALDestroyDriverManager(*args)

def ClearMemoryCaches(*args):
    r"""ClearMemoryCaches()"""
    return _gdal.ClearMemoryCaches(*args)

def GetCacheMax(*args):
    r"""
    GetCacheMax() -> GIntBig


    Get the maximum size of the block cache.
    See :cpp:func:`GDALGetCacheMax`.

    Returns
    -------
    int
        maximum cache size in bytes

    """
    return _gdal.GetCacheMax(*args)

def GetCacheUsed(*args):
    r"""
    GetCacheUsed() -> GIntBig


    Get the number of bytes in used by the block cache.
    See :cpp:func:`GDALGetCacheUsed`.

    Returns
    -------
    int
        cache size in bytes

    """
    return _gdal.GetCacheUsed(*args)

def SetCacheMax(*args):
    r"""
    SetCacheMax(nBytes)


    Set the maximum size of the block cache.
    See :cpp:func:`GDALSetCacheMax`.

    Parameters
    ----------
    nBytes : int
        Cache size in bytes

    See Also
    --------
    :config:`GDAL_CACHEMAX`

    """
    return _gdal.SetCacheMax(*args)

def GetDataTypeSize(*args):
    r"""GetDataTypeSize(eDataType) -> int"""
    return _gdal.GetDataTypeSize(*args)

def GetDataTypeSizeBits(*args):
    r"""GetDataTypeSizeBits(eDataType) -> int"""
    return _gdal.GetDataTypeSizeBits(*args)

def GetDataTypeSizeBytes(*args):
    r"""GetDataTypeSizeBytes(eDataType) -> int"""
    return _gdal.GetDataTypeSizeBytes(*args)

def DataTypeIsComplex(*args):
    r"""DataTypeIsComplex(eDataType) -> int"""
    return _gdal.DataTypeIsComplex(*args)

def GetDataTypeName(*args):
    r"""
    GetDataTypeName(eDataType) -> char const *


    Return the name of the data type.

    Parameters
    ----------
    eDataType : int
        data type code

    Returns
    -------
    str

    Examples
    --------
    >>> gdal.GetDataTypeName(gdal.GDT_Int16)
    'Int16'
    >>> gdal.GetDataTypeName(gdal.GDT_Float64)
    'Float64'

    """
    return _gdal.GetDataTypeName(*args)

def GetDataTypeByName(*args):
    r"""
    GetDataTypeByName(pszDataTypeName) -> GDALDataType


    Return the data type for a given name.

    Parameters
    ----------
    pszDataTypeName : str
        data type name

    Returns
    -------
    int
        data type code

    Examples
    --------
    >>> gdal.GetDataTypeByName('Int16') == gdal.GDT_Int16
    True


    """
    return _gdal.GetDataTypeByName(*args)

def DataTypeUnion(*args):
    r"""DataTypeUnion(a, b) -> GDALDataType"""
    return _gdal.DataTypeUnion(*args)

def DataTypeUnionWithValue(*args):
    r"""DataTypeUnionWithValue(a, val, isComplex) -> GDALDataType"""
    return _gdal.DataTypeUnionWithValue(*args)

def GetColorInterpretationName(*args):
    r"""GetColorInterpretationName(eColorInterp) -> char const *"""
    return _gdal.GetColorInterpretationName(*args)

def GetColorInterpretationByName(*args):
    r"""GetColorInterpretationByName(pszColorInterpName) -> GDALColorInterp"""
    return _gdal.GetColorInterpretationByName(*args)

def GetPaletteInterpretationName(*args):
    r"""GetPaletteInterpretationName(ePaletteInterp) -> char const *"""
    return _gdal.GetPaletteInterpretationName(*args)

def DecToDMS(*args):
    r"""DecToDMS(arg1, arg2, arg3=2) -> char const *"""
    return _gdal.DecToDMS(*args)

def PackedDMSToDec(*args):
    r"""PackedDMSToDec(dfPacked) -> double"""
    return _gdal.PackedDMSToDec(*args)

def DecToPackedDMS(*args):
    r"""DecToPackedDMS(dfDec) -> double"""
    return _gdal.DecToPackedDMS(*args)

def ParseXMLString(*args):
    r"""ParseXMLString(pszXMLString) -> CPLXMLNode *"""
    return _gdal.ParseXMLString(*args)

def SerializeXMLTree(*args):
    r"""SerializeXMLTree(xmlnode) -> retStringAndCPLFree *"""
    return _gdal.SerializeXMLTree(*args)

def GetJPEG2000Structure(*args):
    r"""GetJPEG2000Structure(path, options=None) -> CPLXMLNode *"""
    return _gdal.GetJPEG2000Structure(*args)

def GetJPEG2000StructureAsString(*args):
    r"""GetJPEG2000StructureAsString(path, options=None) -> retStringAndCPLFree *"""
    return _gdal.GetJPEG2000StructureAsString(*args)

def HasTriangulation(*args):
    r"""HasTriangulation() -> int"""
    return _gdal.HasTriangulation(*args)

def GetDriverCount(*args):
    r"""
    GetDriverCount() -> int


    Return the number of registered drivers.
    See :cpp:func:`GDALGetDriverCount`.

    Examples
    --------

    .. testsetup::
        >>> pytest.skip()

    >>> gdal.GetDriverCount()
    >>> 124
    >>> gdal.GetDriverByName('MapInfo File').Deregister()
    >>> gdal.GetDriverCount()
    >>> 123

    """
    return _gdal.GetDriverCount(*args)

def GetDriverByName(*args):
    r"""GetDriverByName(name) -> Driver"""

    from . import gdal


    return _gdal.GetDriverByName(*args)

def GetDriver(*args):
    r"""GetDriver(i) -> Driver"""

    from . import gdal


    return _gdal.GetDriver(*args)

def Open(*args):
    r"""
    Open(path, eAccess=GA_ReadOnly) -> Dataset


    Opens a raster file as a :py:class:`Dataset` using default options.
    See :cpp:func:`GDALOpen`.
    For more control over how the file is opened, use :py:func:`OpenEx`.

    Parameters
    ----------
    path : str
        name of the file to open
    eAccess : int, default = :py:const:`gdal.GA_ReadOnly`

    Returns
    -------
    Dataset or None
        A dataset if successful, or ``None`` on failure.

    See Also
    --------
    :py:func:`OpenEx`
    :py:func:`OpenShared`


    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()
    from . import gdal


    return _gdal.Open(*args)

def OpenEx(*args, **kwargs):
    r"""
    OpenEx(path, nOpenFlags=0, allowed_drivers=None, open_options=None, sibling_files=None) -> Dataset


    Open a raster or vector file as a :py:class:`Dataset`.
    See :cpp:func:`GDALOpenEx`.

    Parameters
    ----------
    path : str
        name of the file to open
    flags : int
            Flags controlling how the Dataset is opened. Multiple ``gdal.OF_XXX`` flags
            may be combined using the ``|`` operator. See :cpp:func:`GDALOpenEx`.
    allowed_drivers : list, optional
            A list of the names of drivers that may attempt to open the dataset.
    open_options : dict or list, optional
            A dict or list of name=value driver-specific opening options.
    sibling_files : list, optional
            A list of filenames that are auxiliary to the main filename

    Returns
    -------
    Dataset or None
        A dataset if successful, or ``None`` on failure.

    See Also
    --------
    :py:func:`Open`
    :py:func:`OpenShared`


    """

    _WarnIfUserHasNotSpecifiedIfUsingExceptions()


    return _gdal.OpenEx(*args, **kwargs)

def OpenShared(*args):
    r"""
    OpenShared(path, eAccess=GA_ReadOnly) -> Dataset


    Open a raster file as a :py:class:`Dataset`. If the file has already been
    opened in the current thread, return a reference to the already-opened
    :py:class:`Dataset`.  See :cpp:func:`GDALOpenShared`.

    Parameters
    ----------
    path : str
        name of the file to open
    eAccess : int, default = :py:const:`gdal.GA_ReadOnly`

    Returns
    -------
    Dataset or None
        A dataset if successful, or ``None`` on failure.

    See Also
    --------
    :py:func:`Open`
    :py:func:`OpenEx`


    """

    from . import gdal


    return _gdal.OpenShared(*args)

def IdentifyDriver(*args):
    r"""IdentifyDriver(path, papszSiblings=None) -> Driver"""
    return _gdal.IdentifyDriver(*args)

def IdentifyDriverEx(*args, **kwargs):
    r"""IdentifyDriverEx(path, nIdentifyFlags=0, allowed_drivers=None, sibling_files=None) -> Driver"""
    return _gdal.IdentifyDriverEx(*args, **kwargs)

def GeneralCmdLineProcessor(*args):
    r"""GeneralCmdLineProcessor(papszArgv, nOptions=0) -> char **"""

    import os
    for i in range(len(args[0])):
        if isinstance(args[0][i], (os.PathLike, int)):
            args[0][i] = str(args[0][i])


    return _gdal.GeneralCmdLineProcessor(*args)

__version__ = _gdal.VersionInfo("RELEASE_NAME")

class GDALInfoOptions(object):
    r"""Proxy of C++ GDALInfoOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALInfoOptions"""
        _gdal.GDALInfoOptions_swiginit(self, _gdal.new_GDALInfoOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALInfoOptions

# Register GDALInfoOptions in _gdal:
_gdal.GDALInfoOptions_swigregister(GDALInfoOptions)

def InfoInternal(*args):
    r"""InfoInternal(hDataset, infoOptions) -> retStringAndCPLFree *"""
    return _gdal.InfoInternal(*args)
class GDALVectorInfoOptions(object):
    r"""Proxy of C++ GDALVectorInfoOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALVectorInfoOptions"""
        _gdal.GDALVectorInfoOptions_swiginit(self, _gdal.new_GDALVectorInfoOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALVectorInfoOptions

# Register GDALVectorInfoOptions in _gdal:
_gdal.GDALVectorInfoOptions_swigregister(GDALVectorInfoOptions)

def VectorInfoInternal(*args):
    r"""VectorInfoInternal(hDataset, infoOptions) -> retStringAndCPLFree *"""
    return _gdal.VectorInfoInternal(*args)
class GDALMultiDimInfoOptions(object):
    r"""Proxy of C++ GDALMultiDimInfoOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALMultiDimInfoOptions"""
        _gdal.GDALMultiDimInfoOptions_swiginit(self, _gdal.new_GDALMultiDimInfoOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALMultiDimInfoOptions

# Register GDALMultiDimInfoOptions in _gdal:
_gdal.GDALMultiDimInfoOptions_swigregister(GDALMultiDimInfoOptions)

def MultiDimInfoInternal(*args):
    r"""MultiDimInfoInternal(hDataset, infoOptions) -> retStringAndCPLFree *"""
    return _gdal.MultiDimInfoInternal(*args)
class GDALTranslateOptions(object):
    r"""Proxy of C++ GDALTranslateOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALTranslateOptions"""
        _gdal.GDALTranslateOptions_swiginit(self, _gdal.new_GDALTranslateOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALTranslateOptions

# Register GDALTranslateOptions in _gdal:
_gdal.GDALTranslateOptions_swigregister(GDALTranslateOptions)

def TranslateInternal(*args):
    r"""TranslateInternal(dest, dataset, translateOptions, callback=0, callback_data=None) -> Dataset"""
    return _gdal.TranslateInternal(*args)
class GDALWarpAppOptions(object):
    r"""Proxy of C++ GDALWarpAppOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALWarpAppOptions"""
        _gdal.GDALWarpAppOptions_swiginit(self, _gdal.new_GDALWarpAppOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALWarpAppOptions

# Register GDALWarpAppOptions in _gdal:
_gdal.GDALWarpAppOptions_swigregister(GDALWarpAppOptions)

def wrapper_GDALWarpDestDS(*args):
    r"""wrapper_GDALWarpDestDS(dstDS, object_list_count, warpAppOptions, callback=0, callback_data=None) -> int"""
    return _gdal.wrapper_GDALWarpDestDS(*args)

def wrapper_GDALWarpDestName(*args):
    r"""wrapper_GDALWarpDestName(dest, object_list_count, warpAppOptions, callback=0, callback_data=None) -> Dataset"""
    return _gdal.wrapper_GDALWarpDestName(*args)
class GDALVectorTranslateOptions(object):
    r"""Proxy of C++ GDALVectorTranslateOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALVectorTranslateOptions"""
        _gdal.GDALVectorTranslateOptions_swiginit(self, _gdal.new_GDALVectorTranslateOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALVectorTranslateOptions

# Register GDALVectorTranslateOptions in _gdal:
_gdal.GDALVectorTranslateOptions_swigregister(GDALVectorTranslateOptions)

def wrapper_GDALVectorTranslateDestDS(*args):
    r"""wrapper_GDALVectorTranslateDestDS(dstDS, srcDS, options, callback=0, callback_data=None) -> int"""
    return _gdal.wrapper_GDALVectorTranslateDestDS(*args)

def wrapper_GDALVectorTranslateDestName(*args):
    r"""wrapper_GDALVectorTranslateDestName(dest, srcDS, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.wrapper_GDALVectorTranslateDestName(*args)
class GDALDEMProcessingOptions(object):
    r"""Proxy of C++ GDALDEMProcessingOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALDEMProcessingOptions"""
        _gdal.GDALDEMProcessingOptions_swiginit(self, _gdal.new_GDALDEMProcessingOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALDEMProcessingOptions

# Register GDALDEMProcessingOptions in _gdal:
_gdal.GDALDEMProcessingOptions_swigregister(GDALDEMProcessingOptions)

def DEMProcessingInternal(*args):
    r"""DEMProcessingInternal(dest, dataset, pszProcessing, pszColorFilename, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.DEMProcessingInternal(*args)
class GDALNearblackOptions(object):
    r"""Proxy of C++ GDALNearblackOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALNearblackOptions"""
        _gdal.GDALNearblackOptions_swiginit(self, _gdal.new_GDALNearblackOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALNearblackOptions

# Register GDALNearblackOptions in _gdal:
_gdal.GDALNearblackOptions_swigregister(GDALNearblackOptions)

def wrapper_GDALNearblackDestDS(*args):
    r"""wrapper_GDALNearblackDestDS(dstDS, srcDS, options, callback=0, callback_data=None) -> int"""
    return _gdal.wrapper_GDALNearblackDestDS(*args)

def wrapper_GDALNearblackDestName(*args):
    r"""wrapper_GDALNearblackDestName(dest, srcDS, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.wrapper_GDALNearblackDestName(*args)
class GDALGridOptions(object):
    r"""Proxy of C++ GDALGridOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALGridOptions"""
        _gdal.GDALGridOptions_swiginit(self, _gdal.new_GDALGridOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALGridOptions

# Register GDALGridOptions in _gdal:
_gdal.GDALGridOptions_swigregister(GDALGridOptions)

def GridInternal(*args):
    r"""GridInternal(dest, dataset, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.GridInternal(*args)
class GDALContourOptions(object):
    r"""Proxy of C++ GDALContourOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALContourOptions"""
        _gdal.GDALContourOptions_swiginit(self, _gdal.new_GDALContourOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALContourOptions

# Register GDALContourOptions in _gdal:
_gdal.GDALContourOptions_swigregister(GDALContourOptions)

def wrapper_GDALContourDestDS(*args):
    r"""wrapper_GDALContourDestDS(dstDS, srcDS, options, callback=0, callback_data=None) -> int"""
    return _gdal.wrapper_GDALContourDestDS(*args)

def wrapper_GDALContourDestName(*args):
    r"""wrapper_GDALContourDestName(dest, srcDS, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.wrapper_GDALContourDestName(*args)
class GDALRasterizeOptions(object):
    r"""Proxy of C++ GDALRasterizeOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALRasterizeOptions"""
        _gdal.GDALRasterizeOptions_swiginit(self, _gdal.new_GDALRasterizeOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALRasterizeOptions

# Register GDALRasterizeOptions in _gdal:
_gdal.GDALRasterizeOptions_swigregister(GDALRasterizeOptions)

def wrapper_GDALRasterizeDestDS(*args):
    r"""wrapper_GDALRasterizeDestDS(dstDS, srcDS, options, callback=0, callback_data=None) -> int"""
    return _gdal.wrapper_GDALRasterizeDestDS(*args)

def wrapper_GDALRasterizeDestName(*args):
    r"""wrapper_GDALRasterizeDestName(dest, srcDS, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.wrapper_GDALRasterizeDestName(*args)
class GDALFootprintOptions(object):
    r"""Proxy of C++ GDALFootprintOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALFootprintOptions"""
        _gdal.GDALFootprintOptions_swiginit(self, _gdal.new_GDALFootprintOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALFootprintOptions

# Register GDALFootprintOptions in _gdal:
_gdal.GDALFootprintOptions_swigregister(GDALFootprintOptions)

def wrapper_GDALFootprintDestDS(*args):
    r"""wrapper_GDALFootprintDestDS(dstDS, srcDS, options, callback=0, callback_data=None) -> int"""
    return _gdal.wrapper_GDALFootprintDestDS(*args)

def wrapper_GDALFootprintDestName(*args):
    r"""wrapper_GDALFootprintDestName(dest, srcDS, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.wrapper_GDALFootprintDestName(*args)
class GDALBuildVRTOptions(object):
    r"""Proxy of C++ GDALBuildVRTOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALBuildVRTOptions"""
        _gdal.GDALBuildVRTOptions_swiginit(self, _gdal.new_GDALBuildVRTOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALBuildVRTOptions

# Register GDALBuildVRTOptions in _gdal:
_gdal.GDALBuildVRTOptions_swigregister(GDALBuildVRTOptions)

def BuildVRTInternalObjects(*args):
    r"""BuildVRTInternalObjects(dest, object_list_count, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.BuildVRTInternalObjects(*args)

def BuildVRTInternalNames(*args):
    r"""BuildVRTInternalNames(dest, source_filenames, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.BuildVRTInternalNames(*args)
class GDALTileIndexOptions(object):
    r"""Proxy of C++ GDALTileIndexOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALTileIndexOptions"""
        _gdal.GDALTileIndexOptions_swiginit(self, _gdal.new_GDALTileIndexOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALTileIndexOptions

# Register GDALTileIndexOptions in _gdal:
_gdal.GDALTileIndexOptions_swigregister(GDALTileIndexOptions)

def TileIndexInternalNames(*args):
    r"""TileIndexInternalNames(dest, source_filenames, options, callback=0, callback_data=None) -> Dataset"""
    return _gdal.TileIndexInternalNames(*args)
class GDALMultiDimTranslateOptions(object):
    r"""Proxy of C++ GDALMultiDimTranslateOptions class."""

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        r"""__init__(self, options) -> GDALMultiDimTranslateOptions"""
        _gdal.GDALMultiDimTranslateOptions_swiginit(self, _gdal.new_GDALMultiDimTranslateOptions(*args))
    __swig_destroy__ = _gdal.delete_GDALMultiDimTranslateOptions

# Register GDALMultiDimTranslateOptions in _gdal:
_gdal.GDALMultiDimTranslateOptions_swigregister(GDALMultiDimTranslateOptions)

def wrapper_GDALMultiDimTranslateDestName(*args):
    r"""wrapper_GDALMultiDimTranslateDestName(dest, object_list_count, multiDimTranslateOptions, callback=0, callback_data=None) -> Dataset"""
    return _gdal.wrapper_GDALMultiDimTranslateDestName(*args)

ogr.DataSource = Dataset
ogr.Driver = Driver



def _generate_gdal_alg_methods():
    """Dynamically generates gdal.alg.{X}.{Y}.{func} methods from GDAL algorithms"""

    import copy
    import os
    import types
    import typing
    from typing import Callable, List, Union, Optional

    gdal_module = sys.modules[__name__]

    def _get_type_hint(arg, for_input):

        import sys
        if sys.version_info >= (3, 9, 0):
            pathlike = "os.PathLike[str]"
        else:
            pathlike = "os.PathLike"
        if arg.GetType() == GAAT_BOOLEAN:
            type_hint = "bool"
        elif arg.GetType() == GAAT_INTEGER:
            type_hint = "int"
        elif arg.GetType() == GAAT_INTEGER_LIST:
            type_hint = "Union[List[int], int]"
        elif arg.GetType() == GAAT_REAL:
            type_hint = "float"
        elif arg.GetType() == GAAT_REAL_LIST:
            type_hint = "Union[List[float], float]"
        elif arg.GetType() == GAAT_STRING:
            if arg.GetName() in ("input", "dataset"):
                type_hint = f"Union[str, {pathlike}]"
            else:
                type_hint = "str"
        elif arg.GetType() == GAAT_STRING_LIST:
            type_hint = "Union[List[str], dict, str]"
        elif arg.GetType() == GAAT_DATASET:
            if for_input:
                type_hint = f"Union[gdal.Dataset, str, {pathlike}]"
            else:
                type_hint = "gdal.ArgDatasetValue"
        elif arg.GetType() == GAAT_DATASET_LIST:
            type_hint = f"Union[List[gdal.Dataset], List[str], List[{pathlike}]]"
        return type_hint

    def register_alg(alg, path, parent_module):
        name = alg.GetName()
        new_path = path + [name]

        if alg.HasSubAlgorithms():
            if path:
                submodule = types.ModuleType(parent_module.__name__ + "." + name)
                submodule.__doc__ = alg.GetDescription()
                setattr(parent_module, name, submodule)
            else:
                submodule = parent_module
            for subalg in alg.GetSubAlgorithmNames():
                register_alg(alg.InstantiateSubAlgorithm(subalg), new_path, submodule)
        else:
            name_sanitized = name.replace('-', '_')
            assert name_sanitized.isidentifier()

            args = ""
            kwargs = "{"
            parameters = ""
            for pass_idx in (1, 2):
                for arg_name in alg.GetArgNames():
                    arg = alg.GetArg(arg_name)
                    if arg.IsInput() and not arg.IsHiddenForAPI():

                        names = [ arg_name ]
                        aliases = arg.GetAliases()
                        if aliases:
                            for alias in aliases:
                                if len(alias) >= 4:  # no 'if', 'of', 'abs', etc.
                                    names.append(alias)

                        is_required = (arg.IsRequired() or arg_name == "pipeline")
                        is_required_without_alias = is_required and len(names) == 1
                        if pass_idx == 1 and not is_required_without_alias:
                            continue
                        elif pass_idx == 2 and is_required_without_alias:
                            continue

                        sanitized_names = []
                        for idx, name in enumerate(names):

                            arg_name_sanitized = name.replace('-', '_')
                            if arg_name_sanitized[0:1].isdigit():
                                arg_name_sanitized = '_' + arg_name_sanitized

                            assert arg_name_sanitized.isidentifier()
                            sanitized_names.append(arg_name_sanitized)

                            if idx == 0:
                                if args:
                                    args += ", "
                                    kwargs += ", "

                                args += arg_name_sanitized
                                type_hint = _get_type_hint(arg, for_input=True)
                                if not is_required:
                                    type_hint = f"Optional[{type_hint}]=None"
                                    args += f": {type_hint}"
                                else:
                                    if len(names) > 1:
                                        args += f": Optional[{type_hint}]=None"
                                    else:
                                        args += f": {type_hint}"

                                kwargs += f'"{arg_name_sanitized}": {arg_name_sanitized}'

                        parameters += "       "
                        parameters += sanitized_names[0]
                        parameters += ": "
                        parameters += type_hint
                        parameters += "\n"
                        if len(sanitized_names) > 1:
                            parameters += "       "
                            parameters += "    Aliases: "
                            parameters += ", ".join(sanitized_names[1:])
                            parameters += "\n"
                        parameters += "       "
                        parameters += "    "
                        parameters += arg.GetDescription()
                        parameters += "\n"

            if args:
                args += ", "
                kwargs += ", "
            args += "progress: Optional[Callable[[float, str, object], bool]]=None"
            kwargs += '"progress": progress'
            parameters += "       "
            parameters += "progress"
            parameters += ": "
            parameters += "Optional[Callable[[float, str, object], bool]]=None"
            parameters += "\n"
            parameters += "       "
            parameters += "    "
            parameters += "Progress callback"
            parameters += "\n"

            kwargs += "}"

            output_parameters = ""
            for arg_name in alg.GetArgNames():
                arg = alg.GetArg(arg_name)
                if arg.IsOutput() and not arg.IsHiddenForAPI():

                    arg_name_sanitized = arg_name.replace('-', '_')
                    if arg_name_sanitized[0:1].isdigit():
                        arg_name_sanitized = '_' + arg_name_sanitized

                    assert arg_name_sanitized.isidentifier()

                    output_parameters += "       "
                    output_parameters += arg_name_sanitized
                    output_parameters += ": "
                    output_parameters += _get_type_hint(arg, for_input=False)
                    output_parameters += "\n"
                    output_parameters += "       "
                    output_parameters += "    "
                    output_parameters += arg.GetDescription()
                    output_parameters += "\n"


            func_code = f"""
def {name_sanitized}({args}, **kwargs):
    new_kwargs = {kwargs}
    new_kwargs = {{k: v for k, v in new_kwargs.items() if v is not None}}
    new_kwargs.update(kwargs)
    return gdal.Run({new_path}, **new_kwargs)
"""
            func_globals = copy.copy(parent_module.__dict__)
            extra = {"gdal": gdal_module, "os": os, "List": List, "Union": Union, "Optional": Optional, "Callable": Callable}
            for k,v in extra.items():
                func_globals[k] = v
            exec(func_code, func_globals)

            parent_module.__dict__[name_sanitized] = func_globals[name_sanitized]

# Register doc string
            parent_module.__dict__[name_sanitized].__doc__ = f"""{alg.GetDescription()}

       Consult {alg.GetHelpFullURL()} for more details.

       Parameters
       ----------
{parameters}

       Output parameters
       -----------------
{output_parameters}
"""

#  Module that lazily registers its submodules and methods
    class GdalAlgLazyModule(types.ModuleType):
        """Root module to access GDAL algorithms"""
        _registered_algs = False

        def _register_algs(self):
            if not self._registered_algs:
                self._registered_algs = True
                reg = _gdal.GetGlobalAlgorithmRegistry()
                register_alg(reg.InstantiateAlg("gdal"), [], alg)

        def __getattribute__(self, name):
            if name not in ("_registered_algs", "_register_algs") and not object.__getattribute__(self, "_registered_algs"):
                self._register_algs()
            return object.__getattribute__(self, name)

        def __dir__(self):
            if not self._registered_algs:
                self._register_algs()
            return list(super().__dir__())

# Registers gdal.alg module
    gdal_module.alg = GdalAlgLazyModule("gdal.alg")

_generate_gdal_alg_methods()

def reregister_gdal_alg():
    """Destroys current gdal.alg module and recreates it"""

    delattr(sys.modules[__name__], "alg")
    _generate_gdal_alg_methods()



