Commit cb9f71dd authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #18640 -- Allowed access to GDAL Feature without Datasource

Thanks Justin Bronn for improving my initial patch.
parent 35e8dc51
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
@@ -16,15 +16,21 @@ from django.utils.six.moves import xrange
#
# The OGR_F_* routines are relevant here.
class Feature(GDALBase):
    "A class that wraps an OGR Feature, needs to be instantiated from a Layer object."
    """
    This class that wraps an OGR Feature, needs to be instantiated
    from a Layer object.
    """

    #### Python 'magic' routines ####
    def __init__(self, feat, fdefn):
        "Initializes on the pointers for the feature and the layer definition."
        if not feat or not fdefn:
    def __init__(self, feat, layer):
        """
        Initializes on the feature pointers for the feature and the layer
        definition, as well as the Layer.
        """
        if not feat:
            raise OGRException('Cannot create OGR Feature, invalid pointer given.')
        self.ptr = feat
        self._fdefn = fdefn
        self._layer = layer

    def __del__(self):
        "Releases a reference to this object."
@@ -43,7 +49,7 @@ class Feature(GDALBase):
            if index < 0 or index > self.num_fields:
                raise OGRIndexError('index out of range')
            i = index
        return Field(self.ptr, i)
        return Field(self, i)

    def __iter__(self):
        "Iterates over each field in the Feature."
@@ -71,7 +77,7 @@ class Feature(GDALBase):
    @property
    def layer_name(self):
        "Returns the name of the layer for the feature."
        return capi.get_feat_name(self._fdefn)
        return capi.get_feat_name(self._layer._ldefn)

    @property
    def num_fields(self):
@@ -81,7 +87,7 @@ class Feature(GDALBase):
    @property
    def fields(self):
        "Returns a list of fields in the Feature."
        return [capi.get_field_name(capi.get_field_defn(self._fdefn, i))
        return [capi.get_field_name(capi.get_field_defn(self._layer._ldefn, i))
                for i in xrange(self.num_fields)]

    @property
@@ -94,7 +100,7 @@ class Feature(GDALBase):
    @property
    def geom_type(self):
        "Returns the OGR Geometry Type for this Feture."
        return OGRGeomType(capi.get_fd_geom_type(self._fdefn))
        return OGRGeomType(capi.get_fd_geom_type(self._layer._ldefn))

    #### Feature Methods ####
    def get(self, field):
+12 −8
Original line number Diff line number Diff line
@@ -9,12 +9,15 @@ from django.contrib.gis.gdal.prototypes import ds as capi
#
# The OGR_Fld_* routines are relevant here.
class Field(GDALBase):
    "A class that wraps an OGR Field, needs to be instantiated from a Feature object."
    """
    This class wraps an OGR Field, and needs to be instantiated
    from a Feature object.
    """

    #### Python 'magic' routines ####
    def __init__(self, feat, index):
        """
        Initializes on the feature pointer and the integer index of
        Initializes on the feature object and the integer index of
        the field within the feature.
        """
        # Setting the feature pointer and index.
@@ -22,7 +25,7 @@ class Field(GDALBase):
        self._index = index

        # Getting the pointer for this field.
        fld_ptr = capi.get_feat_field_defn(feat, index)
        fld_ptr = capi.get_feat_field_defn(feat.ptr, index)
        if not fld_ptr:
            raise OGRException('Cannot create OGR Field, invalid pointer given.')
        self.ptr = fld_ptr
@@ -42,20 +45,21 @@ class Field(GDALBase):
    #### Field Methods ####
    def as_double(self):
        "Retrieves the Field's value as a double (float)."
        return capi.get_field_as_double(self._feat, self._index)
        return capi.get_field_as_double(self._feat.ptr, self._index)

    def as_int(self):
        "Retrieves the Field's value as an integer."
        return capi.get_field_as_integer(self._feat, self._index)
        return capi.get_field_as_integer(self._feat.ptr, self._index)

    def as_string(self):
        "Retrieves the Field's value as a string."
        return capi.get_field_as_string(self._feat, self._index)
        return capi.get_field_as_string(self._feat.ptr, self._index)

    def as_datetime(self):
        "Retrieves the Field's value as a tuple of date & time components."
        yy, mm, dd, hh, mn, ss, tz = [c_int() for i in range(7)]
        status = capi.get_field_as_datetime(self._feat, self._index, byref(yy), byref(mm), byref(dd),
        status = capi.get_field_as_datetime(
            self._feat.ptr, self._index, byref(yy), byref(mm), byref(dd),
            byref(hh), byref(mn), byref(ss), byref(tz))
        if status:
            return (yy, mm, dd, hh, mn, ss, tz)
+2 −2
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ class Layer(GDALBase):
        # ResetReading() must be called before iteration is to begin.
        capi.reset_reading(self._ptr)
        for i in xrange(self.num_feat):
            yield Feature(capi.get_next_feature(self._ptr), self._ldefn)
            yield Feature(capi.get_next_feature(self._ptr), self)

    def __len__(self):
        "The length is the number of features."
@@ -81,7 +81,7 @@ class Layer(GDALBase):
        if self._random_read:
            # If the Layer supports random reading, return.
            try:
                return Feature(capi.get_feature(self.ptr, feat_id), self._ldefn)
                return Feature(capi.get_feature(self.ptr, feat_id), self)
            except OGRException:
                pass
        else:
+7 −1
Original line number Diff line number Diff line
@@ -125,7 +125,10 @@ class DataSourceTest(unittest.TestCase):
            self.assertEqual(control_vals, test_vals)

    def test03c_layer_references(self):
        "Test to make sure Layer access is still available without the DataSource."
        """
        Test to make sure Layer/Feature access is still available without
        the DataSource/Feature.
        """
        source = ds_list[0]

        # See ticket #9448.
@@ -141,6 +144,9 @@ class DataSourceTest(unittest.TestCase):
        self.assertEqual(source.nfeat, len(lyr))
        self.assertEqual(source.gtype, lyr.geom_type.num)

        # Same issue for Feature/Field objects, see #18640
        self.assertEqual(str(lyr[0]['str']), "1")

    def test04_features(self):
        "Testing Data Source Features."
        for source in ds_list: