From ffdf507ec0821f0520e315c2e8a6cf231ea3fd5a Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Sat, 20 Jun 2015 11:31:22 +0200 Subject: [PATCH] Added GDAL 2.0 support --- django/contrib/gis/gdal/field.py | 22 ++++++++++++++++--- django/contrib/gis/gdal/prototypes/ds.py | 8 ++++--- .../contrib/gis/gdal/prototypes/generation.py | 9 +++++++- django/contrib/gis/gdal/prototypes/raster.py | 7 ++++-- django/contrib/gis/utils/ogrinspect.py | 5 ++++- docs/ref/contrib/gis/install/geolibs.txt | 2 +- tests/gis_tests/gdal_tests/test_ds.py | 3 ++- tests/gis_tests/inspectapp/tests.py | 6 ++--- 8 files changed, 47 insertions(+), 15 deletions(-) diff --git a/django/contrib/gis/gdal/field.py b/django/contrib/gis/gdal/field.py index 8da4256bf4..38a72b6e19 100644 --- a/django/contrib/gis/gdal/field.py +++ b/django/contrib/gis/gdal/field.py @@ -49,9 +49,12 @@ class Field(GDALBase): "Retrieves the Field's value as a double (float)." return capi.get_field_as_double(self._feat.ptr, self._index) - def as_int(self): + def as_int(self, is_64=False): "Retrieves the Field's value as an integer." - return capi.get_field_as_integer(self._feat.ptr, self._index) + if is_64: + return capi.get_field_as_integer64(self._feat.ptr, self._index) + else: + return capi.get_field_as_integer(self._feat.ptr, self._index) def as_string(self): "Retrieves the Field's value as a string." @@ -106,6 +109,7 @@ class Field(GDALBase): # ### The Field sub-classes for each OGR Field type. ### class OFTInteger(Field): _double = False + _bit64 = False @property def value(self): @@ -115,7 +119,7 @@ class OFTInteger(Field): # read as a double and cast as Python int (to prevent overflow). return int(self.as_double()) else: - return self.as_int() + return self.as_int(self._bit64) @property def type(self): @@ -185,6 +189,10 @@ class OFTTime(Field): return None +class OFTInteger64(OFTInteger): + _bit64 = True + + # List fields are also just subclasses class OFTIntegerList(Field): pass @@ -201,6 +209,11 @@ class OFTStringList(Field): class OFTWideStringList(Field): pass + +class OFTInteger64List(Field): + pass + + # Class mapping dictionary for OFT Types and reverse mapping. OGRFieldTypes = { 0: OFTInteger, @@ -215,5 +228,8 @@ OGRFieldTypes = { 9: OFTDate, 10: OFTTime, 11: OFTDateTime, + # New 64-bit integer types in GDAL 2 + 12: OFTInteger64, + 13: OFTInteger64List, } ROGRFieldTypes = {cls: num for num, cls in OGRFieldTypes.items()} diff --git a/django/contrib/gis/gdal/prototypes/ds.py b/django/contrib/gis/gdal/prototypes/ds.py index c24e4b79a2..8fe54dbc8e 100644 --- a/django/contrib/gis/gdal/prototypes/ds.py +++ b/django/contrib/gis/gdal/prototypes/ds.py @@ -6,10 +6,10 @@ from ctypes import POINTER, c_char_p, c_double, c_int, c_long, c_void_p from django.contrib.gis.gdal.envelope import OGREnvelope -from django.contrib.gis.gdal.libgdal import lgdal +from django.contrib.gis.gdal.libgdal import GDAL_VERSION, lgdal from django.contrib.gis.gdal.prototypes.generation import ( - const_string_output, double_output, geom_output, int_output, srs_output, - void_output, voidptr_output, + const_string_output, double_output, geom_output, int64_output, int_output, + srs_output, void_output, voidptr_output, ) c_int_p = POINTER(c_int) # shortcut type @@ -66,6 +66,8 @@ get_field_as_datetime = int_output(lgdal.OGR_F_GetFieldAsDateTime, ) get_field_as_double = double_output(lgdal.OGR_F_GetFieldAsDouble, [c_void_p, c_int]) get_field_as_integer = int_output(lgdal.OGR_F_GetFieldAsInteger, [c_void_p, c_int]) +if GDAL_VERSION >= (2, 0): + get_field_as_integer64 = int64_output(lgdal.OGR_F_GetFieldAsInteger64, [c_void_p, c_int]) get_field_as_string = const_string_output(lgdal.OGR_F_GetFieldAsString, [c_void_p, c_int]) get_field_index = int_output(lgdal.OGR_F_GetFieldIndex, [c_void_p, c_char_p]) diff --git a/django/contrib/gis/gdal/prototypes/generation.py b/django/contrib/gis/gdal/prototypes/generation.py index 39bf621796..965e158040 100644 --- a/django/contrib/gis/gdal/prototypes/generation.py +++ b/django/contrib/gis/gdal/prototypes/generation.py @@ -2,7 +2,7 @@ This module contains functions that generate ctypes prototypes for the GDAL routines. """ -from ctypes import c_char_p, c_double, c_int, c_void_p +from ctypes import c_char_p, c_double, c_int, c_int64, c_void_p from functools import partial from django.contrib.gis.gdal.prototypes.errcheck import ( @@ -56,6 +56,13 @@ def int_output(func, argtypes): return func +def int64_output(func, argtypes): + "Generates a ctypes function that returns a 64-bit integer value." + func.argtypes = argtypes + func.restype = c_int64 + return func + + def srs_output(func, argtypes): """ Generates a ctypes prototype for the given function with diff --git a/django/contrib/gis/gdal/prototypes/raster.py b/django/contrib/gis/gdal/prototypes/raster.py index 8ede45f532..15b8f64235 100644 --- a/django/contrib/gis/gdal/prototypes/raster.py +++ b/django/contrib/gis/gdal/prototypes/raster.py @@ -5,7 +5,7 @@ related data structures. from ctypes import POINTER, c_char_p, c_double, c_int, c_void_p from functools import partial -from django.contrib.gis.gdal.libgdal import std_call +from django.contrib.gis.gdal.libgdal import GDAL_VERSION, std_call from django.contrib.gis.gdal.prototypes.generation import ( const_string_output, double_output, int_output, void_output, voidptr_output, @@ -30,7 +30,10 @@ get_driver_description = const_string_output(std_call('GDALGetDescription'), [c_ # Raster Data Source Routines create_ds = voidptr_output(std_call('GDALCreate'), [c_void_p, c_char_p, c_int, c_int, c_int, c_int, c_void_p]) open_ds = voidptr_output(std_call('GDALOpen'), [c_char_p, c_int]) -close_ds = void_output(std_call('GDALClose'), [c_void_p]) +if GDAL_VERSION >= (2, 0): + close_ds = voidptr_output(std_call('GDALClose'), [c_void_p]) +else: + close_ds = void_output(std_call('GDALClose'), [c_void_p]) flush_ds = int_output(std_call('GDALFlushCache'), [c_void_p]) copy_ds = voidptr_output(std_call('GDALCreateCopy'), [c_void_p, c_char_p, c_void_p, c_int, POINTER(c_char_p), c_void_p, c_void_p] diff --git a/django/contrib/gis/utils/ogrinspect.py b/django/contrib/gis/utils/ogrinspect.py index c4697fe242..dcc464e11f 100644 --- a/django/contrib/gis/utils/ogrinspect.py +++ b/django/contrib/gis/utils/ogrinspect.py @@ -5,7 +5,8 @@ models for GeoDjango and/or mapping dictionaries for use with the """ from django.contrib.gis.gdal import DataSource from django.contrib.gis.gdal.field import ( - OFTDate, OFTDateTime, OFTInteger, OFTReal, OFTString, OFTTime, + OFTDate, OFTDateTime, OFTInteger, OFTInteger64, OFTReal, OFTString, + OFTTime, ) from django.utils import six from django.utils.six.moves import zip @@ -195,6 +196,8 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non yield ' %s = models.FloatField(%s)' % (mfield, kwargs_str[2:]) elif field_type is OFTInteger: yield ' %s = models.IntegerField(%s)' % (mfield, kwargs_str[2:]) + elif field_type is OFTInteger64: + yield ' %s = models.BigIntegerField(%s)' % (mfield, kwargs_str[2:]) elif field_type is OFTString: yield ' %s = models.CharField(max_length=%s%s)' % (mfield, width, kwargs_str) elif field_type is OFTDate: diff --git a/docs/ref/contrib/gis/install/geolibs.txt b/docs/ref/contrib/gis/install/geolibs.txt index f343b87dfc..6de4af4312 100644 --- a/docs/ref/contrib/gis/install/geolibs.txt +++ b/docs/ref/contrib/gis/install/geolibs.txt @@ -10,7 +10,7 @@ Program Description Required ======================== ==================================== ================================ ============================ :doc:`GEOS <../geos>` Geometry Engine Open Source Yes 3.4, 3.3, 3.2 `PROJ.4`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 4.9, 4.8, 4.7, 4.6, 4.5, 4.4 -:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes (SQLite only) 1.11, 1.10, 1.9, 1.8, 1.7 +:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes (SQLite only) 2.0, 1.11, 1.10, 1.9, 1.8, 1.7 :doc:`GeoIP <../geoip>` IP-based geolocation library No 1.4 `PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 2.1, 2.0 `SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.1, 4.0, 3.0, 2.4 diff --git a/tests/gis_tests/gdal_tests/test_ds.py b/tests/gis_tests/gdal_tests/test_ds.py index 0de4c282b9..d6a46d5a95 100644 --- a/tests/gis_tests/gdal_tests/test_ds.py +++ b/tests/gis_tests/gdal_tests/test_ds.py @@ -27,7 +27,8 @@ if HAS_GDAL: }, fids=range(5) ), - TestDS('test_vrt', ext='vrt', nfeat=3, nfld=3, geom='POINT', gtype='Point25D', driver='VRT', + TestDS('test_vrt', ext='vrt', nfeat=3, nfld=3, geom='POINT', gtype='Point25D', + driver='OGR_VRT' if GDAL_VERSION >= (2, 0) else 'VRT', fields={ 'POINT_X': OFTString, 'POINT_Y': OFTString, diff --git a/tests/gis_tests/inspectapp/tests.py b/tests/gis_tests/inspectapp/tests.py index ca2dce72de..6525e995ca 100644 --- a/tests/gis_tests/inspectapp/tests.py +++ b/tests/gis_tests/inspectapp/tests.py @@ -14,7 +14,7 @@ from django.utils.six import StringIO from ..test_data import TEST_DATA if HAS_GDAL: - from django.contrib.gis.gdal import Driver, GDALException + from django.contrib.gis.gdal import Driver, GDALException, GDAL_VERSION from django.contrib.gis.utils.ogrinspect import ogrinspect from .models import AllOGRFields @@ -79,7 +79,7 @@ class OGRInspectTest(TestCase): '', 'class MyModel(models.Model):', ' float = models.FloatField()', - ' int = models.FloatField()', + ' int = models.{}()'.format('BigIntegerField' if GDAL_VERSION >= (2, 0) else 'FloatField'), ' str = models.CharField(max_length=80)', ' geom = models.PolygonField(srid=-1)', ' objects = models.GeoManager()', @@ -106,7 +106,7 @@ class OGRInspectTest(TestCase): '', 'class City(models.Model):', ' name = models.CharField(max_length=80)', - ' population = models.FloatField()', + ' population = models.{}()'.format('BigIntegerField' if GDAL_VERSION >= (2, 0) else 'FloatField'), ' density = models.FloatField()', ' created = models.DateField()', ' geom = models.PointField(srid=-1)',