for more information see the ogr c api source code https gdal orgapivectorcapi html the ogrl routines are relevant here a class that wraps an ogr layer needs to be instantiated from a datasource object initialize on an ogr c pointer to the layer and the datasource object that owns this layer the datasource object is required so that a reference to it is kept with this layer this prevents garbage collection of the datasource while this layer is still active does the layer support random reading an integer index was given we cannot do a check based on the number of features because the beginning and ending feature ids are not guaranteed to be 0 and lenlayer1 respectively a slice was given resetreading must be called before iteration is to begin helper routine for getitem that constructs a feature from the given feature id if the ogr layer does not support randomaccess reading then each feature of the layer will be incremented through until the a feature is found matching the given feature id if the layer supports random reading return random access isn t supported have to increment through each feature until the given feature id is encountered should have returned a feature raise an indexerror layer properties return a list of string names corresponding to each of the fields available in this layer return a list of the types of fields in this layer for example return the list oftinteger oftreal oftstring for an ogr layer that has an integer a floatingpoint and string fields map cdouble onto params if a bad type is passed in it will be caught here layer methods return a list containing the given field name for every feature in the layer return a list containing the ogrgeometry for every feature in the layer return a bool indicating whether the this layer supports the given capability a string valid capability strings include randomread sequentialwrite randomwrite fastspatialfilter fastfeaturecount fastgetextent createfield transactions deletefeature and fastsetnextbyindex for more information see the ogr c api source code https gdal org api vector_c_api html the ogr_l_ routines are relevant here a class that wraps an ogr layer needs to be instantiated from a datasource object initialize on an ogr c pointer to the layer and the datasource object that owns this layer the datasource object is required so that a reference to it is kept with this layer this prevents garbage collection of the datasource while this layer is still active does the layer support random reading an integer index was given we cannot do a check based on the number of features because the beginning and ending feature ids are not guaranteed to be 0 and len layer 1 respectively a slice was given resetreading must be called before iteration is to begin helper routine for __getitem__ that constructs a feature from the given feature id if the ogr layer does not support random access reading then each feature of the layer will be incremented through until the a feature is found matching the given feature id if the layer supports random reading return random access isn t supported have to increment through each feature until the given feature id is encountered should have returned a feature raise an indexerror layer properties return a list of string names corresponding to each of the fields available in this layer return a list of the types of fields in this layer for example return the list oftinteger oftreal oftstring for an ogr layer that has an integer a floating point and string fields map c_double onto params if a bad type is passed in it will be caught here layer methods return a list containing the given field name for every feature in the layer return a list containing the ogrgeometry for every feature in the layer return a bool indicating whether the this layer supports the given capability a string valid capability strings include randomread sequentialwrite randomwrite fastspatialfilter fastfeaturecount fastgetextent createfield transactions deletefeature and fastsetnextbyindex
from ctypes import byref, c_double

from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.error import GDALException, SRSException
from django.contrib.gis.gdal.feature import Feature
from django.contrib.gis.gdal.field import OGRFieldTypes
from django.contrib.gis.gdal.geometries import OGRGeometry
from django.contrib.gis.gdal.geomtype import OGRGeomType
from django.contrib.gis.gdal.prototypes import ds as capi
from django.contrib.gis.gdal.prototypes import geom as geom_api
from django.contrib.gis.gdal.prototypes import srs as srs_api
from django.contrib.gis.gdal.srs import SpatialReference
from django.utils.encoding import force_bytes, force_str






class Layer(GDALBase):
    

    def __init__(self, layer_ptr, ds):
        
        if not layer_ptr:
            raise GDALException("Cannot create Layer, invalid pointer given")
        self.ptr = layer_ptr
        self._ds = ds
        self._ldefn = capi.get_layer_defn(self._ptr)
        
        self._random_read = self.test_capability(b"RandomRead")

    def __getitem__(self, index):
        "Get the Feature at the specified index."
        if isinstance(index, int):
            
            
            
            if index < 0:
                raise IndexError("Negative indices are not allowed on OGR Layers.")
            return self._make_feature(index)
        elif isinstance(index, slice):
            
            start, stop, stride = index.indices(self.num_feat)
            return [self._make_feature(fid) for fid in range(start, stop, stride)]
        else:
            raise TypeError(
                "Integers and slices may only be used when indexing OGR Layers."
            )

    def __iter__(self):
        "Iterate over each Feature in the Layer."
        
        capi.reset_reading(self._ptr)
        for i in range(self.num_feat):
            yield Feature(capi.get_next_feature(self._ptr), self)

    def __len__(self):
        "The length is the number of features."
        return self.num_feat

    def __str__(self):
        "The string name of the layer."
        return self.name

    def _make_feature(self, feat_id):
        
        if self._random_read:
            
            try:
                return Feature(capi.get_feature(self.ptr, feat_id), self)
            except GDALException:
                pass
        else:
            
            
            for feat in self:
                if feat.fid == feat_id:
                    return feat
        
        raise IndexError("Invalid feature id: %s." % feat_id)

    
    @property
    def extent(self):
        "Return the extent (an Envelope) of this layer."
        env = OGREnvelope()
        capi.get_extent(self.ptr, byref(env), 1)
        return Envelope(env)

    @property
    def name(self):
        "Return the name of this layer in the Data Source."
        name = capi.get_fd_name(self._ldefn)
        return force_str(name, self._ds.encoding, strings_only=True)

    @property
    def num_feat(self, force=1):
        "Return the number of features in the Layer."
        return capi.get_feature_count(self.ptr, force)

    @property
    def num_fields(self):
        "Return the number of fields in the Layer."
        return capi.get_field_count(self._ldefn)

    @property
    def geom_type(self):
        "Return the geometry type (OGRGeomType) of the Layer."
        return OGRGeomType(capi.get_fd_geom_type(self._ldefn))

    @property
    def srs(self):
        "Return the Spatial Reference used in this Layer."
        try:
            ptr = capi.get_layer_srs(self.ptr)
            return SpatialReference(srs_api.clone_srs(ptr))
        except SRSException:
            return None

    @property
    def fields(self):
        
        return [
            force_str(
                capi.get_field_name(capi.get_field_defn(self._ldefn, i)),
                self._ds.encoding,
                strings_only=True,
            )
            for i in range(self.num_fields)
        ]

    @property
    def field_types(self):
        
        return [
            OGRFieldTypes[capi.get_field_type(capi.get_field_defn(self._ldefn, i))]
            for i in range(self.num_fields)
        ]

    @property
    def field_widths(self):
        "Return a list of the maximum field widths for the features."
        return [
            capi.get_field_width(capi.get_field_defn(self._ldefn, i))
            for i in range(self.num_fields)
        ]

    @property
    def field_precisions(self):
        "Return the field precisions for the features."
        return [
            capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
            for i in range(self.num_fields)
        ]

    def _get_spatial_filter(self):
        try:
            return OGRGeometry(geom_api.clone_geom(capi.get_spatial_filter(self.ptr)))
        except GDALException:
            return None

    def _set_spatial_filter(self, filter):
        if isinstance(filter, OGRGeometry):
            capi.set_spatial_filter(self.ptr, filter.ptr)
        elif isinstance(filter, (tuple, list)):
            if not len(filter) == 4:
                raise ValueError("Spatial filter list/tuple must have 4 elements.")
            
            
            xmin, ymin, xmax, ymax = map(c_double, filter)
            capi.set_spatial_filter_rect(self.ptr, xmin, ymin, xmax, ymax)
        elif filter is None:
            capi.set_spatial_filter(self.ptr, None)
        else:
            raise TypeError(
                "Spatial filter must be either an OGRGeometry instance, a 4-tuple, or "
                "None."
            )

    spatial_filter = property(_get_spatial_filter, _set_spatial_filter)

    
    def get_fields(self, field_name):
        
        if field_name not in self.fields:
            raise GDALException("invalid field name: %s" % field_name)
        return [feat.get(field_name) for feat in self]

    def get_geoms(self, geos=False):
        
        if geos:
            from django.contrib.gis.geos import GEOSGeometry

            return [GEOSGeometry(feat.geom.wkb) for feat in self]
        else:
            return [feat.geom for feat in self]

    def test_capability(self, capability):
        
        return bool(capi.test_capability(self.ptr, force_bytes(capability)))