From 2694fffcc0b8695d91c6b9d4167140721b47c5c5 Mon Sep 17 00:00:00 2001 From: Justin Bronn Date: Sun, 4 Nov 2007 00:48:10 +0000 Subject: [PATCH] gis: gdal: (1) Added the `field_widths` and `field_precision` properties to Layer with patch from tlp. (2) Field definition is now passed into the Feature from the Layer. (3) Fixed memory leak issue with Feature not being properly deleted. (4) OGR_L_GetNextFeature() now used for iteration on Layer. (5) Added the `gdal_version`, `gdal_full_version`, and `gdal_release_date` functions. (6) Made all initial pointers None instead of 0. git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6639 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/gis/gdal/__init__.py | 1 + django/contrib/gis/gdal/datasource.py | 2 +- django/contrib/gis/gdal/driver.py | 2 +- django/contrib/gis/gdal/feature.py | 16 ++++++------ django/contrib/gis/gdal/field.py | 2 +- django/contrib/gis/gdal/layer.py | 35 ++++++++++++++++++--------- django/contrib/gis/gdal/libgdal.py | 28 ++++++++++++++++++++- django/contrib/gis/gdal/srs.py | 2 +- 8 files changed, 64 insertions(+), 24 deletions(-) diff --git a/django/contrib/gis/gdal/__init__.py b/django/contrib/gis/gdal/__init__.py index cb70199f9a..32d9da73d1 100644 --- a/django/contrib/gis/gdal/__init__.py +++ b/django/contrib/gis/gdal/__init__.py @@ -26,6 +26,7 @@ try: from django.contrib.gis.gdal.driver import Driver from django.contrib.gis.gdal.datasource import DataSource + from django.contrib.gis.gdal.libgdal import gdal_version, gdal_full_version, gdal_release_date from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform from django.contrib.gis.gdal.geometries import OGRGeometry HAS_GDAL = True diff --git a/django/contrib/gis/gdal/datasource.py b/django/contrib/gis/gdal/datasource.py index cf72098808..d754821143 100644 --- a/django/contrib/gis/gdal/datasource.py +++ b/django/contrib/gis/gdal/datasource.py @@ -55,7 +55,7 @@ class DataSource(object): #### Python 'magic' routines #### def __init__(self, ds_input, ds_driver=False): - self._ds = 0 # Initially NULL + self._ds = None # Initially NULL # Registering all the drivers, this needs to be done # _before_ we try to open up a data source. diff --git a/django/contrib/gis/gdal/driver.py b/django/contrib/gis/gdal/driver.py index e56c24917c..6123bb45e3 100644 --- a/django/contrib/gis/gdal/driver.py +++ b/django/contrib/gis/gdal/driver.py @@ -27,7 +27,7 @@ class Driver(object): if isinstance(input, StringType): # If a string name of the driver was passed in - self._dr = 0 # Initially NULL + self._dr = None # Initially NULL self._register() # Checking the alias dictionary (case-insensitive) to see if an alias diff --git a/django/contrib/gis/gdal/feature.py b/django/contrib/gis/gdal/feature.py index 947d861967..dac69e2d66 100644 --- a/django/contrib/gis/gdal/feature.py +++ b/django/contrib/gis/gdal/feature.py @@ -17,18 +17,18 @@ class Feature(object): "A class that wraps an OGR Feature, needs to be instantiated from a Layer object." #### Python 'magic' routines #### - def __init__(self, f): + def __init__(self, feat, fdefn): "Needs a C pointer (Python integer in ctypes) in order to initialize." - self._feat = 0 # Initially NULL - self._fdefn = 0 - if not f: + self._feat = None # Initially NULL + self._fdefn = None + if not feat or not fdefn: raise OGRException('Cannot create OGR Feature, invalid pointer given.') - self._feat = f - self._fdefn = lgdal.OGR_F_GetDefnRef(f) + self._feat = feat + self._fdefn = fdefn def __del__(self): "Releases a reference to this object." - if self._fdefn: lgdal.OGR_FD_Release(self._fdefn) + if self._feat: lgdal.OGR_F_Destroy(self._feat) def __getitem__(self, index): "Gets the Field at the specified index." @@ -91,7 +91,7 @@ class Feature(object): raise OGRException('Cannot retrieve Geometry from the feature.') # Attempting to retrieve the Spatial Reference for the geometry. - srs_ptr = lgdal.OGR_G_GetSpatialReference(geom_ptr) + srs_ptr = lgdal.OSRClone(lgdal.OGR_G_GetSpatialReference(geom_ptr)) if srs_ptr: srs = SpatialReference(srs_ptr, 'ogr') else: diff --git a/django/contrib/gis/gdal/field.py b/django/contrib/gis/gdal/field.py index aa40f03474..8a659fa37d 100644 --- a/django/contrib/gis/gdal/field.py +++ b/django/contrib/gis/gdal/field.py @@ -12,7 +12,7 @@ class Field(object): #### Python 'magic' routines #### def __init__(self, fld, val=''): "Needs a C pointer (Python integer in ctypes) in order to initialize." - self._fld = 0 # Initially NULL + self._fld = None # Initially NULL if not fld: raise OGRException('Cannot create OGR Field, invalid pointer given.') diff --git a/django/contrib/gis/gdal/layer.py b/django/contrib/gis/gdal/layer.py index b3cf10dee5..8445de753d 100644 --- a/django/contrib/gis/gdal/layer.py +++ b/django/contrib/gis/gdal/layer.py @@ -27,8 +27,8 @@ class Layer(object): #### Python 'magic' routines #### def __init__(self, l): "Needs a C pointer (Python/ctypes integer) in order to initialize." - self._layer = 0 # Initially NULL - self._ldefn = 0 + self._layer = None # Initially NULL + self._ldefn = None if not l: raise OGRException, 'Cannot create Layer, invalid pointer given' self._layer = l @@ -36,30 +36,27 @@ class Layer(object): def __getitem__(self, index): "Gets the Feature at the specified index." - def make_feature(offset): - return Feature(lgdal.OGR_L_GetFeature(self._layer, - c_long(offset))) - end = self.num_feat if not isinstance(index, (slice, int)): raise TypeError - + end = self.num_feat if isinstance(index,int): # An integer index was given if index < 0: index = end - index if index < 0 or index >= self.num_feat: raise OGRIndexError, 'index out of range' - return make_feature(index) + return self._make_feature(index) else: # A slice was given start, stop, stride = index.indices(end) - return [make_feature(offset) for offset in range(start,stop,stride)] + return [self._make_feature(offset) for offset in range(start,stop,stride)] def __iter__(self): "Iterates over each Feature in the Layer." - #TODO: is OGR's GetNextFeature faster here? + # ResetReading() must be called before iteration is to begin. + lgdal.OGR_L_ResetReading(self._layer) for i in range(self.num_feat): - yield self.__getitem__(i) + yield Feature(lgdal.OGR_L_GetNextFeature(self._layer), self._ldefn) def __len__(self): "The length is the number of features." @@ -69,6 +66,10 @@ class Layer(object): "The string name of the layer." return self.name + def _make_feature(self, offset): + "Helper routine for __getitem__ that makes a feature from an offset." + return Feature(lgdal.OGR_L_GetFeature(self._layer, c_long(offset)), self._ldefn) + #### Layer properties #### @property def extent(self): @@ -112,6 +113,18 @@ class Layer(object): return [ string_at(lgdal.OGR_Fld_GetNameRef(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i))) for i in xrange(self.num_fields) ] + @property + def field_widths(self): + "Returns a list of the maximum field widths for the features." + return [ int(lgdal.OGR_Fld_GetWidth(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i))) + for i in xrange(self.num_fields) ] + + @property + def field_precisions(self): + "Returns the field precisions for the features." + return [ int(lgdal.OGR_Fld_GetPrecision(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i))) + for i in xrange(self.num_fields) ] + #### Layer Methods #### def get_fields(self, field_name): """Returns a list containing the given field name for every Feature diff --git a/django/contrib/gis/gdal/libgdal.py b/django/contrib/gis/gdal/libgdal.py index e40f9138d1..098a9996cc 100644 --- a/django/contrib/gis/gdal/libgdal.py +++ b/django/contrib/gis/gdal/libgdal.py @@ -1,5 +1,5 @@ import os, sys -from ctypes import CDLL +from ctypes import CDLL, string_at from django.contrib.gis.gdal.error import OGRException if os.name == 'nt': @@ -21,3 +21,29 @@ else: # This loads the GDAL/OGR C library lgdal = CDLL(lib_name) +#### Version-information functions. #### +def _version_info(key): + "Returns GDAL library version information with the given key." + buf = lgdal.GDALVersionInfo(key) + if buf: return string_at(buf) + +def gdal_version(): + "Returns only the GDAL version number information." + return _version_info('RELEASE_NAME') + +def gdal_full_version(): + "Returns the full GDAL version information." + return _version_info('') + +def gdal_release_date(date=False): + """ + Returns the release date in a string format, e.g, "2007/06/27". + If the date keyword argument is set to True, a Python datetime object + will be returned instead. + """ + from datetime import datetime + rel = _version_info('RELEASE_DATE') + yy, mm, dd = map(int, (rel[0:4], rel[4:6], rel[6:8])) + d = datetime(yy, mm, dd) + if date: return d + else: return d.strftime('%Y/%m/%d') diff --git a/django/contrib/gis/gdal/srs.py b/django/contrib/gis/gdal/srs.py index 16b47e3386..65bdafa4c7 100644 --- a/django/contrib/gis/gdal/srs.py +++ b/django/contrib/gis/gdal/srs.py @@ -82,7 +82,7 @@ class SpatialReference(object): def __init__(self, srs_input='', srs_type='wkt'): "Creates a spatial reference object from the given OGC Well Known Text (WKT)." - self._srs = 0 # Initially NULL + self._srs = None # Initially NULL # Creating an initial empty string buffer. buf = c_char_p('')