mirror of https://github.com/django/django.git
Fixed #28665 -- Change some database exceptions to NotImplementedError per PEP 249.
This commit is contained in:
parent
7d8d630e37
commit
9d93dff333
|
@ -3,6 +3,7 @@ from django.contrib.gis.db.models.functions import Distance
|
||||||
from django.contrib.gis.measure import (
|
from django.contrib.gis.measure import (
|
||||||
Area as AreaMeasure, Distance as DistanceMeasure,
|
Area as AreaMeasure, Distance as DistanceMeasure,
|
||||||
)
|
)
|
||||||
|
from django.db.utils import NotSupportedError
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,7 +106,7 @@ class BaseSpatialOperations:
|
||||||
|
|
||||||
def check_expression_support(self, expression):
|
def check_expression_support(self, expression):
|
||||||
if isinstance(expression, self.disallowed_aggregates):
|
if isinstance(expression, self.disallowed_aggregates):
|
||||||
raise NotImplementedError(
|
raise NotSupportedError(
|
||||||
"%s spatial aggregation is not supported by this database backend." % expression.name
|
"%s spatial aggregation is not supported by this database backend." % expression.name
|
||||||
)
|
)
|
||||||
super().check_expression_support(expression)
|
super().check_expression_support(expression)
|
||||||
|
@ -115,7 +116,7 @@ class BaseSpatialOperations:
|
||||||
|
|
||||||
def spatial_function_name(self, func_name):
|
def spatial_function_name(self, func_name):
|
||||||
if func_name in self.unsupported_functions:
|
if func_name in self.unsupported_functions:
|
||||||
raise NotImplementedError("This backend doesn't support the %s function." % func_name)
|
raise NotSupportedError("This backend doesn't support the %s function." % func_name)
|
||||||
return self.function_names.get(func_name, self.geom_func_prefix + func_name)
|
return self.function_names.get(func_name, self.geom_func_prefix + func_name)
|
||||||
|
|
||||||
# Routines for getting the OGC-compliant models.
|
# Routines for getting the OGC-compliant models.
|
||||||
|
|
|
@ -13,7 +13,7 @@ from django.contrib.gis.measure import Distance
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db.backends.postgresql.operations import DatabaseOperations
|
from django.db.backends.postgresql.operations import DatabaseOperations
|
||||||
from django.db.models import Func, Value
|
from django.db.models import Func, Value
|
||||||
from django.db.utils import ProgrammingError
|
from django.db.utils import NotSupportedError, ProgrammingError
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.version import get_version_tuple
|
from django.utils.version import get_version_tuple
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
geom_type = f.geom_type
|
geom_type = f.geom_type
|
||||||
if f.geography:
|
if f.geography:
|
||||||
if f.srid != 4326:
|
if f.srid != 4326:
|
||||||
raise NotImplementedError('PostGIS only supports geography columns with an SRID of 4326.')
|
raise NotSupportedError('PostGIS only supports geography columns with an SRID of 4326.')
|
||||||
|
|
||||||
return 'geography(%s,%d)' % (geom_type, f.srid)
|
return 'geography(%s,%d)' % (geom_type, f.srid)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -9,6 +9,7 @@ from django.db.models import (
|
||||||
)
|
)
|
||||||
from django.db.models.expressions import Func, Value
|
from django.db.models.expressions import Func, Value
|
||||||
from django.db.models.functions import Cast
|
from django.db.models.functions import Cast
|
||||||
|
from django.db.utils import NotSupportedError
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
NUMERIC_TYPES = (int, float, Decimal)
|
NUMERIC_TYPES = (int, float, Decimal)
|
||||||
|
@ -123,7 +124,7 @@ class Area(OracleToleranceMixin, GeoFunc):
|
||||||
|
|
||||||
def as_sql(self, compiler, connection, **extra_context):
|
def as_sql(self, compiler, connection, **extra_context):
|
||||||
if not connection.features.supports_area_geodetic and self.geo_field.geodetic(connection):
|
if not connection.features.supports_area_geodetic and self.geo_field.geodetic(connection):
|
||||||
raise NotImplementedError('Area on geodetic coordinate systems not supported.')
|
raise NotSupportedError('Area on geodetic coordinate systems not supported.')
|
||||||
return super().as_sql(compiler, connection, **extra_context)
|
return super().as_sql(compiler, connection, **extra_context)
|
||||||
|
|
||||||
def as_sqlite(self, compiler, connection, **extra_context):
|
def as_sqlite(self, compiler, connection, **extra_context):
|
||||||
|
@ -316,7 +317,7 @@ class Length(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
||||||
|
|
||||||
def as_sql(self, compiler, connection, **extra_context):
|
def as_sql(self, compiler, connection, **extra_context):
|
||||||
if self.geo_field.geodetic(connection) and not connection.features.supports_length_geodetic:
|
if self.geo_field.geodetic(connection) and not connection.features.supports_length_geodetic:
|
||||||
raise NotImplementedError("This backend doesn't support Length on geodetic fields")
|
raise NotSupportedError("This backend doesn't support Length on geodetic fields")
|
||||||
return super().as_sql(compiler, connection, **extra_context)
|
return super().as_sql(compiler, connection, **extra_context)
|
||||||
|
|
||||||
def as_postgresql(self, compiler, connection):
|
def as_postgresql(self, compiler, connection):
|
||||||
|
@ -372,7 +373,7 @@ class Perimeter(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
||||||
def as_postgresql(self, compiler, connection):
|
def as_postgresql(self, compiler, connection):
|
||||||
function = None
|
function = None
|
||||||
if self.geo_field.geodetic(connection) and not self.source_is_geography():
|
if self.geo_field.geodetic(connection) and not self.source_is_geography():
|
||||||
raise NotImplementedError("ST_Perimeter cannot use a non-projected non-geography field.")
|
raise NotSupportedError("ST_Perimeter cannot use a non-projected non-geography field.")
|
||||||
dim = min(f.dim for f in self.get_source_fields())
|
dim = min(f.dim for f in self.get_source_fields())
|
||||||
if dim > 2:
|
if dim > 2:
|
||||||
function = connection.ops.perimeter3d
|
function = connection.ops.perimeter3d
|
||||||
|
@ -380,7 +381,7 @@ class Perimeter(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
||||||
|
|
||||||
def as_sqlite(self, compiler, connection):
|
def as_sqlite(self, compiler, connection):
|
||||||
if self.geo_field.geodetic(connection):
|
if self.geo_field.geodetic(connection):
|
||||||
raise NotImplementedError("Perimeter cannot use a non-projected field.")
|
raise NotSupportedError("Perimeter cannot use a non-projected field.")
|
||||||
return super().as_sql(compiler, connection)
|
return super().as_sql(compiler, connection)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db.models.aggregates import StdDev
|
from django.db.models.aggregates import StdDev
|
||||||
from django.db.utils import ProgrammingError
|
from django.db.utils import NotSupportedError, ProgrammingError
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
|
|
||||||
|
@ -269,9 +269,9 @@ class BaseDatabaseFeatures:
|
||||||
"""Confirm support for STDDEV and related stats functions."""
|
"""Confirm support for STDDEV and related stats functions."""
|
||||||
try:
|
try:
|
||||||
self.connection.ops.check_expression_support(StdDev(1))
|
self.connection.ops.check_expression_support(StdDev(1))
|
||||||
return True
|
except NotSupportedError:
|
||||||
except NotImplementedError:
|
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def introspected_boolean_field_type(self, field=None):
|
def introspected_boolean_field_type(self, field=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -579,7 +579,7 @@ class BaseDatabaseOperations:
|
||||||
This is used on specific backends to rule out known expressions
|
This is used on specific backends to rule out known expressions
|
||||||
that have problematic or nonexistent implementations. If the
|
that have problematic or nonexistent implementations. If the
|
||||||
expression has a known problem, the backend should raise
|
expression has a known problem, the backend should raise
|
||||||
NotImplementedError.
|
NotSupportedError.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if isinstance(output_field, bad_fields):
|
if isinstance(output_field, bad_fields):
|
||||||
raise NotImplementedError(
|
raise utils.NotSupportedError(
|
||||||
'You cannot use Sum, Avg, StdDev, and Variance '
|
'You cannot use Sum, Avg, StdDev, and Variance '
|
||||||
'aggregations on date/time fields in sqlite3 '
|
'aggregations on date/time fields in sqlite3 '
|
||||||
'since date/time is saved as text.'
|
'since date/time is saved as text.'
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Lookup:
|
||||||
# a bilateral transformation on a nested QuerySet: that won't work.
|
# a bilateral transformation on a nested QuerySet: that won't work.
|
||||||
from django.db.models.sql.query import Query # avoid circular import
|
from django.db.models.sql.query import Query # avoid circular import
|
||||||
if isinstance(rhs, Query):
|
if isinstance(rhs, Query):
|
||||||
raise NotImplementedError("Bilateral transformations on nested querysets are not supported.")
|
raise NotImplementedError("Bilateral transformations on nested querysets are not implemented.")
|
||||||
self.bilateral_transforms = bilateral_transforms
|
self.bilateral_transforms = bilateral_transforms
|
||||||
|
|
||||||
def apply_bilateral_transforms(self, value):
|
def apply_bilateral_transforms(self, value):
|
||||||
|
|
|
@ -198,7 +198,9 @@ Backwards incompatible changes in 2.1
|
||||||
Database backend API
|
Database backend API
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
* ...
|
* To adhere to :pep:`249`, exceptions where a database doesn't support a
|
||||||
|
feature are changed from :exc:`NotImplementedError` to
|
||||||
|
:exc:`django.db.NotSupportedError`.
|
||||||
|
|
||||||
:mod:`django.contrib.gis`
|
:mod:`django.contrib.gis`
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
|
@ -4,6 +4,7 @@ import unittest
|
||||||
|
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models import Avg, StdDev, Sum, Variance
|
from django.db.models import Avg, StdDev, Sum, Variance
|
||||||
|
from django.db.utils import NotSupportedError
|
||||||
from django.test import TestCase, TransactionTestCase, override_settings
|
from django.test import TestCase, TransactionTestCase, override_settings
|
||||||
|
|
||||||
from ..models import Item, Object, Square
|
from ..models import Item, Object, Square
|
||||||
|
@ -34,13 +35,13 @@ class Tests(TestCase):
|
||||||
Raise NotImplementedError when aggregating on date/time fields (#19360).
|
Raise NotImplementedError when aggregating on date/time fields (#19360).
|
||||||
"""
|
"""
|
||||||
for aggregate in (Sum, Avg, Variance, StdDev):
|
for aggregate in (Sum, Avg, Variance, StdDev):
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotSupportedError):
|
||||||
Item.objects.all().aggregate(aggregate('time'))
|
Item.objects.all().aggregate(aggregate('time'))
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotSupportedError):
|
||||||
Item.objects.all().aggregate(aggregate('date'))
|
Item.objects.all().aggregate(aggregate('date'))
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotSupportedError):
|
||||||
Item.objects.all().aggregate(aggregate('last_modified'))
|
Item.objects.all().aggregate(aggregate('last_modified'))
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotSupportedError):
|
||||||
Item.objects.all().aggregate(
|
Item.objects.all().aggregate(
|
||||||
**{'complex': aggregate('last_modified') + aggregate('last_modified')}
|
**{'complex': aggregate('last_modified') + aggregate('last_modified')}
|
||||||
)
|
)
|
||||||
|
|
|
@ -319,7 +319,7 @@ class BilateralTransformTests(TestCase):
|
||||||
|
|
||||||
def test_bilateral_inner_qs(self):
|
def test_bilateral_inner_qs(self):
|
||||||
with register_lookup(models.CharField, UpperBilateralTransform):
|
with register_lookup(models.CharField, UpperBilateralTransform):
|
||||||
msg = 'Bilateral transformations on nested querysets are not supported.'
|
msg = 'Bilateral transformations on nested querysets are not implemented.'
|
||||||
with self.assertRaisesMessage(NotImplementedError, msg):
|
with self.assertRaisesMessage(NotImplementedError, msg):
|
||||||
Author.objects.filter(name__upper__in=Author.objects.values_list('name'))
|
Author.objects.filter(name__upper__in=Author.objects.values_list('name'))
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.contrib.gis.db.models.functions import (
|
||||||
)
|
)
|
||||||
from django.contrib.gis.geos import GEOSGeometry, LineString, Point
|
from django.contrib.gis.geos import GEOSGeometry, LineString, Point
|
||||||
from django.contrib.gis.measure import D # alias for Distance
|
from django.contrib.gis.measure import D # alias for Distance
|
||||||
from django.db import connection
|
from django.db import NotSupportedError, connection
|
||||||
from django.db.models import F, Q
|
from django.db.models import F, Q
|
||||||
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||||
|
|
||||||
|
@ -474,7 +474,7 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
# TODO: test with spheroid argument (True and False)
|
# TODO: test with spheroid argument (True and False)
|
||||||
else:
|
else:
|
||||||
# Does not support geodetic coordinate systems.
|
# Does not support geodetic coordinate systems.
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotSupportedError):
|
||||||
list(Interstate.objects.annotate(length=Length('path')))
|
list(Interstate.objects.annotate(length=Length('path')))
|
||||||
|
|
||||||
# Now doing length on a projected coordinate system.
|
# Now doing length on a projected coordinate system.
|
||||||
|
@ -513,7 +513,7 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
if connection.features.supports_perimeter_geodetic:
|
if connection.features.supports_perimeter_geodetic:
|
||||||
self.assertAlmostEqual(qs1[0].perim.m, 18406.3818954314, 3)
|
self.assertAlmostEqual(qs1[0].perim.m, 18406.3818954314, 3)
|
||||||
else:
|
else:
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotSupportedError):
|
||||||
list(qs1)
|
list(qs1)
|
||||||
# But should work fine when transformed to projected coordinates
|
# But should work fine when transformed to projected coordinates
|
||||||
qs2 = CensusZipcode.objects.annotate(perim=Perimeter(Transform('poly', 32140))).filter(name='77002')
|
qs2 = CensusZipcode.objects.annotate(perim=Perimeter(Transform('poly', 32140))).filter(name='77002')
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.contrib.gis.geos import (
|
||||||
GEOSGeometry, LineString, Point, Polygon, fromstr,
|
GEOSGeometry, LineString, Point, Polygon, fromstr,
|
||||||
)
|
)
|
||||||
from django.contrib.gis.measure import Area
|
from django.contrib.gis.measure import Area
|
||||||
from django.db import connection
|
from django.db import NotSupportedError, connection
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
def test_asgeojson(self):
|
def test_asgeojson(self):
|
||||||
# Only PostGIS and SpatiaLite support GeoJSON.
|
# Only PostGIS and SpatiaLite support GeoJSON.
|
||||||
if not connection.features.has_AsGeoJSON_function:
|
if not connection.features.has_AsGeoJSON_function:
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotSupportedError):
|
||||||
list(Country.objects.annotate(json=functions.AsGeoJSON('mpoly')))
|
list(Country.objects.annotate(json=functions.AsGeoJSON('mpoly')))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.contrib.gis.geos import (
|
||||||
MultiPoint, MultiPolygon, Point, Polygon, fromstr,
|
MultiPoint, MultiPolygon, Point, Polygon, fromstr,
|
||||||
)
|
)
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.db import connection
|
from django.db import NotSupportedError, connection
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
|
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
|
@ -516,7 +516,7 @@ class GeoQuerySetTest(TestCase):
|
||||||
Testing the `MakeLine` aggregate.
|
Testing the `MakeLine` aggregate.
|
||||||
"""
|
"""
|
||||||
if not connection.features.supports_make_line_aggr:
|
if not connection.features.supports_make_line_aggr:
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotSupportedError):
|
||||||
City.objects.all().aggregate(MakeLine('point'))
|
City.objects.all().aggregate(MakeLine('point'))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ from unittest import skipIf, skipUnless
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.contrib.gis.db.models.functions import Area, Distance
|
from django.contrib.gis.db.models.functions import Area, Distance
|
||||||
from django.contrib.gis.measure import D
|
from django.contrib.gis.measure import D
|
||||||
from django.db import connection
|
from django.db import NotSupportedError, connection
|
||||||
from django.db.models.functions import Cast
|
from django.db.models.functions import Cast
|
||||||
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||||
|
|
||||||
|
@ -152,5 +152,5 @@ class GeographyFunctionTests(FuncTestMixin, TestCase):
|
||||||
@skipUnlessDBFeature("has_Area_function")
|
@skipUnlessDBFeature("has_Area_function")
|
||||||
@skipIfDBFeature("supports_area_geodetic")
|
@skipIfDBFeature("supports_area_geodetic")
|
||||||
def test_geodetic_area_raises_if_not_supported(self):
|
def test_geodetic_area_raises_if_not_supported(self):
|
||||||
with self.assertRaisesMessage(NotImplementedError, 'Area on geodetic coordinate systems not supported.'):
|
with self.assertRaisesMessage(NotSupportedError, 'Area on geodetic coordinate systems not supported.'):
|
||||||
Zipcode.objects.annotate(area=Area('poly')).get(code='77002')
|
Zipcode.objects.annotate(area=Area('poly')).get(code='77002')
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib.gis.db.models import Collect, Count, Extent, F, Union
|
from django.contrib.gis.db.models import Collect, Count, Extent, F, Union
|
||||||
from django.contrib.gis.geos import GEOSGeometry, MultiPoint, Point
|
from django.contrib.gis.geos import GEOSGeometry, MultiPoint, Point
|
||||||
from django.db import connection
|
from django.db import NotSupportedError, connection
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -147,7 +147,7 @@ class RelatedGeoModelTest(TestCase):
|
||||||
self.assertEqual('P2', qs.get().name)
|
self.assertEqual('P2', qs.get().name)
|
||||||
else:
|
else:
|
||||||
msg = "This backend doesn't support the Transform function."
|
msg = "This backend doesn't support the Transform function."
|
||||||
with self.assertRaisesMessage(NotImplementedError, msg):
|
with self.assertRaisesMessage(NotSupportedError, msg):
|
||||||
list(qs)
|
list(qs)
|
||||||
|
|
||||||
# Should return the first Parcel, which has the center point equal
|
# Should return the first Parcel, which has the center point equal
|
||||||
|
@ -162,7 +162,7 @@ class RelatedGeoModelTest(TestCase):
|
||||||
self.assertEqual('P1', qs.get().name)
|
self.assertEqual('P1', qs.get().name)
|
||||||
else:
|
else:
|
||||||
msg = "This backend doesn't support the Transform function."
|
msg = "This backend doesn't support the Transform function."
|
||||||
with self.assertRaisesMessage(NotImplementedError, msg):
|
with self.assertRaisesMessage(NotSupportedError, msg):
|
||||||
list(qs)
|
list(qs)
|
||||||
|
|
||||||
def test07_values(self):
|
def test07_values(self):
|
||||||
|
|
Loading…
Reference in New Issue