Fixed #26753 -- Made GDAL a required dependency for contrib.gis

Thanks Tim Graham for the review.
This commit is contained in:
Claude Paroz 2016-06-14 16:18:33 +02:00
parent 7def55c3f6
commit f7a363ee1d
29 changed files with 117 additions and 368 deletions

View File

@ -1,8 +1,7 @@
from django.contrib.admin import ModelAdmin
from django.contrib.gis.admin.widgets import OpenLayersWidget
from django.contrib.gis.db import models
from django.contrib.gis.gdal import HAS_GDAL, OGRGeomType
from django.core.exceptions import ImproperlyConfigured
from django.contrib.gis.gdal import OGRGeomType
spherical_mercator_srid = 3857
@ -59,12 +58,6 @@ class GeoModelAdmin(ModelAdmin):
3D editing).
"""
if isinstance(db_field, models.GeometryField) and db_field.dim < 3:
if not HAS_GDAL and db_field.srid != self.map_srid:
raise ImproperlyConfigured(
"Map SRID is %s and SRID of `%s` is %s. GDAL must be "
"installed to perform the transformation."
% (self.map_srid, db_field, db_field.srid)
)
# Setting the widget with the newly defined widget.
kwargs['widget'] = self.get_map_widget(db_field)
return db_field.formfield(**kwargs)

View File

@ -1,5 +1,3 @@
import re
from django.contrib.gis import gdal
from django.utils import six
from django.utils.encoding import python_2_unicode_compatible
@ -11,47 +9,32 @@ class SpatialRefSysMixin(object):
The SpatialRefSysMixin is a class used by the database-dependent
SpatialRefSys objects to reduce redundant code.
"""
# For pulling out the spheroid from the spatial reference string. This
# regular expression is used only if the user does not have GDAL installed.
# TODO: Flattening not used in all ellipsoids, could also be a minor axis,
# or 'b' parameter.
spheroid_regex = re.compile(r'.+SPHEROID\[\"(?P<name>.+)\",(?P<major>\d+(\.\d+)?),(?P<flattening>\d{3}\.\d+),')
# For pulling out the units on platforms w/o GDAL installed.
# TODO: Figure out how to pull out angular units of projected coordinate system and
# fix for LOCAL_CS types. GDAL should be highly recommended for performing
# distance queries.
units_regex = re.compile(r'.+UNIT ?\["(?P<unit_name>[\w \.\'\(\)]+)", ?(?P<unit>[^ ,\]]+)', re.DOTALL)
@property
def srs(self):
"""
Returns a GDAL SpatialReference object, if GDAL is installed.
Returns a GDAL SpatialReference object.
"""
if gdal.HAS_GDAL:
# TODO: Is caching really necessary here? Is complexity worth it?
if hasattr(self, '_srs'):
# Returning a clone of the cached SpatialReference object.
return self._srs.clone()
else:
# Attempting to cache a SpatialReference object.
# Trying to get from WKT first.
try:
self._srs = gdal.SpatialReference(self.wkt)
return self.srs
except Exception as e:
msg = e
try:
self._srs = gdal.SpatialReference(self.proj4text)
return self.srs
except Exception as e:
msg = e
raise Exception('Could not get OSR SpatialReference from WKT: %s\nError:\n%s' % (self.wkt, msg))
# TODO: Is caching really necessary here? Is complexity worth it?
if hasattr(self, '_srs'):
# Returning a clone of the cached SpatialReference object.
return self._srs.clone()
else:
raise Exception('GDAL is not installed.')
# Attempting to cache a SpatialReference object.
# Trying to get from WKT first.
try:
self._srs = gdal.SpatialReference(self.wkt)
return self.srs
except Exception as e:
msg = e
try:
self._srs = gdal.SpatialReference(self.proj4text)
return self.srs
except Exception as e:
msg = e
raise Exception('Could not get OSR SpatialReference from WKT: %s\nError:\n%s' % (self.wkt, msg))
@property
def ellipsoid(self):
@ -59,14 +42,7 @@ class SpatialRefSysMixin(object):
Returns a tuple of the ellipsoid parameters:
(semimajor axis, semiminor axis, and inverse flattening).
"""
if gdal.HAS_GDAL:
return self.srs.ellipsoid
else:
m = self.spheroid_regex.match(self.wkt)
if m:
return (float(m.group('major')), float(m.group('flattening')))
else:
return None
return self.srs.ellipsoid
@property
def name(self):
@ -86,70 +62,37 @@ class SpatialRefSysMixin(object):
@property
def projected(self):
"Is this Spatial Reference projected?"
if gdal.HAS_GDAL:
return self.srs.projected
else:
return self.wkt.startswith('PROJCS')
return self.srs.projected
@property
def local(self):
"Is this Spatial Reference local?"
if gdal.HAS_GDAL:
return self.srs.local
else:
return self.wkt.startswith('LOCAL_CS')
return self.srs.local
@property
def geographic(self):
"Is this Spatial Reference geographic?"
if gdal.HAS_GDAL:
return self.srs.geographic
else:
return self.wkt.startswith('GEOGCS')
return self.srs.geographic
@property
def linear_name(self):
"Returns the linear units name."
if gdal.HAS_GDAL:
return self.srs.linear_name
elif self.geographic:
return None
else:
m = self.units_regex.match(self.wkt)
return m.group('unit_name')
return self.srs.linear_name
@property
def linear_units(self):
"Returns the linear units."
if gdal.HAS_GDAL:
return self.srs.linear_units
elif self.geographic:
return None
else:
m = self.units_regex.match(self.wkt)
return m.group('unit')
return self.srs.linear_units
@property
def angular_name(self):
"Returns the name of the angular units."
if gdal.HAS_GDAL:
return self.srs.angular_name
elif self.projected:
return None
else:
m = self.units_regex.match(self.wkt)
return m.group('unit_name')
return self.srs.angular_name
@property
def angular_units(self):
"Returns the angular units."
if gdal.HAS_GDAL:
return self.srs.angular_units
elif self.projected:
return None
else:
m = self.units_regex.match(self.wkt)
return m.group('unit')
return self.srs.angular_units
@property
def units(self):
@ -167,11 +110,7 @@ class SpatialRefSysMixin(object):
Return a tuple of (unit_value, unit_name) for the given WKT without
using any of the database fields.
"""
if gdal.HAS_GDAL:
return gdal.SpatialReference(wkt).units
else:
m = cls.units_regex.match(wkt)
return float(m.group('unit')), m.group('unit_name')
return gdal.SpatialReference(wkt).units
@classmethod
def get_spheroid(cls, wkt, string=True):
@ -179,17 +118,9 @@ class SpatialRefSysMixin(object):
Class method used by GeometryField on initialization to
retrieve the `SPHEROID[..]` parameters from the given WKT.
"""
if gdal.HAS_GDAL:
srs = gdal.SpatialReference(wkt)
sphere_params = srs.ellipsoid
sphere_name = srs['spheroid']
else:
m = cls.spheroid_regex.match(wkt)
if m:
sphere_params = (float(m.group('major')), float(m.group('flattening')))
sphere_name = m.group('name')
else:
return None
srs = gdal.SpatialReference(wkt)
sphere_params = srs.ellipsoid
sphere_name = srs['spheroid']
if not string:
return sphere_name, sphere_params
@ -203,10 +134,6 @@ class SpatialRefSysMixin(object):
def __str__(self):
"""
Returns the string representation. If GDAL is installed,
it will be 'pretty' OGC WKT.
Returns the string representation, a 'pretty' OGC WKT.
"""
try:
return six.text_type(self.srs)
except Exception:
return six.text_type(self.wkt)
return six.text_type(self.srs)

View File

@ -1,9 +1,8 @@
from django.contrib.gis import forms
from django.contrib.gis import forms, gdal
from django.contrib.gis.db.models.lookups import (
RasterBandTransform, gis_lookups,
)
from django.contrib.gis.db.models.proxy import SpatialProxy
from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.gdal.error import GDALException
from django.contrib.gis.geometry.backend import Geometry, GeometryException
from django.core.exceptions import ImproperlyConfigured
@ -186,18 +185,16 @@ class BaseSpatialField(Field):
"""
Return a GDALRaster if conversion is successful, otherwise return None.
"""
from django.contrib.gis.gdal import GDALRaster
if isinstance(value, GDALRaster):
if isinstance(value, gdal.GDALRaster):
return value
elif is_candidate:
try:
return GDALRaster(value)
return gdal.GDALRaster(value)
except GDALException:
pass
elif isinstance(value, dict):
try:
return GDALRaster(value)
return gdal.GDALRaster(value)
except GDALException:
raise ValueError("Couldn't create spatial object from lookup value '%s'." % value)
@ -228,10 +225,8 @@ class BaseSpatialField(Field):
else:
# Check if input is a candidate for conversion to raster or geometry.
is_candidate = isinstance(obj, (bytes, six.string_types)) or hasattr(obj, '__geo_interface__')
# With GDAL installed, try to convert the input to raster.
raster = False
if HAS_GDAL:
raster = self.get_raster_prep_value(obj, is_candidate)
# Try to convert the input to raster.
raster = self.get_raster_prep_value(obj, is_candidate)
if raster:
obj = raster
@ -425,11 +420,6 @@ class RasterField(BaseSpatialField):
geom_type = 'RASTER'
geography = False
def __init__(self, *args, **kwargs):
if not HAS_GDAL:
raise ImproperlyConfigured('RasterField requires GDAL.')
super(RasterField, self).__init__(*args, **kwargs)
def _check_connection(self, connection):
# Make sure raster fields are used only on backends with raster support.
if not connection.features.gis_enabled or not connection.features.supports_raster:
@ -451,13 +441,11 @@ class RasterField(BaseSpatialField):
def contribute_to_class(self, cls, name, **kwargs):
super(RasterField, self).contribute_to_class(cls, name, **kwargs)
# Importing GDALRaster raises an exception on systems without gdal.
from django.contrib.gis.gdal import GDALRaster
# Setup for lazy-instantiated Raster object. For large querysets, the
# instantiation of all GDALRasters can potentially be expensive. This
# delays the instantiation of the objects to the moment of evaluation
# of the raster attribute.
setattr(cls, self.attname, SpatialProxy(GDALRaster, self))
setattr(cls, self.attname, SpatialProxy(gdal.GDALRaster, self))
def get_transform(self, name):
try:

View File

@ -91,6 +91,7 @@ class OSMWidget(BaseGeometryWidget):
template_name = 'gis/openlayers-osm.html'
default_lon = 5
default_lat = 47
map_srid = 3857
class Media:
js = (
@ -104,12 +105,3 @@ class OSMWidget(BaseGeometryWidget):
self.attrs[key] = getattr(self, key)
if attrs:
self.attrs.update(attrs)
@property
def map_srid(self):
# Use the official spherical mercator projection SRID when GDAL is
# available; otherwise, fallback to 900913.
if gdal.HAS_GDAL:
return 3857
else:
return 900913

View File

@ -24,12 +24,6 @@
library name for the current OS. The default library path may be overridden
by setting `GDAL_LIBRARY_PATH` in your settings with the path to the GDAL C
library on your system.
GDAL links to a large number of external libraries that consume RAM when
loaded. Thus, it may desirable to disable GDAL on systems with limited
RAM resources -- this may be accomplished by setting `GDAL_LIBRARY_PATH`
to a non-existent file location (e.g., `GDAL_LIBRARY_PATH='/null/path'`;
setting to None/False/'' will not work as a string must be given).
"""
from django.contrib.gis.gdal.envelope import Envelope
from django.contrib.gis.gdal.error import ( # NOQA

View File

@ -64,8 +64,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
g = wkb_r().read(force_bytes(geo_input))
elif json_regex.match(geo_input):
# Handling GeoJSON input.
if not gdal.HAS_GDAL:
raise ValueError('Initializing geometry from JSON input requires GDAL.')
g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb)
else:
raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
@ -476,8 +474,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
@property
def ogr(self):
"Returns the OGR Geometry for this Geometry."
if not gdal.HAS_GDAL:
raise GEOSException('GDAL required to convert to an OGRGeometry.')
if self.srid:
try:
return gdal.OGRGeometry(self.wkb, self.srid)
@ -488,8 +484,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
@property
def srs(self):
"Returns the OSR SpatialReference for SRID of this Geometry."
if not gdal.HAS_GDAL:
raise GEOSException('GDAL required to return a SpatialReference object.')
if self.srid:
try:
return gdal.SpatialReference(self.srid)
@ -520,9 +514,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
else:
return
if not gdal.HAS_GDAL:
raise GEOSException("GDAL library is not available to transform() geometry.")
if isinstance(ct, gdal.CoordTransform):
# We don't care about SRID because CoordTransform presupposes
# source SRS.

View File

@ -98,8 +98,6 @@ class Command(BaseCommand):
def handle(self, *args, **options):
data_source, model_name = options.pop('data_source'), options.pop('model_name')
if not gdal.HAS_GDAL:
raise CommandError('GDAL is required to inspect geospatial data sources.')
# Getting the OGR DataSource from the string parameter.
try:

View File

@ -1,9 +1,7 @@
from __future__ import unicode_literals
from django.contrib.gis.gdal import HAS_GDAL
from django.core.serializers.base import (
SerializationError, SerializerDoesNotExist,
)
from django.core.serializers.base import SerializerDoesNotExist
from django.core.serializers.json import Serializer as JSONSerializer
if HAS_GDAL:
@ -53,10 +51,6 @@ class Serializer(JSONSerializer):
if self._geometry:
if self._geometry.srid != self.srid:
# If needed, transform the geometry in the srid of the global geojson srid
if not HAS_GDAL:
raise SerializationError(
'Unable to convert geometry to SRID %s when GDAL is not installed.' % self.srid
)
if self._geometry.srid not in self._cts:
srs = SpatialReference(self.srid)
self._cts[self._geometry.srid] = CoordTransform(self._geometry.srs, srs)

View File

@ -91,9 +91,9 @@ transform procedure::
Thus, geometry parameters may be passed in using the ``GEOSGeometry`` object, WKT
(Well Known Text [#fnwkt]_), HEXEWKB (PostGIS specific -- a WKB geometry in
hexadecimal [#fnewkb]_), and GeoJSON [#fngeojson]_ (requires GDAL). Essentially,
if the input is not a ``GEOSGeometry`` object, the geometry field will attempt to
create a ``GEOSGeometry`` instance from the input.
hexadecimal [#fnewkb]_), and GeoJSON [#fngeojson]_. Essentially, if the input is
not a ``GEOSGeometry`` object, the geometry field will attempt to create a
``GEOSGeometry`` instance from the input.
For more information creating :class:`~django.contrib.gis.geos.GEOSGeometry`
objects, refer to the :ref:`GEOS tutorial <geos-tutorial>`.

View File

@ -195,7 +195,7 @@ Format Input Type
WKT / EWKT ``str`` or ``unicode``
HEX / HEXEWKB ``str`` or ``unicode``
WKB / EWKB ``buffer``
GeoJSON (requires GDAL) ``str`` or ``unicode``
GeoJSON ``str`` or ``unicode``
======================= ======================
Properties
@ -345,10 +345,6 @@ another object.
Returns an :class:`~django.contrib.gis.gdal.OGRGeometry` object
corresponding to the GEOS geometry.
.. note::
Requires GDAL.
.. _wkb:
.. attribute:: GEOSGeometry.wkb
@ -618,10 +614,6 @@ Other Properties & Methods
Returns a :class:`~django.contrib.gis.gdal.SpatialReference` object
corresponding to the SRID of the geometry or ``None``.
.. note::
Requires GDAL.
.. method:: GEOSGeometry.transform(ct, clone=False)
Transforms the geometry according to the given coordinate transformation
@ -635,10 +627,10 @@ Other Properties & Methods
.. note::
Requires GDAL. Raises :class:`~django.contrib.gis.geos.GEOSException` if
GDAL is not available or if the geometry's SRID is ``None`` or less than
0. It doesn't impose any constraints on the geometry's SRID if called
with a :class:`~django.contrib.gis.gdal.CoordTransform` object.
Raises :class:`~django.contrib.gis.geos.GEOSException` if GDAL is not
available or if the geometry's SRID is ``None`` or less than 0. It
doesn't impose any constraints on the geometry's SRID if called with a
:class:`~django.contrib.gis.gdal.CoordTransform` object.
.. versionchanged:: 1.10

View File

@ -10,7 +10,7 @@ Program Description Required
======================== ==================================== ================================ ===================================
:doc:`GEOS <../geos>` Geometry Engine Open Source Yes 3.4, 3.3
`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) 2.1, 2.0, 1.11, 1.10, 1.9, 1.8, 1.7
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 2.1, 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.2, 2.1
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.3, 4.2, 4.1, 4.0
@ -19,6 +19,11 @@ Program Description Required
Note that older or more recent versions of these libraries *may* also work
totally fine with GeoDjango. Your mileage may vary.
.. versionchanged:: 1.11
In older versions, GDAL is required only for SQLite. Now it's required for
all databases.
..
Libs release dates:
GEOS 3.3.0 2011-05-30
@ -37,13 +42,6 @@ totally fine with GeoDjango. Your mileage may vary.
Spatialite 4.2.0 2014-07-25
Spatialite 4.3.0 2015-09-07
.. admonition:: Install GDAL
While :ref:`gdalbuild` is technically not required, it is *recommended*.
Important features of GeoDjango (including the :doc:`../layermapping`,
geometry reprojection, and the geographic admin) depend on its
functionality.
.. note::
The GeoDjango interfaces to GEOS, GDAL, and GeoIP may be used

View File

@ -58,9 +58,9 @@ supported versions, and any notes for each of the supported database backends:
================== ============================== ================== =========================================
Database Library Requirements Supported Versions Notes
================== ============================== ================== =========================================
PostgreSQL GEOS, PROJ.4, PostGIS 9.3+ Requires PostGIS.
MySQL GEOS 5.5+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
Oracle GEOS 11.2+ XE not supported.
PostgreSQL GEOS, GDAL, PROJ.4, PostGIS 9.3+ Requires PostGIS.
MySQL GEOS, GDAL 5.5+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
Oracle GEOS, GDAL 11.2+ XE not supported.
SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 4.0+, pysqlite2 2.5+
================== ============================== ================== =========================================

View File

@ -8,10 +8,6 @@
GeoDjango provides a specific serializer for the `GeoJSON`__ format. See
:doc:`/topics/serialization` for more information on serialization.
The GDAL library is required if any of the serialized geometries need
coordinate transformations (that is if the geometry's spatial reference system
differs from the ``srid`` serializer option).
__ http://geojson.org/
The ``geojson`` serializer is not meant for round-tripping data, as it has no

View File

@ -668,7 +668,7 @@ for popular geospatial formats::
MULTIPOLYGON (((12.4157980000000006 43.9579540000000009, 12.4505540000000003 43.9797209999999978, ...
>>> sm.mpoly.wkb # WKB (as Python binary buffer)
<read-only buffer for 0x1fe2c70, size -1, offset 0 at 0x2564c40>
>>> sm.mpoly.geojson # GeoJSON (requires GDAL)
>>> sm.mpoly.geojson # GeoJSON
'{ "type": "MultiPolygon", "coordinates": [ [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...
This includes access to all of the advanced geometric operations provided by
@ -753,13 +753,8 @@ This provides more context (including street and thoroughfare details) than
available with the :class:`~django.contrib.gis.admin.GeoModelAdmin`
(which uses the `Vector Map Level 0`_ WMS dataset hosted at `OSGeo`_).
First, there are some important requirements:
* :class:`~django.contrib.gis.admin.OSMGeoAdmin` requires that
:doc:`GDAL <gdal>` is installed.
* The PROJ.4 datum shifting files must be installed (see the
:ref:`PROJ.4 installation instructions <proj4>` for more details).
The PROJ.4 datum shifting files must be installed (see the :ref:`PROJ.4
installation instructions <proj4>` for more details).
If you meet this requirement, then just substitute the ``OSMGeoAdmin``
option class in your ``admin.py`` file::

View File

@ -227,6 +227,13 @@ Validators
Backwards incompatible changes in 1.11
======================================
:mod:`django.contrib.gis`
-------------------------
* To simplify the codebase and because it's easier to install than when
``contrib.gis`` was first released, :ref:`gdalbuild` is now a required
dependency for GeoDjango. In older versions, it's only required for SQLite.
Database backend API
--------------------

View File

@ -1,16 +1,13 @@
from __future__ import unicode_literals
from unittest import skipUnless
from django.contrib.gis.db.models.functions import (
Area, Distance, Length, Perimeter, Transform,
)
from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.geos import GEOSGeometry, LineString, Point
from django.contrib.gis.measure import D # alias for Distance
from django.db import connection
from django.db.models import F, Q
from django.test import TestCase, ignore_warnings, mock, skipUnlessDBFeature
from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
from django.utils.deprecation import RemovedInDjango20Warning
from ..utils import no_oracle, oracle, postgis
@ -497,7 +494,6 @@ class DistanceFunctionsTests(TestCase):
tol
)
@skipUnless(HAS_GDAL, "GDAL is required.")
@skipUnlessDBFeature("has_Distance_function", "has_Transform_function")
def test_distance_projected(self):
"""
@ -520,26 +516,24 @@ class DistanceFunctionsTests(TestCase):
455411.438904354, 519386.252102563, 696139.009211594,
232513.278304279, 542445.630586414, 456679.155883207]
for has_gdal in [False, True]:
with mock.patch('django.contrib.gis.gdal.HAS_GDAL', has_gdal):
# Testing using different variations of parameters and using models
# with different projected coordinate systems.
dist1 = SouthTexasCity.objects.annotate(distance=Distance('point', lagrange)).order_by('id')
if oracle:
dist_qs = [dist1]
else:
dist2 = SouthTexasCityFt.objects.annotate(distance=Distance('point', lagrange)).order_by('id')
dist_qs = [dist1, dist2]
# Testing using different variations of parameters and using models
# with different projected coordinate systems.
dist1 = SouthTexasCity.objects.annotate(distance=Distance('point', lagrange)).order_by('id')
if oracle:
dist_qs = [dist1]
else:
dist2 = SouthTexasCityFt.objects.annotate(distance=Distance('point', lagrange)).order_by('id')
dist_qs = [dist1, dist2]
# Original query done on PostGIS, have to adjust AlmostEqual tolerance
# for Oracle.
tol = 2 if oracle else 5
# Original query done on PostGIS, have to adjust AlmostEqual tolerance
# for Oracle.
tol = 2 if oracle else 5
# Ensuring expected distances are returned for each distance queryset.
for qs in dist_qs:
for i, c in enumerate(qs):
self.assertAlmostEqual(m_distances[i], c.distance.m, tol)
self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, tol)
# Ensuring expected distances are returned for each distance queryset.
for qs in dist_qs:
for i, c in enumerate(qs):
self.assertAlmostEqual(m_distances[i], c.distance.m, tol)
self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, tol)
@skipUnlessDBFeature("has_Distance_function", "supports_distance_geodetic")
def test_distance_geodetic(self):

View File

@ -2,13 +2,11 @@ from __future__ import unicode_literals
import os
import re
from unittest import skipUnless
from django.contrib.gis.db.models import Extent3D, Union
from django.contrib.gis.db.models.functions import (
AsGeoJSON, AsKML, Length, Perimeter, Scale, Translate,
)
from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.geos import GEOSGeometry, LineString, Point, Polygon
from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
from django.utils._os import upath
@ -19,10 +17,6 @@ from .models import (
MultiPoint3D, Point2D, Point3D, Polygon2D, Polygon3D,
)
if HAS_GDAL:
from django.contrib.gis.utils import LayerMapping, LayerMapError
data_path = os.path.realpath(os.path.join(os.path.dirname(upath(__file__)), '..', 'data'))
city_file = os.path.join(data_path, 'cities', 'cities.shp')
vrt_file = os.path.join(data_path, 'test_vrt', 'test_vrt.vrt')
@ -101,7 +95,6 @@ class Geo3DLoadingHelper(object):
Polygon3D.objects.create(name='3D BBox', poly=bbox_3d)
@skipUnless(HAS_GDAL, "GDAL is required for Geo3DTest.")
@skipUnlessDBFeature("gis_enabled", "supports_3d_storage")
class Geo3DTest(Geo3DLoadingHelper, TestCase):
"""
@ -147,6 +140,9 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
"""
Testing LayerMapping on 3D models.
"""
# Import here as GDAL is required for those imports
from django.contrib.gis.utils import LayerMapping, LayerMapError
point_mapping = {'point': 'POINT'}
mpoint_mapping = {'mpoint': 'MULTIPOINT'}
@ -310,7 +306,6 @@ class Geo3DTest(Geo3DLoadingHelper, TestCase):
self.assertEqual(city_dict[city.name][2] + ztrans, city.translate.z)
@skipUnless(HAS_GDAL, "GDAL is required for Geo3DTest.")
@skipUnlessDBFeature("gis_enabled", "supports_3d_functions")
class Geo3DFunctionsTests(Geo3DLoadingHelper, TestCase):
def test_kml(self):

View File

@ -17,17 +17,5 @@ class City(models.Model):
return self.name
@python_2_unicode_compatible
class CityMercator(models.Model):
name = models.CharField(max_length=30)
point = models.PointField(srid=3857)
class Meta:
required_db_features = ['gis_enabled']
def __str__(self):
return self.name
site = admin.AdminSite(name='admin_gis')
site.register(City, admin.OSMGeoAdmin)
site.register(CityMercator, admin.OSMGeoAdmin)

View File

@ -1,15 +1,11 @@
from __future__ import unicode_literals
from unittest import skipUnless
from django.contrib.gis import admin
from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.geos import Point
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase, mock, override_settings, skipUnlessDBFeature
from django.test import TestCase, override_settings, skipUnlessDBFeature
from .admin import UnmodifiableAdmin
from .models import City, CityMercator, site
from .models import City, site
@skipUnlessDBFeature("gis_enabled")
@ -56,22 +52,6 @@ class GeoAdminTest(TestCase):
""""http://vmap0.tiles.osgeo.org/wms/vmap0", {layers: 'basic', format: 'image/jpeg'});""",
result)
@mock.patch('django.contrib.gis.admin.options.HAS_GDAL', False)
def test_no_gdal_admin_model_diffent_srid(self):
msg = (
'Map SRID is 3857 and SRID of `geoadmin.City.point` is 4326. '
'GDAL must be installed to perform the transformation.'
)
with self.assertRaisesMessage(ImproperlyConfigured, msg):
geoadmin = site._registry[City]
geoadmin.get_changelist_form(None)()
@mock.patch('django.contrib.gis.admin.options.HAS_GDAL', False)
def test_no_gdal_admin_model_same_srid(self):
geoadmin = site._registry[CityMercator]
geoadmin.get_changelist_form(None)()
@skipUnless(HAS_GDAL, "GDAL is required.")
def test_olwidget_has_changed(self):
"""
Check that changes are accurately noticed by OpenLayersWidget.

View File

@ -4,8 +4,7 @@ import json
from django.contrib.gis.geos import LinearRing, Point, Polygon
from django.core import serializers
from django.test import TestCase, mock, skipUnlessDBFeature
from django.utils import six
from django.test import TestCase, skipUnlessDBFeature
from .models import City, MultiFields, PennsylvaniaCity
@ -89,14 +88,6 @@ class GeoJSONSerializerTests(TestCase):
[1564802, 5613214]
)
@mock.patch('django.contrib.gis.serializers.geojson.HAS_GDAL', False)
def test_without_gdal(self):
# Without coordinate transformation, the serialization should succeed:
serializers.serialize('geojson', City.objects.all())
with six.assertRaisesRegex(self, serializers.base.SerializationError, '.*GDAL is not installed'):
# Coordinate transformations need GDAL
serializers.serialize('geojson', City.objects.all(), srid=2847)
def test_deserialization_exception(self):
"""
GeoJSON cannot be deserialized.

View File

@ -8,7 +8,6 @@ from unittest import skipUnless
from django.contrib.gis.db import models
from django.contrib.gis.db.models.functions import Area, Distance
from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.measure import D
from django.db import connection
from django.db.models.functions import Cast
@ -70,7 +69,6 @@ class GeographyTest(TestCase):
with self.assertRaises(ValueError):
City.objects.get(point__exact=htown.point)
@skipUnless(HAS_GDAL, "GDAL is required.")
def test05_geography_layermapping(self):
"Testing LayerMapping support on models with geography fields."
# There is a similar test in `layermap` that uses the same data set,

View File

@ -1092,19 +1092,6 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
self.assertEqual(g1.srid, 4326)
self.assertIsNot(g1, g, "Clone didn't happen")
with mock.patch('django.contrib.gis.gdal.HAS_GDAL', False):
g = GEOSGeometry('POINT (-104.609 38.255)', 4326)
gt = g.tuple
g.transform(4326)
self.assertEqual(g.tuple, gt)
self.assertEqual(g.srid, 4326)
g = GEOSGeometry('POINT (-104.609 38.255)', 4326)
g1 = g.transform(4326, clone=True)
self.assertEqual(g1.tuple, g.tuple)
self.assertEqual(g1.srid, 4326)
self.assertIsNot(g1, g, "Clone didn't happen")
@skipUnless(HAS_GDAL, "GDAL is required.")
def test_transform_nosrid(self):
""" Testing `transform` method (no SRID or negative SRID) """
@ -1125,17 +1112,6 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
with self.assertRaises(GEOSException):
g.transform(2774, clone=True)
@mock.patch('django.contrib.gis.gdal.HAS_GDAL', False)
def test_transform_nogdal(self):
""" Testing `transform` method (GDAL not available) """
g = GEOSGeometry('POINT (-104.609 38.255)', 4326)
with self.assertRaises(GEOSException):
g.transform(2774)
g = GEOSGeometry('POINT (-104.609 38.255)', 4326)
with self.assertRaises(GEOSException):
g.transform(2774, clone=True)
def test_extent(self):
"Testing `extent` method."
# The xmin, ymin, xmax, ymax of the MultiPoint should be returned.

View File

@ -1,9 +1,6 @@
from __future__ import unicode_literals
from unittest import skipUnless
from django.contrib.gis.db.models import fields
from django.contrib.gis.gdal import HAS_GDAL
from django.core.exceptions import ImproperlyConfigured
from django.db import connection, migrations, models
from django.db.migrations.migration import Migration
@ -117,7 +114,6 @@ class OperationTests(TransactionTestCase):
self.assertSpatialIndexExists('gis_neighborhood', 'heatmap')
@skipIfDBFeature('supports_raster')
@skipUnless(HAS_GDAL, 'A different error is raised if GDAL is not installed.')
def test_create_raster_model_on_db_without_raster_support(self):
"""
Test creating a model with a raster field on a db without raster support.
@ -127,7 +123,6 @@ class OperationTests(TransactionTestCase):
self.set_up_test_model(True)
@skipIfDBFeature('supports_raster')
@skipUnless(HAS_GDAL, 'A different error is raised if GDAL is not installed.')
def test_add_raster_field_on_db_without_raster_support(self):
"""
Test adding a raster field on a db without raster support.

View File

@ -2,7 +2,6 @@ from __future__ import unicode_literals
import os
import re
from unittest import skipUnless
from django.contrib.gis.gdal import HAS_GDAL
from django.core.management import call_command
@ -20,9 +19,8 @@ if HAS_GDAL:
from .models import AllOGRFields
@skipUnless(HAS_GDAL, "InspectDbTests needs GDAL support")
@skipUnlessDBFeature("gis_enabled")
class InspectDbTests(TestCase):
@skipUnlessDBFeature("gis_enabled")
def test_geom_columns(self):
"""
Test the geo-enabled inspectdb command.
@ -60,7 +58,7 @@ class InspectDbTests(TestCase):
self.assertIn('poly = models.GeometryField(', output)
@skipUnless(HAS_GDAL, "OGRInspectTest needs GDAL support")
@skipUnlessDBFeature("gis_enabled")
@modify_settings(
INSTALLED_APPS={'append': 'django.contrib.gis'},
)

View File

@ -5,7 +5,6 @@ import os
import unittest
from copy import copy
from decimal import Decimal
from unittest import skipUnless
from django.conf import settings
from django.contrib.gis.gdal import HAS_GDAL
@ -39,7 +38,6 @@ NUMS = [1, 2, 1, 19, 1] # Number of polygons for each.
STATES = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
@skipUnless(HAS_GDAL, "LayerMapTest needs GDAL support")
@skipUnlessDBFeature("gis_enabled")
class LayerMapTest(TestCase):
@ -337,7 +335,6 @@ class OtherRouter(object):
return True
@skipUnless(HAS_GDAL, "LayerMapRouterTest needs GDAL support")
@skipUnlessDBFeature("gis_enabled")
@override_settings(DATABASE_ROUTERS=[OtherRouter()])
class LayerMapRouterTest(TestCase):

View File

@ -1,23 +1,24 @@
from django.contrib.gis.gdal import HAS_GDAL
from ..models import models
if HAS_GDAL:
class RasterModel(models.Model):
rast = models.RasterField('A Verbose Raster Name', null=True, srid=4326, spatial_index=True, blank=True)
rastprojected = models.RasterField('A Projected Raster Table', srid=3086, null=True)
geom = models.PointField(null=True)
class RasterModel(models.Model):
rast = models.RasterField('A Verbose Raster Name', null=True, srid=4326, spatial_index=True, blank=True)
rastprojected = models.RasterField('A Projected Raster Table', srid=3086, null=True)
geom = models.PointField(null=True)
class Meta:
required_db_features = ['supports_raster']
class Meta:
required_db_features = ['supports_raster']
def __str__(self):
return str(self.id)
def __str__(self):
return str(self.id)
class RasterRelatedModel(models.Model):
rastermodel = models.ForeignKey(RasterModel, models.CASCADE)
class Meta:
required_db_features = ['supports_raster']
class RasterRelatedModel(models.Model):
rastermodel = models.ForeignKey(RasterModel, models.CASCADE)
class Meta:
required_db_features = ['supports_raster']
def __str__(self):
return str(self.id)
def __str__(self):
return str(self.id)

View File

@ -7,18 +7,14 @@ from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.measure import D
from django.contrib.gis.shortcuts import numpy
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Q
from django.test import (
TestCase, TransactionTestCase, mock, skipUnlessDBFeature,
)
from django.test import TransactionTestCase, skipUnlessDBFeature
from ..data.rasters.textrasters import JSON_RASTER
from ..models import models
from .models import RasterModel, RasterRelatedModel
if HAS_GDAL:
from django.contrib.gis.gdal import GDALRaster
from .models import RasterModel, RasterRelatedModel
@skipUnlessDBFeature('supports_raster')
@ -330,12 +326,3 @@ class RasterFieldTest(TransactionTestCase):
msg = "Couldn't create spatial object from lookup value '%s'." % obj
with self.assertRaisesMessage(ValueError, msg):
RasterModel.objects.filter(geom__intersects=obj)
@mock.patch('django.contrib.gis.db.models.fields.HAS_GDAL', False)
class RasterFieldWithoutGDALTest(TestCase):
def test_raster_field_without_gdal_exception(self):
msg = 'RasterField requires GDAL.'
with self.assertRaisesMessage(ImproperlyConfigured, msg):
models.OriginalRasterField()

View File

@ -1,14 +1,10 @@
from unittest import skipUnless
from django.contrib.gis import forms
from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.geos import GEOSGeometry
from django.forms import ValidationError
from django.test import SimpleTestCase, override_settings, skipUnlessDBFeature
from django.utils.html import escape
@skipUnless(HAS_GDAL, "GeometryFieldTest needs GDAL support")
@skipUnlessDBFeature("gis_enabled")
class GeometryFieldTest(SimpleTestCase):
@ -89,7 +85,6 @@ class GeometryFieldTest(SimpleTestCase):
self.assertFalse(form.has_changed())
@skipUnless(HAS_GDAL, "SpecializedFieldTest needs GDAL support")
@skipUnlessDBFeature("gis_enabled")
class SpecializedFieldTest(SimpleTestCase):
def setUp(self):
@ -260,7 +255,6 @@ class SpecializedFieldTest(SimpleTestCase):
self.assertFalse(GeometryForm(data={'g': invalid.wkt}).is_valid())
@skipUnless(HAS_GDAL, "OSMWidgetTest needs GDAL support")
@skipUnlessDBFeature("gis_enabled")
class OSMWidgetTest(SimpleTestCase):
def setUp(self):
@ -302,7 +296,6 @@ class OSMWidgetTest(SimpleTestCase):
rendered)
@skipUnless(HAS_GDAL, "CustomGeometryWidgetTest needs GDAL support")
@skipUnlessDBFeature("gis_enabled")
class CustomGeometryWidgetTest(SimpleTestCase):

View File

@ -1,8 +1,7 @@
import re
import unittest
from django.contrib.gis.gdal import HAS_GDAL
from django.test import mock, skipUnlessDBFeature
from django.test import skipUnlessDBFeature
from django.utils import six
from .utils import SpatialRefSys, oracle, postgis, spatialite
@ -51,7 +50,6 @@ test_srs = ({
})
@unittest.skipUnless(HAS_GDAL, "SpatialRefSysTest needs gdal support")
@skipUnlessDBFeature("has_spatialrefsys_table")
class SpatialRefSysTest(unittest.TestCase):
@ -61,13 +59,6 @@ class SpatialRefSysTest(unittest.TestCase):
self.assertEqual(unit_name, 'degree')
self.assertAlmostEqual(unit, 0.01745329251994328)
@mock.patch('django.contrib.gis.gdal.HAS_GDAL', False)
def test_get_units_without_gdal(self):
epsg_4326 = next(f for f in test_srs if f['srid'] == 4326)
unit, unit_name = SpatialRefSys().get_units(epsg_4326['wkt'])
self.assertEqual(unit_name, 'degree')
self.assertAlmostEqual(unit, 0.01745329251994328)
def test_retrieve(self):
"""
Test retrieval of SpatialRefSys model objects.