Skip to content

Commit

Permalink
Fixed django#18640 -- Allowed access to GDAL Feature without Datasource
Browse files Browse the repository at this point in the history
Thanks Justin Bronn for improving my initial patch.
  • Loading branch information
claudep committed Oct 7, 2012
1 parent 35e8dc5 commit cb9f71d
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 20 deletions.
24 changes: 15 additions & 9 deletions django/contrib/gis/gdal/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@
#
# 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."
Expand All @@ -43,7 +49,7 @@ def __getitem__(self, index):
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."
Expand Down Expand Up @@ -71,7 +77,7 @@ def fid(self):
@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):
Expand All @@ -81,7 +87,7 @@ def num_fields(self):
@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
Expand All @@ -94,7 +100,7 @@ def geom(self):
@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):
Expand Down
20 changes: 12 additions & 8 deletions django/contrib/gis/gdal/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@
#
# 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.
self._feat = feat
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
Expand All @@ -42,21 +45,22 @@ def __str__(self):
#### 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),
byref(hh), byref(mn), byref(ss), byref(tz))
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)
else:
Expand Down
4 changes: 2 additions & 2 deletions django/contrib/gis/gdal/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __iter__(self):
# 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."
Expand All @@ -81,7 +81,7 @@ def _make_feature(self, feat_id):
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:
Expand Down
8 changes: 7 additions & 1 deletion django/contrib/gis/gdal/tests/test_ds.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ def test03b_layer_slice(self):
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.
Expand All @@ -141,6 +144,9 @@ def get_layer():
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:
Expand Down

0 comments on commit cb9f71d

Please sign in to comment.