2
0
Эх сурвалжийг харах

Replaced HAS_SPATIAL_DB by testing database feature

Refs #22632. This should be the base for using more database
features to exclude specific backends in GIS tests.
Thanks Tim Graham for the review.
Claude Paroz 10 жил өмнө
parent
commit
6295ea0027

+ 4 - 0
django/contrib/gis/db/backends/base.py

@@ -9,6 +9,10 @@ from django.utils import six
 from django.utils.encoding import python_2_unicode_compatible
 
 
+class BaseSpatialFeatures(object):
+    gis_enabled = True
+
+
 class BaseSpatialOperations(object):
     """
     This module holds the base `BaseSpatialBackend` object, which is

+ 10 - 1
django/contrib/gis/db/backends/mysql/base.py

@@ -1,12 +1,21 @@
-from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper
+from django.db.backends.mysql.base import (
+    DatabaseWrapper as MySQLDatabaseWrapper,
+    DatabaseFeatures as MySQLDatabaseFeatures,
+)
+from django.contrib.gis.db.backends.base import BaseSpatialFeatures
 from django.contrib.gis.db.backends.mysql.creation import MySQLCreation
 from django.contrib.gis.db.backends.mysql.introspection import MySQLIntrospection
 from django.contrib.gis.db.backends.mysql.operations import MySQLOperations
 
 
+class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
+    pass
+
+
 class DatabaseWrapper(MySQLDatabaseWrapper):
     def __init__(self, *args, **kwargs):
         super(DatabaseWrapper, self).__init__(*args, **kwargs)
+        self.features = DatabaseFeatures(self)
         self.creation = MySQLCreation(self)
         self.ops = MySQLOperations(self)
         self.introspection = MySQLIntrospection(self)

+ 10 - 1
django/contrib/gis/db/backends/oracle/base.py

@@ -1,12 +1,21 @@
-from django.db.backends.oracle.base import DatabaseWrapper as OracleDatabaseWrapper
+from django.db.backends.oracle.base import (
+    DatabaseWrapper as OracleDatabaseWrapper,
+    DatabaseFeatures as OracleDatabaseFeatures,
+)
+from django.contrib.gis.db.backends.base import BaseSpatialFeatures
 from django.contrib.gis.db.backends.oracle.creation import OracleCreation
 from django.contrib.gis.db.backends.oracle.introspection import OracleIntrospection
 from django.contrib.gis.db.backends.oracle.operations import OracleOperations
 
 
+class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures):
+    pass
+
+
 class DatabaseWrapper(OracleDatabaseWrapper):
     def __init__(self, *args, **kwargs):
         super(DatabaseWrapper, self).__init__(*args, **kwargs)
+        self.features = DatabaseFeatures(self)
         self.ops = OracleOperations(self)
         self.creation = OracleCreation(self)
         self.introspection = OracleIntrospection(self)

+ 10 - 1
django/contrib/gis/db/backends/postgis/base.py

@@ -1,15 +1,24 @@
 from django.db.backends.creation import NO_DB_ALIAS
-from django.db.backends.postgresql_psycopg2.base import DatabaseWrapper as Psycopg2DatabaseWrapper
+from django.db.backends.postgresql_psycopg2.base import (
+    DatabaseWrapper as Psycopg2DatabaseWrapper,
+    DatabaseFeatures as Psycopg2DatabaseFeatures
+)
+from django.contrib.gis.db.backends.base import BaseSpatialFeatures
 from django.contrib.gis.db.backends.postgis.creation import PostGISCreation
 from django.contrib.gis.db.backends.postgis.introspection import PostGISIntrospection
 from django.contrib.gis.db.backends.postgis.operations import PostGISOperations
 from django.contrib.gis.db.backends.postgis.schema import PostGISSchemaEditor
 
 
+class DatabaseFeatures(BaseSpatialFeatures, Psycopg2DatabaseFeatures):
+    pass
+
+
 class DatabaseWrapper(Psycopg2DatabaseWrapper):
     def __init__(self, *args, **kwargs):
         super(DatabaseWrapper, self).__init__(*args, **kwargs)
         if kwargs.get('alias', '') != NO_DB_ALIAS:
+            self.features = DatabaseFeatures(self)
             self.creation = PostGISCreation(self)
             self.ops = PostGISOperations(self)
             self.introspection = PostGISIntrospection(self)

+ 8 - 1
django/contrib/gis/db/backends/spatialite/base.py

@@ -4,7 +4,9 @@ from django.conf import settings
 
 from django.core.exceptions import ImproperlyConfigured
 from django.db.backends.sqlite3.base import (Database,
-    DatabaseWrapper as SQLiteDatabaseWrapper, SQLiteCursorWrapper)
+    DatabaseWrapper as SQLiteDatabaseWrapper,
+    DatabaseFeatures as SQLiteDatabaseFeatures, SQLiteCursorWrapper)
+from django.contrib.gis.db.backends.base import BaseSpatialFeatures
 from django.contrib.gis.db.backends.spatialite.client import SpatiaLiteClient
 from django.contrib.gis.db.backends.spatialite.creation import SpatiaLiteCreation
 from django.contrib.gis.db.backends.spatialite.introspection import SpatiaLiteIntrospection
@@ -13,6 +15,10 @@ from django.contrib.gis.db.backends.spatialite.schema import SpatialiteSchemaEdi
 from django.utils import six
 
 
+class DatabaseFeatures(BaseSpatialFeatures, SQLiteDatabaseFeatures):
+    pass
+
+
 class DatabaseWrapper(SQLiteDatabaseWrapper):
     def __init__(self, *args, **kwargs):
         # Before we get too far, make sure pysqlite 2.5+ is installed.
@@ -33,6 +39,7 @@ class DatabaseWrapper(SQLiteDatabaseWrapper):
                                        'SPATIALITE_LIBRARY_PATH in your settings.'
                                        )
         super(DatabaseWrapper, self).__init__(*args, **kwargs)
+        self.features = DatabaseFeatures(self)
         self.ops = SpatiaLiteOperations(self)
         self.client = SpatiaLiteClient(self)
         self.creation = SpatiaLiteCreation(self)

+ 7 - 6
django/contrib/gis/tests/distapp/tests.py

@@ -7,23 +7,24 @@ from django.db.models import Q
 from django.contrib.gis.geos import HAS_GEOS
 from django.contrib.gis.measure import D  # alias for Distance
 from django.contrib.gis.tests.utils import (
-    HAS_SPATIAL_DB, mysql, oracle, postgis, spatialite, no_oracle, no_spatialite
+    mysql, oracle, postgis, spatialite, no_oracle, no_spatialite
 )
-from django.test import TestCase
+from django.test import TestCase, skipUnlessDBFeature
 
-if HAS_GEOS and HAS_SPATIAL_DB:
+if HAS_GEOS:
     from django.contrib.gis.geos import GEOSGeometry, LineString
 
     from .models import (AustraliaCity, Interstate, SouthTexasInterstate,
         SouthTexasCity, SouthTexasCityFt, CensusZipcode, SouthTexasZipcode)
 
 
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB and not mysql,
-    "Geos and spatial db (not mysql) are required.")
+@skipUnless(HAS_GEOS and not mysql,
+    "GEOS and spatial db (not mysql) are required.")
+@skipUnlessDBFeature("gis_enabled")
 class DistanceTest(TestCase):
     fixtures = ['initial']
 
-    if HAS_GEOS and HAS_SPATIAL_DB:
+    if HAS_GEOS:
         # A point we are testing distances with -- using a WGS84
         # coordinate that'll be implicitly transformed to that to
         # the coordinate system of the field, EPSG:32140 (Texas South Central

+ 3 - 6
django/contrib/gis/tests/geoadmin/tests.py

@@ -1,19 +1,16 @@
 from __future__ import unicode_literals
 
-from unittest import skipUnless
-
 from django.contrib.gis.geos import HAS_GEOS
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
-from django.test import TestCase, override_settings
+from django.test import TestCase, override_settings, skipUnlessDBFeature
 
-if HAS_GEOS and HAS_SPATIAL_DB:
+if HAS_GEOS:
     from django.contrib.gis import admin
     from django.contrib.gis.geos import Point
 
     from .models import City
 
 
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
+@skipUnlessDBFeature("gis_enabled")
 @override_settings(ROOT_URLCONF='django.contrib.gis.tests.geoadmin.urls')
 class GeoAdminTest(TestCase):
 

+ 4 - 3
django/contrib/gis/tests/geoapp/test_feeds.py

@@ -6,8 +6,9 @@ from xml.dom import minidom
 from django.conf import settings
 from django.contrib.sites.models import Site
 from django.contrib.gis.geos import HAS_GEOS
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
-from django.test import TestCase, modify_settings, override_settings
+from django.test import (
+    TestCase, modify_settings, override_settings, skipUnlessDBFeature
+)
 
 if HAS_GEOS:
     from .models import City
@@ -15,7 +16,7 @@ if HAS_GEOS:
 
 @modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
 @override_settings(ROOT_URLCONF='django.contrib.gis.tests.geoapp.urls')
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
+@skipUnlessDBFeature("gis_enabled")
 class GeoFeedTest(TestCase):
     fixtures = ['initial']
 

+ 2 - 3
django/contrib/gis/tests/geoapp/test_regress.py

@@ -7,15 +7,14 @@ from unittest import skipUnless
 from django.contrib.gis.geos import HAS_GEOS
 from django.contrib.gis.tests.utils import no_mysql, no_spatialite
 from django.contrib.gis.shortcuts import render_to_kmz
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
 from django.db.models import Count, Min
-from django.test import TestCase
+from django.test import TestCase, skipUnlessDBFeature
 
 if HAS_GEOS:
     from .models import City, PennsylvaniaCity, State, Truth
 
 
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
+@skipUnlessDBFeature("gis_enabled")
 class GeoRegressionTests(TestCase):
     fixtures = ['initial']
 

+ 4 - 3
django/contrib/gis/tests/geoapp/test_sitemaps.py

@@ -8,9 +8,10 @@ import zipfile
 
 from django.conf import settings
 from django.contrib.gis.geos import HAS_GEOS
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
 from django.contrib.sites.models import Site
-from django.test import TestCase, modify_settings, override_settings
+from django.test import (
+    TestCase, modify_settings, override_settings, skipUnlessDBFeature
+)
 from django.utils.deprecation import RemovedInDjango20Warning
 
 if HAS_GEOS:
@@ -19,7 +20,7 @@ if HAS_GEOS:
 
 @modify_settings(INSTALLED_APPS={'append': ['django.contrib.sites', 'django.contrib.sitemaps']})
 @override_settings(ROOT_URLCONF='django.contrib.gis.tests.geoapp.urls')
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
+@skipUnlessDBFeature("gis_enabled")
 class GeoSitemapTest(TestCase):
 
     def setUp(self):

+ 5 - 6
django/contrib/gis/tests/geoapp/tests.py

@@ -8,9 +8,8 @@ from django.db import connection
 from django.contrib.gis import gdal
 from django.contrib.gis.geos import HAS_GEOS
 from django.contrib.gis.tests.utils import (
-    HAS_SPATIAL_DB, no_mysql, no_oracle, no_spatialite,
-    mysql, oracle, postgis, spatialite)
-from django.test import TestCase
+    no_mysql, no_oracle, no_spatialite, mysql, oracle, postgis, spatialite)
+from django.test import TestCase, skipUnlessDBFeature
 from django.utils import six
 
 if HAS_GEOS:
@@ -28,7 +27,7 @@ def postgis_bug_version():
     return spatial_version and (2, 0, 0) <= spatial_version <= (2, 0, 1)
 
 
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
+@skipUnlessDBFeature("gis_enabled")
 class GeoModelTest(TestCase):
     fixtures = ['initial']
 
@@ -205,7 +204,7 @@ class GeoModelTest(TestCase):
         self.assertIsInstance(cities2[0].point, Point)
 
 
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
+@skipUnlessDBFeature("gis_enabled")
 class GeoLookupTest(TestCase):
     fixtures = ['initial']
 
@@ -397,7 +396,7 @@ class GeoLookupTest(TestCase):
             self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, intersects_mask)).name)
 
 
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
+@skipUnlessDBFeature("gis_enabled")
 class GeoQuerySetTest(TestCase):
     fixtures = ['initial']
 

+ 5 - 5
django/contrib/gis/tests/gis_migrations/test_commands.py

@@ -1,13 +1,14 @@
 from __future__ import unicode_literals
 
-from unittest import skipUnless
-
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
 from django.core.management import call_command
 from django.db import connection
-from django.test import override_settings, override_system_checks, TransactionTestCase
+from django.test import (
+    override_settings, override_system_checks, skipUnlessDBFeature,
+    TransactionTestCase
+)
 
 
+@skipUnlessDBFeature("gis_enabled")
 class MigrateTests(TransactionTestCase):
     """
     Tests running the migrate command in Geodjango.
@@ -26,7 +27,6 @@ class MigrateTests(TransactionTestCase):
         with connection.cursor() as cursor:
             self.assertNotIn(table, connection.introspection.get_table_list(cursor))
 
-    @skipUnless(HAS_SPATIAL_DB, "Spatial db is required.")
     @override_system_checks([])
     @override_settings(MIGRATION_MODULES={"gis": "django.contrib.gis.tests.gis_migrations.migrations"})
     def test_migrate_gis(self):

+ 3 - 6
django/contrib/gis/tests/gis_migrations/test_operations.py

@@ -1,14 +1,11 @@
 from __future__ import unicode_literals
 
-from unittest import skipUnless
-
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
 from django.db import connection, migrations, models
 from django.db.migrations.migration import Migration
 from django.db.migrations.state import ProjectState
-from django.test import TransactionTestCase
+from django.test import skipUnlessDBFeature, TransactionTestCase
 
-if HAS_SPATIAL_DB:
+if connection.features.gis_enabled:
     from django.contrib.gis.db.models import fields
     try:
         GeometryColumns = connection.ops.geometry_columns()
@@ -17,7 +14,7 @@ if HAS_SPATIAL_DB:
         HAS_GEOMETRY_COLUMNS = False
 
 
-@skipUnless(HAS_SPATIAL_DB, "Spatial db is required.")
+@skipUnlessDBFeature("gis_enabled")
 class OperationTests(TransactionTestCase):
     available_apps = ["django.contrib.gis.tests.gis_migrations"]
 

+ 5 - 4
django/contrib/gis/tests/inspectapp/tests.py

@@ -5,10 +5,9 @@ from unittest import skipUnless
 
 from django.core.management import call_command
 from django.db import connections
-from django.test import TestCase
+from django.test import TestCase, skipUnlessDBFeature
 from django.contrib.gis.gdal import HAS_GDAL
 from django.contrib.gis.geometry.test_data import TEST_DATA
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
 from django.utils.six import StringIO
 
 if HAS_GDAL:
@@ -18,7 +17,8 @@ if HAS_GDAL:
     from .models import AllOGRFields
 
 
-@skipUnless(HAS_GDAL and HAS_SPATIAL_DB, "GDAL and spatial db are required.")
+@skipUnless(HAS_GDAL, "InspectDbTests needs GDAL support")
+@skipUnlessDBFeature("gis_enabled")
 class InspectDbTests(TestCase):
     def test_geom_columns(self):
         """
@@ -34,7 +34,8 @@ class InspectDbTests(TestCase):
         self.assertIn('objects = models.GeoManager()', output)
 
 
-@skipUnless(HAS_GDAL and HAS_SPATIAL_DB, "GDAL and spatial db are required.")
+@skipUnless(HAS_GDAL, "OGRInspectTest needs GDAL support")
+@skipUnlessDBFeature("gis_enabled")
 class OGRInspectTest(TestCase):
     maxDiff = 1024
 

+ 6 - 4
django/contrib/gis/tests/layermap/tests.py

@@ -8,10 +8,10 @@ import unittest
 from unittest import skipUnless
 
 from django.contrib.gis.gdal import HAS_GDAL
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB, mysql
+from django.contrib.gis.tests.utils import mysql
 from django.db import router
 from django.conf import settings
-from django.test import TestCase
+from django.test import TestCase, skipUnlessDBFeature
 from django.utils._os import upath
 
 if HAS_GDAL:
@@ -36,7 +36,8 @@ NUMS = [1, 2, 1, 19, 1]  # Number of polygons for each.
 STATES = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
 
 
-@skipUnless(HAS_GDAL and HAS_SPATIAL_DB, "GDAL and spatial db are required.")
+@skipUnless(HAS_GDAL, "LayerMapTest needs GDAL support")
+@skipUnlessDBFeature("gis_enabled")
 class LayerMapTest(TestCase):
 
     def test_init(self):
@@ -319,7 +320,8 @@ class OtherRouter(object):
         return True
 
 
-@skipUnless(HAS_GDAL and HAS_SPATIAL_DB, "GDAL and spatial db are required.")
+@skipUnless(HAS_GDAL, "LayerMapRouterTest needs GDAL support")
+@skipUnlessDBFeature("gis_enabled")
 class LayerMapRouterTest(TestCase):
 
     def setUp(self):

+ 3 - 5
django/contrib/gis/tests/relatedapp/tests.py

@@ -1,10 +1,8 @@
 from __future__ import unicode_literals
 
-from unittest import skipUnless
-
 from django.contrib.gis.geos import HAS_GEOS
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB, mysql, no_mysql, no_oracle, no_spatialite
-from django.test import TestCase
+from django.contrib.gis.tests.utils import mysql, no_mysql, no_oracle, no_spatialite
+from django.test import TestCase, skipUnlessDBFeature
 
 if HAS_GEOS:
     from django.contrib.gis.db.models import Collect, Count, Extent, F, Union
@@ -14,7 +12,7 @@ if HAS_GEOS:
     from .models import City, Location, DirectoryEntry, Parcel, Book, Author, Article
 
 
-@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
+@skipUnlessDBFeature("gis_enabled")
 class RelatedGeoModelTest(TestCase):
     fixtures = ['initial']
 

+ 10 - 10
django/contrib/gis/tests/test_geoforms.py

@@ -2,17 +2,17 @@ from unittest import skipUnless
 
 from django.forms import ValidationError
 from django.contrib.gis.gdal import HAS_GDAL
-from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
-from django.test import SimpleTestCase
+from django.test import SimpleTestCase, skipUnlessDBFeature
 from django.utils import six
 from django.utils.html import escape
 
-if HAS_SPATIAL_DB:
+if HAS_GDAL:
     from django.contrib.gis import forms
     from django.contrib.gis.geos import GEOSGeometry
 
 
-@skipUnless(HAS_GDAL and HAS_SPATIAL_DB, "GeometryFieldTest needs gdal support and a spatial database")
+@skipUnless(HAS_GDAL, "GeometryFieldTest needs GDAL support")
+@skipUnlessDBFeature("gis_enabled")
 class GeometryFieldTest(SimpleTestCase):
 
     def test_init(self):
@@ -90,8 +90,8 @@ class GeometryFieldTest(SimpleTestCase):
         self.assertFalse(form.has_changed())
 
 
-@skipUnless(HAS_GDAL and HAS_SPATIAL_DB,
-    "SpecializedFieldTest needs gdal support and a spatial database")
+@skipUnless(HAS_GDAL, "SpecializedFieldTest needs GDAL support")
+@skipUnlessDBFeature("gis_enabled")
 class SpecializedFieldTest(SimpleTestCase):
     def setUp(self):
         self.geometries = {
@@ -258,8 +258,8 @@ class SpecializedFieldTest(SimpleTestCase):
             self.assertFalse(GeometryForm(data={'g': invalid.wkt}).is_valid())
 
 
-@skipUnless(HAS_GDAL and HAS_SPATIAL_DB,
-    "OSMWidgetTest needs gdal support and a spatial database")
+@skipUnless(HAS_GDAL, "OSMWidgetTest needs GDAL support")
+@skipUnlessDBFeature("gis_enabled")
 class OSMWidgetTest(SimpleTestCase):
     def setUp(self):
         self.geometries = {
@@ -300,8 +300,8 @@ class OSMWidgetTest(SimpleTestCase):
                 rendered)
 
 
-@skipUnless(HAS_GDAL and HAS_SPATIAL_DB,
-    "CustomGeometryWidgetTest needs gdal support and a spatial database")
+@skipUnless(HAS_GDAL, "CustomGeometryWidgetTest needs GDAL support")
+@skipUnlessDBFeature("gis_enabled")
 class CustomGeometryWidgetTest(SimpleTestCase):
 
     def test_custom_serialization_widget(self):

+ 0 - 9
django/contrib/gis/tests/utils.py

@@ -49,12 +49,3 @@ elif spatialite:
 else:
     HAS_SPATIALREFSYS = False
     SpatialRefSys = None
-
-
-def has_spatial_db():
-    # All databases must have spatial backends to run GeoDjango tests.
-    spatial_dbs = [name for name, db_dict in settings.DATABASES.items()
-        if db_dict['ENGINE'].startswith('django.contrib.gis')]
-    return len(spatial_dbs) == len(settings.DATABASES)
-
-HAS_SPATIAL_DB = has_spatial_db()

+ 1 - 0
django/db/backends/__init__.py

@@ -474,6 +474,7 @@ class BaseDatabaseWrapper(object):
 
 
 class BaseDatabaseFeatures(object):
+    gis_enabled = False
     allows_group_by_pk = False
     # True if django.db.backends.utils.typecast_timestamp is used on values
     # returned from dates() calls.

+ 1 - 2
tests/runtests.py

@@ -60,13 +60,12 @@ ALWAYS_MIDDLEWARE_CLASSES = (
 
 
 def get_test_modules():
-    from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
     modules = []
     discovery_paths = [
         (None, RUNTESTS_DIR),
         (CONTRIB_MODULE_PATH, CONTRIB_DIR)
     ]
-    if HAS_SPATIAL_DB:
+    if connection.features.gis_enabled:
         discovery_paths.append(
             ('django.contrib.gis.tests', os.path.join(CONTRIB_DIR, 'gis', 'tests'))
         )