From f23597cdd75f4aa48d4ec1a7fcb543b3e1c1feca Mon Sep 17 00:00:00 2001 From: Justin Bronn Date: Tue, 20 Nov 2007 15:10:20 +0000 Subject: [PATCH] gis: gdal: Fixed memory leak introduced in the refactor caused by unnecessary cloning of SpatialReference objects from Features; fixed windows-compatibility issues (no error code returned by some destruction routines by windows libraries); OFTDate/Time fields return None if invalid date is encountered (thanks tlp). git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6707 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/gis/gdal/feature.py | 21 +++++++++------------ django/contrib/gis/gdal/field.py | 15 ++++++++++++--- django/contrib/gis/gdal/libgdal.py | 2 ++ django/contrib/gis/gdal/prototypes/ds.py | 4 ++-- django/contrib/gis/gdal/prototypes/geom.py | 4 ++-- django/contrib/gis/gdal/prototypes/srs.py | 9 +++++---- 6 files changed, 32 insertions(+), 23 deletions(-) diff --git a/django/contrib/gis/gdal/feature.py b/django/contrib/gis/gdal/feature.py index eeab6a8b6a..147564aed8 100644 --- a/django/contrib/gis/gdal/feature.py +++ b/django/contrib/gis/gdal/feature.py @@ -33,7 +33,12 @@ class Feature(object): if self._ptr: destroy_feature(self._ptr) def __getitem__(self, index): - "Gets the Field at the specified index." + """ + Gets the Field object at the specified index, which may be either + an integer or the Field's string label. Note that the Field object + is not the field's _value_ -- use the `get` method instead to + retrieve the value (e.g. an integer) instead of a Field instance. + """ if isinstance(index, basestring): i = self.index(index) else: @@ -86,16 +91,8 @@ class Feature(object): "Returns the OGR Geometry for this Feature." # Retrieving the geometry pointer for the feature. geom_ptr = get_feat_geom_ref(self._ptr) + return OGRGeometry(clone_geom(geom_ptr)) - # Attempting to retrieve the Spatial Reference for the geometry. - try: - srs_ptr = get_geom_srs(geom_ptr) - srs = SpatialReference(clone_srs(srs_ptr)) - except OGRException: - srs = None - # Geometry is cloned so the feature isn't invalidated. - return OGRGeometry(clone_geom(geom_ptr), srs) - @property def geom_type(self): "Returns the OGR Geometry Type for this Feture." @@ -105,8 +102,8 @@ class Feature(object): def get(self, field): """ Returns the value of the field, instead of an instance of the Field - object. May take a string of the field name or a Field object as - parameters. + object. May take a string of the field name or a Field object as + parameters. """ field_name = getattr(field, 'name', field) return self[field_name].value diff --git a/django/contrib/gis/gdal/field.py b/django/contrib/gis/gdal/field.py index 993d1d6b18..ad1feb3d22 100644 --- a/django/contrib/gis/gdal/field.py +++ b/django/contrib/gis/gdal/field.py @@ -128,7 +128,10 @@ class OFTDate(Field): def value(self): "Returns a Python `date` object for the OFTDate field." yy, mm, dd, hh, mn, ss, tz = self.as_datetime() - return date(yy.value, mm.value, dd.value) + try: + return date(yy.value, mm.value, dd.value) + except ValueError: + return None class OFTDateTime(Field): @property @@ -139,14 +142,20 @@ class OFTDateTime(Field): # See http://lists.maptools.org/pipermail/gdal-dev/2006-February/007990.html # The `tz` variable has values of: 0=unknown, 1=localtime (ambiguous), # 100=GMT, 104=GMT+1, 80=GMT-5, etc. - return datetime(yy.value, mm.value, dd.value, hh.value, mn.value, ss.value) + try: + return datetime(yy.value, mm.value, dd.value, hh.value, mn.value, ss.value) + except ValueError: + return None class OFTTime(Field): @property def value(self): "Returns a Python `time` object for this OFTTime field." yy, mm, dd, hh, mn, ss, tz = self.as_datetime() - return time(hh.value, mn.value, ss.value) + try: + return time(hh.value, mn.value, ss.value) + except ValueError: + return None # List fields are also just subclasses class OFTIntegerList(Field): pass diff --git a/django/contrib/gis/gdal/libgdal.py b/django/contrib/gis/gdal/libgdal.py index 5ebc699701..da942c9f62 100644 --- a/django/contrib/gis/gdal/libgdal.py +++ b/django/contrib/gis/gdal/libgdal.py @@ -6,6 +6,7 @@ from django.contrib.gis.gdal.error import OGRException if os.name == 'nt': # Windows NT shared library lib_name = 'libgdal-1.dll' + errcheck_flag = False elif os.name == 'posix': platform = os.uname()[0] if platform == 'Darwin': @@ -14,6 +15,7 @@ elif os.name == 'posix': else: # Attempting to use .so extension for all other platforms. lib_name = 'libgdal.so' + errcheck_flag = True else: raise OGRException('Unsupported OS "%s"' % os.name) diff --git a/django/contrib/gis/gdal/prototypes/ds.py b/django/contrib/gis/gdal/prototypes/ds.py index 1f55f4b58d..18d8e4c884 100644 --- a/django/contrib/gis/gdal/prototypes/ds.py +++ b/django/contrib/gis/gdal/prototypes/ds.py @@ -5,7 +5,7 @@ """ from ctypes import c_char_p, c_int, c_long, c_void_p, POINTER from django.contrib.gis.gdal.envelope import OGREnvelope -from django.contrib.gis.gdal.libgdal import lgdal +from django.contrib.gis.gdal.libgdal import lgdal, errcheck_flag from django.contrib.gis.gdal.prototypes.generation import \ const_string_output, double_output, geom_output, int_output, \ srs_output, void_output, voidptr_output @@ -47,7 +47,7 @@ get_field_defn = voidptr_output(lgdal.OGR_FD_GetFieldDefn, [c_void_p, c_int]) ### Feature Routines ### clone_feature = voidptr_output(lgdal.OGR_F_Clone, [c_void_p]) -destroy_feature = void_output(lgdal.OGR_F_Destroy, [c_void_p]) +destroy_feature = void_output(lgdal.OGR_F_Destroy, [c_void_p], errcheck=errcheck_flag) feature_equal = int_output(lgdal.OGR_F_Equal, [c_void_p, c_void_p]) get_feat_geom_ref = geom_output(lgdal.OGR_F_GetGeometryRef, [c_void_p]) get_feat_field_count = int_output(lgdal.OGR_F_GetFieldCount, [c_void_p]) diff --git a/django/contrib/gis/gdal/prototypes/geom.py b/django/contrib/gis/gdal/prototypes/geom.py index c3deb3aa6b..8b1167eea3 100644 --- a/django/contrib/gis/gdal/prototypes/geom.py +++ b/django/contrib/gis/gdal/prototypes/geom.py @@ -1,6 +1,6 @@ from ctypes import c_char, c_char_p, c_double, c_int, c_ubyte, c_void_p, POINTER from django.contrib.gis.gdal.envelope import OGREnvelope -from django.contrib.gis.gdal.libgdal import lgdal +from django.contrib.gis.gdal.libgdal import lgdal, errcheck_flag from django.contrib.gis.gdal.prototypes.errcheck import check_bool, check_envelope from django.contrib.gis.gdal.prototypes.generation import \ const_string_output, double_output, geom_output, int_output, \ @@ -72,7 +72,7 @@ get_geom_name = const_string_output(lgdal.OGR_G_GetGeometryName, [c_void_p]) get_geom_type = int_output(lgdal.OGR_G_GetGeometryType, [c_void_p]) get_point_count = int_output(lgdal.OGR_G_GetPointCount, [c_void_p]) get_point = void_output(lgdal.OGR_G_GetPoint, [c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double)], errcheck=False) -geom_close_rings = void_output(lgdal.OGR_G_CloseRings, [c_void_p]) +geom_close_rings = void_output(lgdal.OGR_G_CloseRings, [c_void_p], errcheck=errcheck_flag) # Topology routines. ogr_contains = topology_func(lgdal.OGR_G_Contains) diff --git a/django/contrib/gis/gdal/prototypes/srs.py b/django/contrib/gis/gdal/prototypes/srs.py index acbf9665d8..620f9558a5 100644 --- a/django/contrib/gis/gdal/prototypes/srs.py +++ b/django/contrib/gis/gdal/prototypes/srs.py @@ -1,5 +1,5 @@ from ctypes import c_char_p, c_int, c_void_p, POINTER -from django.contrib.gis.gdal.libgdal import lgdal +from django.contrib.gis.gdal.libgdal import lgdal, errcheck_flag from django.contrib.gis.gdal.prototypes.generation import \ const_string_output, double_output, int_output, \ srs_output, string_output, void_output @@ -22,8 +22,9 @@ def units_func(f): # Creation & destruction. clone_srs = srs_output(lgdal.OSRClone, [c_void_p]) new_srs = srs_output(lgdal.OSRNewSpatialReference, [c_char_p]) -release_srs = void_output(lgdal.OSRRelease, [c_void_p]) -srs_validate = void_output(lgdal.OSRValidate, [c_void_p], errcheck=True) +release_srs = void_output(lgdal.OSRRelease, [c_void_p], errcheck=errcheck_flag) +destroy_srs = void_output(lgdal.OSRDestroySpatialReference, [c_void_p], errcheck=errcheck_flag) +srs_validate = void_output(lgdal.OSRValidate, [c_void_p]) # Getting the semi_major, semi_minor, and flattening functions. semi_major = srs_double(lgdal.OSRGetSemiMajor) @@ -67,4 +68,4 @@ isprojected = int_output(lgdal.OSRIsProjected, [c_void_p]) # Coordinate transformation new_ct= srs_output(lgdal.OCTNewCoordinateTransformation, [c_void_p, c_void_p]) -destroy_ct = void_output(lgdal.OCTDestroyCoordinateTransformation, [c_void_p]) +destroy_ct = void_output(lgdal.OCTDestroyCoordinateTransformation, [c_void_p], errcheck=errcheck_flag)