diff --git a/django/contrib/gis/gdal/__init__.py b/django/contrib/gis/gdal/__init__.py index cedf165ef1..22f962c0e5 100644 --- a/django/contrib/gis/gdal/__init__.py +++ b/django/contrib/gis/gdal/__init__.py @@ -31,6 +31,8 @@ to a non-existant file location (e.g., `GDAL_LIBRARY_PATH='/null/path'`; setting to None/False/'' will not work as a string must be given). """ +import sys + # Attempting to import objects that depend on the GDAL library. The # HAS_GDAL flag will be set to True if the library is present on # the system. @@ -46,6 +48,8 @@ except: # The envelope, error, and geomtype modules do not actually require the # GDAL library. -from django.contrib.gis.gdal.envelope import Envelope -from django.contrib.gis.gdal.error import check_err, OGRException, OGRIndexError, SRSException -from django.contrib.gis.gdal.geomtype import OGRGeomType +PYTHON23 = sys.version_info[0] == 2 and sys.version_info[1] == 3 +if not PYTHON23: + from django.contrib.gis.gdal.envelope import Envelope + from django.contrib.gis.gdal.error import check_err, OGRException, OGRIndexError, SRSException + from django.contrib.gis.gdal.geomtype import OGRGeomType diff --git a/django/contrib/gis/models.py b/django/contrib/gis/models.py index d3e8dbdb83..bb068ec5df 100644 --- a/django/contrib/gis/models.py +++ b/django/contrib/gis/models.py @@ -6,7 +6,7 @@ import re from django.conf import settings # Checking for the presence of GDAL (needed for the SpatialReference object) -from django.contrib.gis.gdal import HAS_GDAL +from django.contrib.gis.gdal import HAS_GDAL, PYTHON23 if HAS_GDAL: from django.contrib.gis.gdal import SpatialReference @@ -28,7 +28,6 @@ class SpatialRefSysMixin(object): # distance queries. units_regex = re.compile(r'.+UNIT ?\["(?P[\w \'\(\)]+)", ?(?P[\d\.]+)(,AUTHORITY\["(?P[\w \'\(\)]+)","(?P\d+)"\])?\]([\w ]+)?(,AUTHORITY\["(?P[\w \'\(\)]+)","(?P\d+)"\])?\]$') - @property def srs(self): """ Returns a GDAL SpatialReference object, if GDAL is installed. @@ -50,8 +49,8 @@ class SpatialRefSysMixin(object): raise Exception('Could not get OSR SpatialReference from WKT: %s\nError:\n%s' % (self.wkt, msg)) else: raise Exception('GDAL is not installed.') + srs = property(srs) - @property def ellipsoid(self): """ Returns a tuple of the ellipsoid parameters: @@ -63,47 +62,47 @@ class SpatialRefSysMixin(object): m = self.spheroid_regex.match(self.wkt) if m: return (float(m.group('major')), float(m.group('flattening'))) else: return None + ellipsoid = property(ellipsoid) - @property def name(self): "Returns the projection name." return self.srs.name + name = property(name) - @property def spheroid(self): "Returns the spheroid name for this spatial reference." return self.srs['spheroid'] + spheroid = property(spheroid) - @property def datum(self): "Returns the datum for this spatial reference." return self.srs['datum'] + datum = property(datum) - @property def projected(self): "Is this Spatial Reference projected?" if HAS_GDAL: return self.srs.projected else: return self.wkt.startswith('PROJCS') + projected = property(projected) - @property def local(self): "Is this Spatial Reference local?" if HAS_GDAL: return self.srs.local else: return self.wkt.startswith('LOCAL_CS') + local = property(local) - @property def geographic(self): "Is this Spatial Reference geographic?" if HAS_GDAL: return self.srs.geographic else: return self.wkt.startswith('GEOGCS') + geographic = property(geographic) - @property def linear_name(self): "Returns the linear units name." if HAS_GDAL: @@ -113,8 +112,8 @@ class SpatialRefSysMixin(object): else: m = self.units_regex.match(self.wkt) return m.group('unit_name') - - @property + linear_name = property(linear_name) + def linear_units(self): "Returns the linear units." if HAS_GDAL: @@ -124,8 +123,8 @@ class SpatialRefSysMixin(object): else: m = self.units_regex.match(self.wkt) return m.group('unit') + linear_units = property(linear_units) - @property def angular_name(self): "Returns the name of the angular units." if HAS_GDAL: @@ -135,8 +134,8 @@ class SpatialRefSysMixin(object): else: m = self.units_regex.match(self.wkt) return m.group('unit_name') + angular_name = property(angular_name) - @property def angular_units(self): "Returns the angular units." if HAS_GDAL: @@ -146,8 +145,8 @@ class SpatialRefSysMixin(object): else: m = self.units_regex.match(self.wkt) return m.group('unit') + angular_units = property(angular_units) - @property def units(self): "Returns a tuple of the units and the name." if self.projected or self.local: @@ -156,8 +155,8 @@ class SpatialRefSysMixin(object): return (self.angular_units, self.angular_name) else: return (None, None) + units = property(units) - @classmethod def get_units(cls, wkt): """ Class method used by GeometryField on initialization to @@ -169,8 +168,8 @@ class SpatialRefSysMixin(object): else: m = cls.units_regex.match(wkt) return m.group('unit'), m.group('unit_name') + get_units = classmethod(get_units) - @classmethod def get_spheroid(cls, wkt, string=True): """ Class method used by GeometryField on initialization to @@ -197,6 +196,7 @@ class SpatialRefSysMixin(object): else: radius, flattening = sphere_params return 'SPHEROID["%s",%s,%s]' % (sphere_name, radius, flattening) + get_spheroid = classmethod(get_spheroid) def __unicode__(self): """ @@ -210,7 +210,7 @@ class SpatialRefSysMixin(object): # The SpatialRefSys and GeometryColumns models _srid_info = True -if settings.DATABASE_ENGINE == 'postgresql_psycopg2': +if not PYTHON23 and settings.DATABASE_ENGINE == 'postgresql_psycopg2': # Because the PostGIS version is checked when initializing the spatial # backend a `ProgrammingError` will be raised if the PostGIS tables # and functions are not installed. We catch here so it won't be raised when @@ -220,7 +220,7 @@ if settings.DATABASE_ENGINE == 'postgresql_psycopg2': from django.contrib.gis.db.backend.postgis.models import GeometryColumns, SpatialRefSys except ProgrammingError: _srid_info = False -elif settings.DATABASE_ENGINE == 'oracle': +elif not PYTHON23 and settings.DATABASE_ENGINE == 'oracle': # Same thing as above, except the GEOS library is attempted to be loaded for # `BaseSpatialBackend`, and an exception will be raised during the # Django test suite if it doesn't exist. diff --git a/django/contrib/gis/tests/__init__.py b/django/contrib/gis/tests/__init__.py index 9bf1ccd936..3584274a4c 100644 --- a/django/contrib/gis/tests/__init__.py +++ b/django/contrib/gis/tests/__init__.py @@ -1,49 +1,10 @@ import sys from copy import copy from unittest import TestSuite, TextTestRunner -from django.contrib.gis.gdal import HAS_GDAL -try: - from django.contrib.gis.tests.utils import mysql, oracle, postgis -except: - mysql, oracle, postgis = (False, False, False) -from django.contrib.gis.utils import HAS_GEOIP + from django.conf import settings if not settings._target: settings.configure() -# Tests that require use of a spatial database (e.g., creation of models) -test_models = ['geoapp',] - -# Tests that do not require setting up and tearing down a spatial database. -test_suite_names = [ - 'test_geos', - 'test_measure', -] -if HAS_GDAL: - if oracle: - # TODO: There's a problem with `select_related` and GeoQuerySet on - # Oracle -- e.g., GeoModel.objects.distance(geom, field_name='fk__point') - # doesn't work so we don't test `relatedapp`. - test_models += ['distapp', 'layermap'] - elif postgis: - test_models += ['distapp', 'layermap', 'relatedapp'] - elif mysql: - test_models += ['relatedapp'] - - test_suite_names += [ - 'test_gdal_driver', - 'test_gdal_ds', - 'test_gdal_envelope', - 'test_gdal_geom', - 'test_gdal_srs', - 'test_spatialrefsys', - ] -else: - print >>sys.stderr, "GDAL not available - no GDAL tests will be run." - -if HAS_GEOIP: - if hasattr(settings, 'GEOIP_PATH'): - test_suite_names.append('test_geoip') - def geo_suite(): """ Builds a test suite for the GIS package. This is not named @@ -51,11 +12,48 @@ def geo_suite(): spatial database tables are required to execute these tests on some backends). """ + from django.contrib.gis.tests.utils import mysql, oracle, postgis + from django.contrib.gis.gdal import HAS_GDAL + from django.contrib.gis.utils import HAS_GEOIP + + # Tests that require use of a spatial database (e.g., creation of models) + test_models = ['geoapp',] + + # Tests that do not require setting up and tearing down a spatial database. + test_suite_names = [ + 'test_geos', + 'test_measure', + ] + if HAS_GDAL: + if oracle: + # TODO: There's a problem with `select_related` and GeoQuerySet on + # Oracle -- e.g., GeoModel.objects.distance(geom, field_name='fk__point') + # doesn't work so we don't test `relatedapp`. + test_models += ['distapp', 'layermap'] + elif postgis: + test_models += ['distapp', 'layermap', 'relatedapp'] + elif mysql: + test_models += ['relatedapp'] + + test_suite_names += [ + 'test_gdal_driver', + 'test_gdal_ds', + 'test_gdal_envelope', + 'test_gdal_geom', + 'test_gdal_srs', + 'test_spatialrefsys', + ] + else: + print >>sys.stderr, "GDAL not available - no GDAL tests will be run." + + if HAS_GEOIP and hasattr(settings, 'GEOIP_PATH'): + test_suite_names.append('test_geoip') + s = TestSuite() for test_suite in test_suite_names: tsuite = getattr(__import__('django.contrib.gis.tests', globals(), locals(), [test_suite]),test_suite) s.addTest(tsuite.suite()) - return s + return s, test_models def run(verbosity=1): "Runs the tests that do not require geographic (GEOS, GDAL, etc.) models." @@ -94,6 +92,7 @@ def run_tests(module_list, verbosity=1, interactive=True): Finally, the tests may be run by invoking `./manage.py test`. """ from django.contrib.gis.db.backend import create_spatial_db + from django.contrib.gis.tests.utils import mysql from django.db import connection from django.test.utils import destroy_test_db @@ -110,7 +109,7 @@ def run_tests(module_list, verbosity=1, interactive=True): # Creating the test suite, adding the test models to INSTALLED_APPS, and # adding the model test suites to our suite package. - test_suite = geo_suite() + test_suite, test_models = geo_suite() for test_model in test_models: module_name = 'django.contrib.gis.tests.%s' % test_model if mysql: