From 44069054d72ec5037a4032e890ba31b2f147f065 Mon Sep 17 00:00:00 2001 From: Justin Bronn Date: Mon, 2 Jul 2007 23:47:40 +0000 Subject: [PATCH] gis: fixed ticket 4740 with the addition of new exceptions; updated tests for prev change in Field; added get() method to Feature; fixed bug in Layer for geometries w/o srs; SpatialRefSys now uses ellipsoid git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@5587 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/gis/gdal/Feature.py | 4 ++++ django/contrib/gis/gdal/Layer.py | 9 +++++++-- django/contrib/gis/gdal/OGRGeometry.py | 14 +++++++++++--- django/contrib/gis/geos/GEOSGeometry.py | 17 ++++++++++++----- django/contrib/gis/models.py | 9 +++------ django/contrib/gis/tests/test_gdal_ds.py | 6 ++++-- 6 files changed, 41 insertions(+), 18 deletions(-) diff --git a/django/contrib/gis/gdal/Feature.py b/django/contrib/gis/gdal/Feature.py index 03d97f304e..2e607cb3a6 100644 --- a/django/contrib/gis/gdal/Feature.py +++ b/django/contrib/gis/gdal/Feature.py @@ -93,6 +93,10 @@ class Feature(object): return OGRGeomType(lgdal.OGR_FD_GetGeomType(self._fdefn)) #### Feature Methods #### + def get(self, field_name): + "Returns the value of the field, instead of an instance of the Field object." + return self.__getitem__(field_name).value + def index(self, field_name): "Returns the index of the given field name." i = lgdal.OGR_F_GetFieldIndex(self._feat, c_char_p(field_name)) diff --git a/django/contrib/gis/gdal/Layer.py b/django/contrib/gis/gdal/Layer.py index 0ea3560a3c..2f6b07905d 100644 --- a/django/contrib/gis/gdal/Layer.py +++ b/django/contrib/gis/gdal/Layer.py @@ -7,6 +7,7 @@ from django.contrib.gis.gdal.libgdal import lgdal # Other GDAL imports. from django.contrib.gis.gdal.Envelope import Envelope, OGREnvelope from django.contrib.gis.gdal.Feature import Feature +from django.contrib.gis.gdal.OGRGeometry import OGRGeomType from django.contrib.gis.gdal.OGRError import OGRException, check_err from django.contrib.gis.gdal.SpatialReference import SpatialReference @@ -83,12 +84,16 @@ class Layer(object): @property def geom_type(self): "Returns the geometry type (OGRGeomType) of the Layer." - return lgdal.OGR_FD_GetGeomType(self._ldefn) + return OGRGeomType(lgdal.OGR_FD_GetGeomType(self._ldefn)) @property def srs(self): "Returns the Spatial Reference used in this Layer." - return SpatialReference(lgdal.OSRClone(lgdal.OGR_L_GetSpatialRef(self._layer)), 'ogr') + ptr = lgdal.OGR_L_GetSpatialRef(self._layer) + if ptr: + srs = SpatialReference(lgdal.OSRClone(ptr), 'ogr') + else: + return None @property def fields(self): diff --git a/django/contrib/gis/gdal/OGRGeometry.py b/django/contrib/gis/gdal/OGRGeometry.py index 4296989036..5a7b0b2480 100644 --- a/django/contrib/gis/gdal/OGRGeometry.py +++ b/django/contrib/gis/gdal/OGRGeometry.py @@ -131,6 +131,14 @@ class OGRGeomType(object): return self.__ogr_int[self._index] #### OGRGeometry Class #### +class OGRGeometryIndexError(OGRException, KeyError): + """This exception is raised when an invalid index is encountered, and has + the 'silent_variable_feature' attribute set to true. This ensures that + django's templates proceed to use the next lookup type gracefully when + an Exception is raised. Fixes ticket #4740. + """ + silent_variable_failure = True + class OGRGeometry(object): "Generally encapsulates an OGR geometry." @@ -412,7 +420,7 @@ class LineString(OGRGeometry): elif self.coord_dim == 3: return (x.value, y.value, z.value) else: - raise IndexError, 'index out of range' + raise OGRGeometryIndexError, 'index out of range: %s' % str(index) def __iter__(self): "Iterates over each point in the LineString." @@ -445,7 +453,7 @@ class Polygon(OGRGeometry): def __getitem__(self, index): "Gets the ring at the specified index." if index < 0 or index >= self.geom_count: - raise IndexError, 'index out of range' + raise OGRGeometryIndexError, 'index out of range: %s' % str(index) else: return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index)))) @@ -481,7 +489,7 @@ class GeometryCollection(OGRGeometry): def __getitem__(self, index): "Gets the Geometry at the specified index." if index < 0 or index >= self.geom_count: - raise IndexError, 'index out of range' + raise OGRGeometryIndexError, 'index out of range: %s' % str(index) else: return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index)))) diff --git a/django/contrib/gis/geos/GEOSGeometry.py b/django/contrib/gis/geos/GEOSGeometry.py index e710e228d3..d3ad0b5e2a 100644 --- a/django/contrib/gis/geos/GEOSGeometry.py +++ b/django/contrib/gis/geos/GEOSGeometry.py @@ -85,6 +85,13 @@ else: # The GEOSException class class GEOSException(Exception): pass +class GEOSGeometryIndexError(GEOSException, KeyError): + """This exception is raised when an invalid index is encountered, and has + the 'silent_variable_feature' attribute set to true. This ensures that + django's templates proceed to use the next lookup type gracefully when + an Exception is raised. Fixes ticket #4740. + """ + silent_variable_failure = True # Getting the GEOS C library. The C interface (CDLL) is used for # both *NIX and Windows. @@ -345,7 +352,7 @@ class GEOSGeometry(object): @property def envelope(self): - "Return the geometries bounding box." + "Return the envelope for this geometry (a polygon)." return GEOSGeometry(lgeos.GEOSEnvelope(self._g)) @property @@ -432,7 +439,7 @@ class GEOSCoordSeq(object): "Checks the index." sz = self.size if (sz < 1) or (index < 0) or (index >= sz): - raise IndexError, 'index out of range' + raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index) def _checkdim(self, dim): "Checks the given dimension." @@ -594,7 +601,7 @@ class LineString(GEOSGeometry): "Gets the point at the specified index." self._cache_cs() if index < 0 or index >= self._cs.size: - raise IndexError, 'index out of range' + raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index) else: return self._cs[index] @@ -624,7 +631,7 @@ class Polygon(GEOSGeometry): """Returns the ring at the specified index. The first index, 0, will always return the exterior ring. Indices > 0 will return the interior ring.""" if index < 0 or index > self.num_interior_rings: - raise IndexError, 'index out of range' + raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index) else: if index == 0: return self.exterior_ring @@ -687,7 +694,7 @@ class GeometryCollection(GEOSGeometry): def _checkindex(self, index): "Checks the given geometry index." if index < 0 or index >= self.num_geom: - raise IndexError, 'index out of range' + raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index) def __iter__(self): "For iteration on the multiple geometries." diff --git a/django/contrib/gis/models.py b/django/contrib/gis/models.py index 7ee8df0201..bfcd10c8f3 100644 --- a/django/contrib/gis/models.py +++ b/django/contrib/gis/models.py @@ -48,7 +48,7 @@ class SpatialRefSys(models.Model): db_table = 'spatial_ref_sys' def _cache_osr(self): - "Caches a GDAL OSR object for this Spatial Reference." + "Caches a GDAL OSR SpatialReference object for this SpatialRefSys model." if HAS_OSR: if not hasattr(self, '_srs'): # Trying to get from WKT first @@ -71,6 +71,7 @@ class SpatialRefSys(models.Model): @property def srs(self): + "Returns the SpatialReference equivalent of this model." self._cache_osr() return self._srs.clone() @@ -79,12 +80,8 @@ class SpatialRefSys(models.Model): """Returns a tuple of the ellipsoid parameters: (semimajor axis, semiminor axis, and inverse flattening).""" if HAS_OSR: - # Setting values initially to False self._cache_osr() - major = self._srs.semi_major - minor = self._srs.semi_minor - invflat = self._srs.inverse_flattening - return (major, minor, invflat) + return self._srs.ellipsoid else: m = spheroid_regex.match(self.srtext) if m: return (float(m.group('major')), float(m.group('flattening'))) diff --git a/django/contrib/gis/tests/test_gdal_ds.py b/django/contrib/gis/tests/test_gdal_ds.py index 6e6964c224..00a4e4b752 100644 --- a/django/contrib/gis/tests/test_gdal_ds.py +++ b/django/contrib/gis/tests/test_gdal_ds.py @@ -101,8 +101,10 @@ class DataSourceTest(unittest.TestCase): for k, v in source.fields.items(): fld = feat[k] # Indexing with string value - # Asserting the string representation (which asserts the type) - self.assertEqual('%s (%s)' % (k, v.__name__), str(fld)) + # Asserting the string representation, and making sure we get + # the proper OGR Field instance. + self.assertEqual('%s (%s)' % (k, fld.value), str(fld)) + self.assertEqual(True, isinstance(fld, v)) # Testing __iter__ on the Feature for fld in feat: self.assertEqual(fld.name in source.fields.keys(), True)