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('')