summaryrefslogtreecommitdiff
path: root/django/contrib/gis
diff options
context:
space:
mode:
authordjango-bot <ops@djangoproject.com>2022-02-03 20:24:19 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-02-07 20:37:05 +0100
commit9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch)
treef0506b668a013d0063e5fba3dbf4863b466713ba /django/contrib/gis
parentf68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff)
downloaddjango-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'django/contrib/gis')
-rw-r--r--django/contrib/gis/admin/__init__.py36
-rw-r--r--django/contrib/gis/admin/options.py128
-rw-r--r--django/contrib/gis/admin/widgets.py61
-rw-r--r--django/contrib/gis/apps.py8
-rw-r--r--django/contrib/gis/db/backends/base/adapter.py6
-rw-r--r--django/contrib/gis/db/backends/base/features.py12
-rw-r--r--django/contrib/gis/db/backends/base/models.py14
-rw-r--r--django/contrib/gis/db/backends/base/operations.py111
-rw-r--r--django/contrib/gis/db/backends/mysql/base.py4
-rw-r--r--django/contrib/gis/db/backends/mysql/features.py29
-rw-r--r--django/contrib/gis/db/backends/mysql/introspection.py9
-rw-r--r--django/contrib/gis/db/backends/mysql/operations.py83
-rw-r--r--django/contrib/gis/db/backends/mysql/schema.py32
-rw-r--r--django/contrib/gis/db/backends/oracle/adapter.py13
-rw-r--r--django/contrib/gis/db/backends/oracle/base.py4
-rw-r--r--django/contrib/gis/db/backends/oracle/features.py14
-rw-r--r--django/contrib/gis/db/backends/oracle/introspection.py12
-rw-r--r--django/contrib/gis/db/backends/oracle/models.py14
-rw-r--r--django/contrib/gis/db/backends/oracle/operations.py147
-rw-r--r--django/contrib/gis/db/backends/oracle/schema.py81
-rw-r--r--django/contrib/gis/db/backends/postgis/adapter.py10
-rw-r--r--django/contrib/gis/db/backends/postgis/base.py2
-rw-r--r--django/contrib/gis/db/backends/postgis/const.py38
-rw-r--r--django/contrib/gis/db/backends/postgis/introspection.py39
-rw-r--r--django/contrib/gis/db/backends/postgis/models.py16
-rw-r--r--django/contrib/gis/db/backends/postgis/operations.py217
-rw-r--r--django/contrib/gis/db/backends/postgis/pgraster.py51
-rw-r--r--django/contrib/gis/db/backends/postgis/schema.py31
-rw-r--r--django/contrib/gis/db/backends/spatialite/adapter.py1
-rw-r--r--django/contrib/gis/db/backends/spatialite/base.py38
-rw-r--r--django/contrib/gis/db/backends/spatialite/client.py2
-rw-r--r--django/contrib/gis/db/backends/spatialite/features.py12
-rw-r--r--django/contrib/gis/db/backends/spatialite/introspection.py51
-rw-r--r--django/contrib/gis/db/backends/spatialite/models.py18
-rw-r--r--django/contrib/gis/db/backends/spatialite/operations.py110
-rw-r--r--django/contrib/gis/db/backends/spatialite/schema.py65
-rw-r--r--django/contrib/gis/db/backends/utils.py7
-rw-r--r--django/contrib/gis/db/models/__init__.py24
-rw-r--r--django/contrib/gis/db/models/aggregates.py51
-rw-r--r--django/contrib/gis/db/models/fields.py133
-rw-r--r--django/contrib/gis/db/models/functions.py173
-rw-r--r--django/contrib/gis/db/models/lookups.py152
-rw-r--r--django/contrib/gis/db/models/proxy.py12
-rw-r--r--django/contrib/gis/db/models/sql/__init__.py7
-rw-r--r--django/contrib/gis/db/models/sql/conversion.py12
-rw-r--r--django/contrib/gis/feeds.py53
-rw-r--r--django/contrib/gis/forms/__init__.py9
-rw-r--r--django/contrib/gis/forms/fields.py51
-rw-r--r--django/contrib/gis/forms/widgets.py59
-rw-r--r--django/contrib/gis/gdal/__init__.py31
-rw-r--r--django/contrib/gis/gdal/datasource.py19
-rw-r--r--django/contrib/gis/gdal/driver.py29
-rw-r--r--django/contrib/gis/gdal/envelope.py75
-rw-r--r--django/contrib/gis/gdal/error.py36
-rw-r--r--django/contrib/gis/gdal/feature.py21
-rw-r--r--django/contrib/gis/gdal/field.py36
-rw-r--r--django/contrib/gis/gdal/geometries.py100
-rw-r--r--django/contrib/gis/gdal/geomtype.py60
-rw-r--r--django/contrib/gis/gdal/layer.py57
-rw-r--r--django/contrib/gis/gdal/libgdal.py47
-rw-r--r--django/contrib/gis/gdal/prototypes/ds.py36
-rw-r--r--django/contrib/gis/gdal/prototypes/errcheck.py13
-rw-r--r--django/contrib/gis/gdal/prototypes/generation.py18
-rw-r--r--django/contrib/gis/gdal/prototypes/geom.py58
-rw-r--r--django/contrib/gis/gdal/prototypes/raster.py190
-rw-r--r--django/contrib/gis/gdal/prototypes/srs.py61
-rw-r--r--django/contrib/gis/gdal/raster/band.py45
-rw-r--r--django/contrib/gis/gdal/raster/base.py14
-rw-r--r--django/contrib/gis/gdal/raster/const.py94
-rw-r--r--django/contrib/gis/gdal/raster/source.py205
-rw-r--r--django/contrib/gis/gdal/srs.py47
-rw-r--r--django/contrib/gis/geoip2/__init__.py5
-rw-r--r--django/contrib/gis/geoip2/base.py79
-rw-r--r--django/contrib/gis/geoip2/resources.py28
-rw-r--r--django/contrib/gis/geometry.py16
-rw-r--r--django/contrib/gis/geos/__init__.py5
-rw-r--r--django/contrib/gis/geos/collections.py30
-rw-r--r--django/contrib/gis/geos/coordseq.py20
-rw-r--r--django/contrib/gis/geos/factory.py2
-rw-r--r--django/contrib/gis/geos/geometry.py76
-rw-r--r--django/contrib/gis/geos/io.py7
-rw-r--r--django/contrib/gis/geos/libgeos.py20
-rw-r--r--django/contrib/gis/geos/linestring.py30
-rw-r--r--django/contrib/gis/geos/mutable_list.py64
-rw-r--r--django/contrib/gis/geos/point.py12
-rw-r--r--django/contrib/gis/geos/polygon.py27
-rw-r--r--django/contrib/gis/geos/prepared.py2
-rw-r--r--django/contrib/gis/geos/prototypes/__init__.py62
-rw-r--r--django/contrib/gis/geos/prototypes/coordseq.py42
-rw-r--r--django/contrib/gis/geos/prototypes/errcheck.py24
-rw-r--r--django/contrib/gis/geos/prototypes/geom.py48
-rw-r--r--django/contrib/gis/geos/prototypes/io.py95
-rw-r--r--django/contrib/gis/geos/prototypes/misc.py13
-rw-r--r--django/contrib/gis/geos/prototypes/predicates.py38
-rw-r--r--django/contrib/gis/geos/prototypes/prepared.py26
-rw-r--r--django/contrib/gis/geos/prototypes/threadsafe.py8
-rw-r--r--django/contrib/gis/geos/prototypes/topology.py63
-rw-r--r--django/contrib/gis/management/commands/inspectdb.py16
-rw-r--r--django/contrib/gis/management/commands/ogrinspect.py134
-rw-r--r--django/contrib/gis/measure.py224
-rw-r--r--django/contrib/gis/ptr.py7
-rw-r--r--django/contrib/gis/serializers/geojson.py28
-rw-r--r--django/contrib/gis/shortcuts.py8
-rw-r--r--django/contrib/gis/sitemaps/__init__.py2
-rw-r--r--django/contrib/gis/sitemaps/kml.py31
-rw-r--r--django/contrib/gis/sitemaps/views.py14
-rw-r--r--django/contrib/gis/utils/__init__.py3
-rw-r--r--django/contrib/gis/utils/layermapping.py216
-rw-r--r--django/contrib/gis/utils/ogrinfo.py8
-rw-r--r--django/contrib/gis/utils/ogrinspect.py112
-rw-r--r--django/contrib/gis/utils/srs.py35
-rw-r--r--django/contrib/gis/views.py12
112 files changed, 3235 insertions, 2011 deletions
diff --git a/django/contrib/gis/admin/__init__.py b/django/contrib/gis/admin/__init__.py
index 4abc4898ae..d5bd54c479 100644
--- a/django/contrib/gis/admin/__init__.py
+++ b/django/contrib/gis/admin/__init__.py
@@ -1,16 +1,34 @@
from django.contrib.admin import (
- HORIZONTAL, VERTICAL, AdminSite, ModelAdmin, StackedInline, TabularInline,
- action, autodiscover, display, register, site,
-)
-from django.contrib.gis.admin.options import (
- GeoModelAdmin, GISModelAdmin, OSMGeoAdmin,
+ HORIZONTAL,
+ VERTICAL,
+ AdminSite,
+ ModelAdmin,
+ StackedInline,
+ TabularInline,
+ action,
+ autodiscover,
+ display,
+ register,
+ site,
)
+from django.contrib.gis.admin.options import GeoModelAdmin, GISModelAdmin, OSMGeoAdmin
from django.contrib.gis.admin.widgets import OpenLayersWidget
__all__ = [
- 'HORIZONTAL', 'VERTICAL', 'AdminSite', 'ModelAdmin', 'StackedInline',
- 'TabularInline', 'action', 'autodiscover', 'display', 'register', 'site',
- 'GISModelAdmin', 'OpenLayersWidget',
+ "HORIZONTAL",
+ "VERTICAL",
+ "AdminSite",
+ "ModelAdmin",
+ "StackedInline",
+ "TabularInline",
+ "action",
+ "autodiscover",
+ "display",
+ "register",
+ "site",
+ "GISModelAdmin",
+ "OpenLayersWidget",
# RemovedInDjango50Warning.
- 'GeoModelAdmin', 'OSMGeoAdmin',
+ "GeoModelAdmin",
+ "OSMGeoAdmin",
]
diff --git a/django/contrib/gis/admin/options.py b/django/contrib/gis/admin/options.py
index 524ba4bdc5..9eb6af6335 100644
--- a/django/contrib/gis/admin/options.py
+++ b/django/contrib/gis/admin/options.py
@@ -14,11 +14,10 @@ class GeoModelAdminMixin:
gis_widget_kwargs = {}
def formfield_for_dbfield(self, db_field, request, **kwargs):
- if (
- isinstance(db_field, models.GeometryField) and
- (db_field.dim < 3 or self.gis_widget.supports_3d)
+ if isinstance(db_field, models.GeometryField) and (
+ db_field.dim < 3 or self.gis_widget.supports_3d
):
- kwargs['widget'] = self.gis_widget(**self.gis_widget_kwargs)
+ kwargs["widget"] = self.gis_widget(**self.gis_widget_kwargs)
return db_field.formfield(**kwargs)
else:
return super().formfield_for_dbfield(db_field, request, **kwargs)
@@ -38,6 +37,7 @@ class GeoModelAdmin(ModelAdmin):
The administration options class for Geographic models. Map settings
may be overloaded from their defaults to create custom maps.
"""
+
# The default map settings that may be overloaded -- still subject
# to API changes.
default_lon = 0
@@ -60,22 +60,25 @@ class GeoModelAdmin(ModelAdmin):
map_width = 600
map_height = 400
map_srid = 4326
- map_template = 'gis/admin/openlayers.html'
- openlayers_url = 'https://cdnjs.cloudflare.com/ajax/libs/openlayers/2.13.1/OpenLayers.js'
+ map_template = "gis/admin/openlayers.html"
+ openlayers_url = (
+ "https://cdnjs.cloudflare.com/ajax/libs/openlayers/2.13.1/OpenLayers.js"
+ )
point_zoom = num_zoom - 6
- wms_url = 'http://vmap0.tiles.osgeo.org/wms/vmap0'
- wms_layer = 'basic'
- wms_name = 'OpenLayers WMS'
- wms_options = {'format': 'image/jpeg'}
+ wms_url = "http://vmap0.tiles.osgeo.org/wms/vmap0"
+ wms_layer = "basic"
+ wms_name = "OpenLayers WMS"
+ wms_options = {"format": "image/jpeg"}
debug = False
widget = OpenLayersWidget
def __init__(self, *args, **kwargs):
warnings.warn(
- 'django.contrib.gis.admin.GeoModelAdmin and OSMGeoAdmin are '
- 'deprecated in favor of django.contrib.admin.ModelAdmin and '
- 'django.contrib.gis.admin.GISModelAdmin.',
- RemovedInDjango50Warning, stacklevel=2,
+ "django.contrib.gis.admin.GeoModelAdmin and OSMGeoAdmin are "
+ "deprecated in favor of django.contrib.admin.ModelAdmin and "
+ "django.contrib.gis.admin.GISModelAdmin.",
+ RemovedInDjango50Warning,
+ stacklevel=2,
)
super().__init__(*args, **kwargs)
@@ -92,7 +95,7 @@ class GeoModelAdmin(ModelAdmin):
"""
if isinstance(db_field, models.GeometryField) and db_field.dim < 3:
# Setting the widget with the newly defined widget.
- kwargs['widget'] = self.get_map_widget(db_field)
+ kwargs["widget"] = self.get_map_widget(db_field)
return db_field.formfield(**kwargs)
else:
return super().formfield_for_dbfield(db_field, request, **kwargs)
@@ -103,68 +106,75 @@ class GeoModelAdmin(ModelAdmin):
in the `widget` attribute) using the settings from the attributes set
in this class.
"""
- is_collection = db_field.geom_type in ('MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON', 'GEOMETRYCOLLECTION')
+ is_collection = db_field.geom_type in (
+ "MULTIPOINT",
+ "MULTILINESTRING",
+ "MULTIPOLYGON",
+ "GEOMETRYCOLLECTION",
+ )
if is_collection:
- if db_field.geom_type == 'GEOMETRYCOLLECTION':
- collection_type = 'Any'
+ if db_field.geom_type == "GEOMETRYCOLLECTION":
+ collection_type = "Any"
else:
- collection_type = OGRGeomType(db_field.geom_type.replace('MULTI', ''))
+ collection_type = OGRGeomType(db_field.geom_type.replace("MULTI", ""))
else:
- collection_type = 'None'
+ collection_type = "None"
class OLMap(self.widget):
template_name = self.map_template
geom_type = db_field.geom_type
- wms_options = ''
+ wms_options = ""
if self.wms_options:
wms_options = ["%s: '%s'" % pair for pair in self.wms_options.items()]
- wms_options = ', %s' % ', '.join(wms_options)
+ wms_options = ", %s" % ", ".join(wms_options)
params = {
- 'default_lon': self.default_lon,
- 'default_lat': self.default_lat,
- 'default_zoom': self.default_zoom,
- 'display_wkt': self.debug or self.display_wkt,
- 'geom_type': OGRGeomType(db_field.geom_type),
- 'field_name': db_field.name,
- 'is_collection': is_collection,
- 'scrollable': self.scrollable,
- 'layerswitcher': self.layerswitcher,
- 'collection_type': collection_type,
- 'is_generic': db_field.geom_type == 'GEOMETRY',
- 'is_linestring': db_field.geom_type in ('LINESTRING', 'MULTILINESTRING'),
- 'is_polygon': db_field.geom_type in ('POLYGON', 'MULTIPOLYGON'),
- 'is_point': db_field.geom_type in ('POINT', 'MULTIPOINT'),
- 'num_zoom': self.num_zoom,
- 'max_zoom': self.max_zoom,
- 'min_zoom': self.min_zoom,
- 'units': self.units, # likely should get from object
- 'max_resolution': self.max_resolution,
- 'max_extent': self.max_extent,
- 'modifiable': self.modifiable,
- 'mouse_position': self.mouse_position,
- 'scale_text': self.scale_text,
- 'map_width': self.map_width,
- 'map_height': self.map_height,
- 'point_zoom': self.point_zoom,
- 'srid': self.map_srid,
- 'display_srid': self.display_srid,
- 'wms_url': self.wms_url,
- 'wms_layer': self.wms_layer,
- 'wms_name': self.wms_name,
- 'wms_options': wms_options,
- 'debug': self.debug,
+ "default_lon": self.default_lon,
+ "default_lat": self.default_lat,
+ "default_zoom": self.default_zoom,
+ "display_wkt": self.debug or self.display_wkt,
+ "geom_type": OGRGeomType(db_field.geom_type),
+ "field_name": db_field.name,
+ "is_collection": is_collection,
+ "scrollable": self.scrollable,
+ "layerswitcher": self.layerswitcher,
+ "collection_type": collection_type,
+ "is_generic": db_field.geom_type == "GEOMETRY",
+ "is_linestring": db_field.geom_type
+ in ("LINESTRING", "MULTILINESTRING"),
+ "is_polygon": db_field.geom_type in ("POLYGON", "MULTIPOLYGON"),
+ "is_point": db_field.geom_type in ("POINT", "MULTIPOINT"),
+ "num_zoom": self.num_zoom,
+ "max_zoom": self.max_zoom,
+ "min_zoom": self.min_zoom,
+ "units": self.units, # likely should get from object
+ "max_resolution": self.max_resolution,
+ "max_extent": self.max_extent,
+ "modifiable": self.modifiable,
+ "mouse_position": self.mouse_position,
+ "scale_text": self.scale_text,
+ "map_width": self.map_width,
+ "map_height": self.map_height,
+ "point_zoom": self.point_zoom,
+ "srid": self.map_srid,
+ "display_srid": self.display_srid,
+ "wms_url": self.wms_url,
+ "wms_layer": self.wms_layer,
+ "wms_name": self.wms_name,
+ "wms_options": wms_options,
+ "debug": self.debug,
}
+
return OLMap
# RemovedInDjango50Warning.
class OSMGeoAdmin(GeoModelAdmin):
- map_template = 'gis/admin/osm.html'
+ map_template = "gis/admin/osm.html"
num_zoom = 20
map_srid = spherical_mercator_srid
- max_extent = '-20037508,-20037508,20037508,20037508'
- max_resolution = '156543.0339'
+ max_extent = "-20037508,-20037508,20037508,20037508"
+ max_resolution = "156543.0339"
point_zoom = num_zoom - 6
- units = 'm'
+ units = "m"
diff --git a/django/contrib/gis/admin/widgets.py b/django/contrib/gis/admin/widgets.py
index 1ce94ec7c2..420c170608 100644
--- a/django/contrib/gis/admin/widgets.py
+++ b/django/contrib/gis/admin/widgets.py
@@ -7,26 +7,27 @@ from django.utils import translation
# Creating a template context that contains Django settings
# values needed by admin map templates.
-geo_context = {'LANGUAGE_BIDI': translation.get_language_bidi()}
-logger = logging.getLogger('django.contrib.gis')
+geo_context = {"LANGUAGE_BIDI": translation.get_language_bidi()}
+logger = logging.getLogger("django.contrib.gis")
class OpenLayersWidget(Textarea):
"""
Render an OpenLayers map using the WKT of the geometry.
"""
+
def get_context(self, name, value, attrs):
# Update the template parameters with any attributes passed in.
if attrs:
self.params.update(attrs)
- self.params['editable'] = self.params['modifiable']
+ self.params["editable"] = self.params["modifiable"]
else:
- self.params['editable'] = True
+ self.params["editable"] = True
# Defaulting the WKT value to a blank string -- this
# will be tested in the JavaScript and the appropriate
# interface will be constructed.
- self.params['wkt'] = ''
+ self.params["wkt"] = ""
# If a string reaches here (via a validation error on another
# field) then just reconstruct the Geometry.
@@ -37,26 +38,29 @@ class OpenLayersWidget(Textarea):
logger.error("Error creating geometry from value '%s' (%s)", value, err)
value = None
- if (value and value.geom_type.upper() != self.geom_type and
- self.geom_type != 'GEOMETRY'):
+ if (
+ value
+ and value.geom_type.upper() != self.geom_type
+ and self.geom_type != "GEOMETRY"
+ ):
value = None
# Constructing the dictionary of the map options.
- self.params['map_options'] = self.map_options()
+ self.params["map_options"] = self.map_options()
# Constructing the JavaScript module name using the name of
# the GeometryField (passed in via the `attrs` keyword).
# Use the 'name' attr for the field name (rather than 'field')
- self.params['name'] = name
+ self.params["name"] = name
# note: we must switch out dashes for underscores since js
# functions are created using the module variable
- js_safe_name = self.params['name'].replace('-', '_')
- self.params['module'] = 'geodjango_%s' % js_safe_name
+ js_safe_name = self.params["name"].replace("-", "_")
+ self.params["module"] = "geodjango_%s" % js_safe_name
if value:
# Transforming the geometry to the projection used on the
# OpenLayers map.
- srid = self.params['srid']
+ srid = self.params["srid"]
if value.srid != srid:
try:
ogr = value.ogr
@@ -65,15 +69,17 @@ class OpenLayersWidget(Textarea):
except GDALException as err:
logger.error(
"Error transforming geometry from srid '%s' to srid '%s' (%s)",
- value.srid, srid, err
+ value.srid,
+ srid,
+ err,
)
- wkt = ''
+ wkt = ""
else:
wkt = value.wkt
# Setting the parameter WKT with that of the transformed
# geometry.
- self.params['wkt'] = wkt
+ self.params["wkt"] = wkt
self.params.update(geo_context)
return self.params
@@ -82,30 +88,31 @@ class OpenLayersWidget(Textarea):
"""Build the map options hash for the OpenLayers template."""
# JavaScript construction utilities for the Bounds and Projection.
def ol_bounds(extent):
- return 'new OpenLayers.Bounds(%s)' % extent
+ return "new OpenLayers.Bounds(%s)" % extent
def ol_projection(srid):
return 'new OpenLayers.Projection("EPSG:%s")' % srid
# An array of the parameter name, the name of their OpenLayers
# counterpart, and the type of variable they are.
- map_types = [('srid', 'projection', 'srid'),
- ('display_srid', 'displayProjection', 'srid'),
- ('units', 'units', str),
- ('max_resolution', 'maxResolution', float),
- ('max_extent', 'maxExtent', 'bounds'),
- ('num_zoom', 'numZoomLevels', int),
- ('max_zoom', 'maxZoomLevels', int),
- ('min_zoom', 'minZoomLevel', int),
- ]
+ map_types = [
+ ("srid", "projection", "srid"),
+ ("display_srid", "displayProjection", "srid"),
+ ("units", "units", str),
+ ("max_resolution", "maxResolution", float),
+ ("max_extent", "maxExtent", "bounds"),
+ ("num_zoom", "numZoomLevels", int),
+ ("max_zoom", "maxZoomLevels", int),
+ ("min_zoom", "minZoomLevel", int),
+ ]
# Building the map options hash.
map_options = {}
for param_name, js_name, option_type in map_types:
if self.params.get(param_name, False):
- if option_type == 'srid':
+ if option_type == "srid":
value = ol_projection(self.params[param_name])
- elif option_type == 'bounds':
+ elif option_type == "bounds":
value = ol_bounds(self.params[param_name])
elif option_type in (float, int):
value = self.params[param_name]
diff --git a/django/contrib/gis/apps.py b/django/contrib/gis/apps.py
index e582e76760..6282501056 100644
--- a/django/contrib/gis/apps.py
+++ b/django/contrib/gis/apps.py
@@ -4,9 +4,11 @@ from django.utils.translation import gettext_lazy as _
class GISConfig(AppConfig):
- default_auto_field = 'django.db.models.AutoField'
- name = 'django.contrib.gis'
+ default_auto_field = "django.db.models.AutoField"
+ name = "django.contrib.gis"
verbose_name = _("GIS")
def ready(self):
- serializers.BUILTIN_SERIALIZERS.setdefault('geojson', 'django.contrib.gis.serializers.geojson')
+ serializers.BUILTIN_SERIALIZERS.setdefault(
+ "geojson", "django.contrib.gis.serializers.geojson"
+ )
diff --git a/django/contrib/gis/db/backends/base/adapter.py b/django/contrib/gis/db/backends/base/adapter.py
index f6f271915d..b472e3aacb 100644
--- a/django/contrib/gis/db/backends/base/adapter.py
+++ b/django/contrib/gis/db/backends/base/adapter.py
@@ -2,14 +2,16 @@ class WKTAdapter:
"""
An adaptor for Geometries sent to the MySQL and Oracle database backends.
"""
+
def __init__(self, geom):
self.wkt = geom.wkt
self.srid = geom.srid
def __eq__(self, other):
return (
- isinstance(other, WKTAdapter) and
- self.wkt == other.wkt and self.srid == other.srid
+ isinstance(other, WKTAdapter)
+ and self.wkt == other.wkt
+ and self.srid == other.srid
)
def __hash__(self):
diff --git a/django/contrib/gis/db/backends/base/features.py b/django/contrib/gis/db/backends/base/features.py
index cf52c4e122..cc4ce1046b 100644
--- a/django/contrib/gis/db/backends/base/features.py
+++ b/django/contrib/gis/db/backends/base/features.py
@@ -60,15 +60,15 @@ class BaseSpatialFeatures:
@property
def supports_bbcontains_lookup(self):
- return 'bbcontains' in self.connection.ops.gis_operators
+ return "bbcontains" in self.connection.ops.gis_operators
@property
def supports_contained_lookup(self):
- return 'contained' in self.connection.ops.gis_operators
+ return "contained" in self.connection.ops.gis_operators
@property
def supports_crosses_lookup(self):
- return 'crosses' in self.connection.ops.gis_operators
+ return "crosses" in self.connection.ops.gis_operators
@property
def supports_distances_lookups(self):
@@ -76,11 +76,11 @@ class BaseSpatialFeatures:
@property
def supports_dwithin_lookup(self):
- return 'dwithin' in self.connection.ops.gis_operators
+ return "dwithin" in self.connection.ops.gis_operators
@property
def supports_relate_lookup(self):
- return 'relate' in self.connection.ops.gis_operators
+ return "relate" in self.connection.ops.gis_operators
@property
def supports_isvalid_lookup(self):
@@ -104,7 +104,7 @@ class BaseSpatialFeatures:
return models.Union not in self.connection.ops.disallowed_aggregates
def __getattr__(self, name):
- m = re.match(r'has_(\w*)_function$', name)
+ m = re.match(r"has_(\w*)_function$", name)
if m:
func_name = m[1]
return func_name not in self.connection.ops.unsupported_functions
diff --git a/django/contrib/gis/db/backends/base/models.py b/django/contrib/gis/db/backends/base/models.py
index c25c1ccdee..589c872da6 100644
--- a/django/contrib/gis/db/backends/base/models.py
+++ b/django/contrib/gis/db/backends/base/models.py
@@ -6,13 +6,14 @@ class SpatialRefSysMixin:
The SpatialRefSysMixin is a class used by the database-dependent
SpatialRefSys objects to reduce redundant code.
"""
+
@property
def srs(self):
"""
Return a GDAL SpatialReference object.
"""
# TODO: Is caching really necessary here? Is complexity worth it?
- if hasattr(self, '_srs'):
+ if hasattr(self, "_srs"):
# Returning a clone of the cached SpatialReference object.
return self._srs.clone()
else:
@@ -31,7 +32,10 @@ class SpatialRefSysMixin:
except Exception as e:
msg = e
- raise Exception('Could not get OSR SpatialReference from WKT: %s\nError:\n%s' % (self.wkt, msg))
+ raise Exception(
+ "Could not get OSR SpatialReference from WKT: %s\nError:\n%s"
+ % (self.wkt, msg)
+ )
@property
def ellipsoid(self):
@@ -49,12 +53,12 @@ class SpatialRefSysMixin:
@property
def spheroid(self):
"Return the spheroid name for this spatial reference."
- return self.srs['spheroid']
+ return self.srs["spheroid"]
@property
def datum(self):
"Return the datum for this spatial reference."
- return self.srs['datum']
+ return self.srs["datum"]
@property
def projected(self):
@@ -117,7 +121,7 @@ class SpatialRefSysMixin:
"""
srs = gdal.SpatialReference(wkt)
sphere_params = srs.ellipsoid
- sphere_name = srs['spheroid']
+ sphere_name = srs["spheroid"]
if not string:
return sphere_name, sphere_params
diff --git a/django/contrib/gis/db/backends/base/operations.py b/django/contrib/gis/db/backends/base/operations.py
index 84b1785a1c..5e56b82a78 100644
--- a/django/contrib/gis/db/backends/base/operations.py
+++ b/django/contrib/gis/db/backends/base/operations.py
@@ -1,8 +1,7 @@
from django.contrib.gis.db.models import GeometryField
from django.contrib.gis.db.models.functions import Distance
-from django.contrib.gis.measure import (
- Area as AreaMeasure, Distance as DistanceMeasure,
-)
+from django.contrib.gis.measure import Area as AreaMeasure
+from django.contrib.gis.measure import Distance as DistanceMeasure
from django.db import NotSupportedError
from django.utils.functional import cached_property
@@ -18,7 +17,7 @@ class BaseSpatialOperations:
spatial_version = None
# How the geometry column should be selected.
- select = '%s'
+ select = "%s"
@cached_property
def select_extent(self):
@@ -27,7 +26,7 @@ class BaseSpatialOperations:
# Aggregates
disallowed_aggregates = ()
- geom_func_prefix = ''
+ geom_func_prefix = ""
# Mapping between Django function names and backend names, when names do not
# match; used in spatial_function_name().
@@ -35,12 +34,36 @@ class BaseSpatialOperations:
# Set of known unsupported functions of the backend
unsupported_functions = {
- 'Area', 'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG', 'Azimuth',
- 'BoundingCircle', 'Centroid', 'Difference', 'Distance', 'Envelope',
- 'GeoHash', 'GeometryDistance', 'Intersection', 'IsValid', 'Length',
- 'LineLocatePoint', 'MakeValid', 'MemSize', 'NumGeometries',
- 'NumPoints', 'Perimeter', 'PointOnSurface', 'Reverse', 'Scale',
- 'SnapToGrid', 'SymDifference', 'Transform', 'Translate', 'Union',
+ "Area",
+ "AsGeoJSON",
+ "AsGML",
+ "AsKML",
+ "AsSVG",
+ "Azimuth",
+ "BoundingCircle",
+ "Centroid",
+ "Difference",
+ "Distance",
+ "Envelope",
+ "GeoHash",
+ "GeometryDistance",
+ "Intersection",
+ "IsValid",
+ "Length",
+ "LineLocatePoint",
+ "MakeValid",
+ "MemSize",
+ "NumGeometries",
+ "NumPoints",
+ "Perimeter",
+ "PointOnSurface",
+ "Reverse",
+ "Scale",
+ "SnapToGrid",
+ "SymDifference",
+ "Transform",
+ "Translate",
+ "Union",
}
# Constructors
@@ -49,10 +72,14 @@ class BaseSpatialOperations:
# Default conversion functions for aggregates; will be overridden if implemented
# for the spatial backend.
def convert_extent(self, box, srid):
- raise NotImplementedError('Aggregate extent not implemented for this spatial backend.')
+ raise NotImplementedError(
+ "Aggregate extent not implemented for this spatial backend."
+ )
def convert_extent3d(self, box, srid):
- raise NotImplementedError('Aggregate 3D extent not implemented for this spatial backend.')
+ raise NotImplementedError(
+ "Aggregate 3D extent not implemented for this spatial backend."
+ )
# For quoting column values, rather than columns.
def geo_quote_name(self, name):
@@ -64,14 +91,18 @@ class BaseSpatialOperations:
Return the database column type for the geometry field on
the spatial backend.
"""
- raise NotImplementedError('subclasses of BaseSpatialOperations must provide a geo_db_type() method')
+ raise NotImplementedError(
+ "subclasses of BaseSpatialOperations must provide a geo_db_type() method"
+ )
def get_distance(self, f, value, lookup_type):
"""
Return the distance parameters for the given geometry field,
lookup value, and lookup type.
"""
- raise NotImplementedError('Distance operations not available on this spatial backend.')
+ raise NotImplementedError(
+ "Distance operations not available on this spatial backend."
+ )
def get_geom_placeholder(self, f, value, compiler):
"""
@@ -80,48 +111,60 @@ class BaseSpatialOperations:
stored procedure call to the transformation function of the spatial
backend.
"""
+
def transform_value(value, field):
return value is not None and value.srid != field.srid
- if hasattr(value, 'as_sql'):
+ if hasattr(value, "as_sql"):
return (
- '%s(%%s, %s)' % (self.spatial_function_name('Transform'), f.srid)
+ "%s(%%s, %s)" % (self.spatial_function_name("Transform"), f.srid)
if transform_value(value.output_field, f)
- else '%s'
+ else "%s"
)
if transform_value(value, f):
# Add Transform() to the SQL placeholder.
- return '%s(%s(%%s,%s), %s)' % (
- self.spatial_function_name('Transform'),
- self.from_text, value.srid, f.srid,
+ return "%s(%s(%%s,%s), %s)" % (
+ self.spatial_function_name("Transform"),
+ self.from_text,
+ value.srid,
+ f.srid,
)
elif self.connection.features.has_spatialrefsys_table:
- return '%s(%%s,%s)' % (self.from_text, f.srid)
+ return "%s(%%s,%s)" % (self.from_text, f.srid)
else:
# For backwards compatibility on MySQL (#27464).
- return '%s(%%s)' % self.from_text
+ return "%s(%%s)" % self.from_text
def check_expression_support(self, expression):
if isinstance(expression, self.disallowed_aggregates):
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)
def spatial_aggregate_name(self, agg_name):
- raise NotImplementedError('Aggregate support not implemented for this spatial backend.')
+ raise NotImplementedError(
+ "Aggregate support not implemented for this spatial backend."
+ )
def spatial_function_name(self, func_name):
if func_name in self.unsupported_functions:
- raise NotSupportedError("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)
# Routines for getting the OGC-compliant models.
def geometry_columns(self):
- raise NotImplementedError('Subclasses of BaseSpatialOperations must provide a geometry_columns() method.')
+ raise NotImplementedError(
+ "Subclasses of BaseSpatialOperations must provide a geometry_columns() method."
+ )
def spatial_ref_sys(self):
- raise NotImplementedError('subclasses of BaseSpatialOperations must a provide spatial_ref_sys() method')
+ raise NotImplementedError(
+ "subclasses of BaseSpatialOperations must a provide spatial_ref_sys() method"
+ )
distance_expr_for_lookup = staticmethod(Distance)
@@ -133,15 +176,17 @@ class BaseSpatialOperations:
def get_geometry_converter(self, expression):
raise NotImplementedError(
- 'Subclasses of BaseSpatialOperations must provide a '
- 'get_geometry_converter() method.'
+ "Subclasses of BaseSpatialOperations must provide a "
+ "get_geometry_converter() method."
)
def get_area_att_for_field(self, field):
if field.geodetic(self.connection):
if self.connection.features.supports_area_geodetic:
- return 'sq_m'
- raise NotImplementedError('Area on geodetic coordinate systems not supported.')
+ return "sq_m"
+ raise NotImplementedError(
+ "Area on geodetic coordinate systems not supported."
+ )
else:
units_name = field.units_name(self.connection)
if units_name:
@@ -151,7 +196,7 @@ class BaseSpatialOperations:
dist_att = None
if field.geodetic(self.connection):
if self.connection.features.supports_distance_geodetic:
- dist_att = 'm'
+ dist_att = "m"
else:
units = field.units_name(self.connection)
if units:
diff --git a/django/contrib/gis/db/backends/mysql/base.py b/django/contrib/gis/db/backends/mysql/base.py
index fccea5919d..4abc052e6e 100644
--- a/django/contrib/gis/db/backends/mysql/base.py
+++ b/django/contrib/gis/db/backends/mysql/base.py
@@ -1,6 +1,4 @@
-from django.db.backends.mysql.base import (
- DatabaseWrapper as MySQLDatabaseWrapper,
-)
+from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper
from .features import DatabaseFeatures
from .introspection import MySQLIntrospection
diff --git a/django/contrib/gis/db/backends/mysql/features.py b/django/contrib/gis/db/backends/mysql/features.py
index 613ccce9c5..8999a38bf9 100644
--- a/django/contrib/gis/db/backends/mysql/features.py
+++ b/django/contrib/gis/db/backends/mysql/features.py
@@ -1,7 +1,5 @@
from django.contrib.gis.db.backends.base.features import BaseSpatialFeatures
-from django.db.backends.mysql.features import (
- DatabaseFeatures as MySQLDatabaseFeatures,
-)
+from django.db.backends.mysql.features import DatabaseFeatures as MySQLDatabaseFeatures
from django.utils.functional import cached_property
@@ -14,13 +12,13 @@ class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
supports_transform = False
supports_null_geometries = False
supports_num_points_poly = False
- unsupported_geojson_options = {'crs'}
+ unsupported_geojson_options = {"crs"}
@cached_property
def empty_intersection_returns_none(self):
return (
- not self.connection.mysql_is_mariadb and
- self.connection.mysql_version < (5, 7, 5)
+ not self.connection.mysql_is_mariadb
+ and self.connection.mysql_version < (5, 7, 5)
)
@cached_property
@@ -31,13 +29,16 @@ class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
@cached_property
def django_test_skips(self):
skips = super().django_test_skips
- if (
- not self.connection.mysql_is_mariadb and
- self.connection.mysql_version < (8, 0, 0)
+ if not self.connection.mysql_is_mariadb and self.connection.mysql_version < (
+ 8,
+ 0,
+ 0,
):
- skips.update({
- 'MySQL < 8 gives different results.': {
- 'gis_tests.geoapp.tests.GeoLookupTest.test_disjoint_lookup',
- },
- })
+ skips.update(
+ {
+ "MySQL < 8 gives different results.": {
+ "gis_tests.geoapp.tests.GeoLookupTest.test_disjoint_lookup",
+ },
+ }
+ )
return skips
diff --git a/django/contrib/gis/db/backends/mysql/introspection.py b/django/contrib/gis/db/backends/mysql/introspection.py
index ad78595e24..7497ad520c 100644
--- a/django/contrib/gis/db/backends/mysql/introspection.py
+++ b/django/contrib/gis/db/backends/mysql/introspection.py
@@ -8,14 +8,13 @@ class MySQLIntrospection(DatabaseIntrospection):
# Updating the data_types_reverse dictionary with the appropriate
# type for Geometry fields.
data_types_reverse = DatabaseIntrospection.data_types_reverse.copy()
- data_types_reverse[FIELD_TYPE.GEOMETRY] = 'GeometryField'
+ data_types_reverse[FIELD_TYPE.GEOMETRY] = "GeometryField"
def get_geometry_type(self, table_name, description):
with self.connection.cursor() as cursor:
# In order to get the specific geometry type of the field,
# we introspect on the table definition using `DESCRIBE`.
- cursor.execute('DESCRIBE %s' %
- self.connection.ops.quote_name(table_name))
+ cursor.execute("DESCRIBE %s" % self.connection.ops.quote_name(table_name))
# Increment over description info until we get to the geometry
# column.
for column, typ, null, key, default, extra in cursor.fetchall():
@@ -31,8 +30,8 @@ class MySQLIntrospection(DatabaseIntrospection):
def supports_spatial_index(self, cursor, table_name):
# Supported with MyISAM/Aria, or InnoDB on MySQL 5.7.5+/MariaDB.
storage_engine = self.get_storage_engine(cursor, table_name)
- if storage_engine == 'InnoDB':
+ if storage_engine == "InnoDB":
if self.connection.mysql_is_mariadb:
return True
return self.connection.mysql_version >= (5, 7, 5)
- return storage_engine in ('MyISAM', 'Aria')
+ return storage_engine in ("MyISAM", "Aria")
diff --git a/django/contrib/gis/db/backends/mysql/operations.py b/django/contrib/gis/db/backends/mysql/operations.py
index 87ab371aa3..4ef014b36b 100644
--- a/django/contrib/gis/db/backends/mysql/operations.py
+++ b/django/contrib/gis/db/backends/mysql/operations.py
@@ -1,8 +1,6 @@
from django.contrib.gis.db import models
from django.contrib.gis.db.backends.base.adapter import WKTAdapter
-from django.contrib.gis.db.backends.base.operations import (
- BaseSpatialOperations,
-)
+from django.contrib.gis.db.backends.base.operations import BaseSpatialOperations
from django.contrib.gis.db.backends.utils import SpatialOperator
from django.contrib.gis.geos.geometry import GEOSGeometryBase
from django.contrib.gis.geos.prototypes.io import wkb_r
@@ -12,8 +10,8 @@ from django.utils.functional import cached_property
class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
- name = 'mysql'
- geom_func_prefix = 'ST_'
+ name = "mysql"
+ geom_func_prefix = "ST_"
Adapter = WKTAdapter
@@ -27,51 +25,69 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
@cached_property
def select(self):
- return self.geom_func_prefix + 'AsBinary(%s)'
+ return self.geom_func_prefix + "AsBinary(%s)"
@cached_property
def from_text(self):
- return self.geom_func_prefix + 'GeomFromText'
+ return self.geom_func_prefix + "GeomFromText"
@cached_property
def gis_operators(self):
operators = {
- 'bbcontains': SpatialOperator(func='MBRContains'), # For consistency w/PostGIS API
- 'bboverlaps': SpatialOperator(func='MBROverlaps'), # ...
- 'contained': SpatialOperator(func='MBRWithin'), # ...
- 'contains': SpatialOperator(func='ST_Contains'),
- 'crosses': SpatialOperator(func='ST_Crosses'),
- 'disjoint': SpatialOperator(func='ST_Disjoint'),
- 'equals': SpatialOperator(func='ST_Equals'),
- 'exact': SpatialOperator(func='ST_Equals'),
- 'intersects': SpatialOperator(func='ST_Intersects'),
- 'overlaps': SpatialOperator(func='ST_Overlaps'),
- 'same_as': SpatialOperator(func='ST_Equals'),
- 'touches': SpatialOperator(func='ST_Touches'),
- 'within': SpatialOperator(func='ST_Within'),
+ "bbcontains": SpatialOperator(
+ func="MBRContains"
+ ), # For consistency w/PostGIS API
+ "bboverlaps": SpatialOperator(func="MBROverlaps"), # ...
+ "contained": SpatialOperator(func="MBRWithin"), # ...
+ "contains": SpatialOperator(func="ST_Contains"),
+ "crosses": SpatialOperator(func="ST_Crosses"),
+ "disjoint": SpatialOperator(func="ST_Disjoint"),
+ "equals": SpatialOperator(func="ST_Equals"),
+ "exact": SpatialOperator(func="ST_Equals"),
+ "intersects": SpatialOperator(func="ST_Intersects"),
+ "overlaps": SpatialOperator(func="ST_Overlaps"),
+ "same_as": SpatialOperator(func="ST_Equals"),
+ "touches": SpatialOperator(func="ST_Touches"),
+ "within": SpatialOperator(func="ST_Within"),
}
if self.connection.mysql_is_mariadb:
- operators['relate'] = SpatialOperator(func='ST_Relate')
+ operators["relate"] = SpatialOperator(func="ST_Relate")
return operators
disallowed_aggregates = (
- models.Collect, models.Extent, models.Extent3D, models.MakeLine,
+ models.Collect,
+ models.Extent,
+ models.Extent3D,
+ models.MakeLine,
models.Union,
)
@cached_property
def unsupported_functions(self):
unsupported = {
- 'AsGML', 'AsKML', 'AsSVG', 'Azimuth', 'BoundingCircle',
- 'ForcePolygonCW', 'GeometryDistance', 'LineLocatePoint',
- 'MakeValid', 'MemSize', 'Perimeter', 'PointOnSurface', 'Reverse',
- 'Scale', 'SnapToGrid', 'Transform', 'Translate',
+ "AsGML",
+ "AsKML",
+ "AsSVG",
+ "Azimuth",
+ "BoundingCircle",
+ "ForcePolygonCW",
+ "GeometryDistance",
+ "LineLocatePoint",
+ "MakeValid",
+ "MemSize",
+ "Perimeter",
+ "PointOnSurface",
+ "Reverse",
+ "Scale",
+ "SnapToGrid",
+ "Transform",
+ "Translate",
}
if self.connection.mysql_is_mariadb:
- unsupported.remove('PointOnSurface')
- unsupported.update({'GeoHash', 'IsValid'})
+ unsupported.remove("PointOnSurface")
+ unsupported.update({"GeoHash", "IsValid"})
elif self.connection.mysql_version < (5, 7, 5):
- unsupported.update({'AsGeoJSON', 'GeoHash', 'IsValid'})
+ unsupported.update({"AsGeoJSON", "GeoHash", "IsValid"})
return unsupported
def geo_db_type(self, f):
@@ -82,10 +98,12 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
if isinstance(value, Distance):
if f.geodetic(self.connection):
raise ValueError(
- 'Only numeric values of degree units are allowed on '
- 'geodetic distance queries.'
+ "Only numeric values of degree units are allowed on "
+ "geodetic distance queries."
)
- dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
+ dist_param = getattr(
+ value, Distance.unit_attname(f.units_name(self.connection))
+ )
else:
dist_param = value
return [dist_param]
@@ -103,4 +121,5 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
if srid:
geom.srid = srid
return geom
+
return converter
diff --git a/django/contrib/gis/db/backends/mysql/schema.py b/django/contrib/gis/db/backends/mysql/schema.py
index da033ce5d6..b173df0198 100644
--- a/django/contrib/gis/db/backends/mysql/schema.py
+++ b/django/contrib/gis/db/backends/mysql/schema.py
@@ -4,12 +4,12 @@ from django.contrib.gis.db.models import GeometryField
from django.db import OperationalError
from django.db.backends.mysql.schema import DatabaseSchemaEditor
-logger = logging.getLogger('django.contrib.gis')
+logger = logging.getLogger("django.contrib.gis")
class MySQLGISSchemaEditor(DatabaseSchemaEditor):
- sql_add_spatial_index = 'CREATE SPATIAL INDEX %(index)s ON %(table)s(%(column)s)'
- sql_drop_spatial_index = 'DROP INDEX %(index)s ON %(table)s'
+ sql_add_spatial_index = "CREATE SPATIAL INDEX %(index)s ON %(table)s(%(column)s)"
+ sql_drop_spatial_index = "DROP INDEX %(index)s ON %(table)s"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -18,7 +18,10 @@ class MySQLGISSchemaEditor(DatabaseSchemaEditor):
def skip_default(self, field):
# Geometry fields are stored as BLOB/TEXT, for which MySQL < 8.0.13
# doesn't support defaults.
- if isinstance(field, GeometryField) and not self._supports_limited_data_type_defaults:
+ if (
+ isinstance(field, GeometryField)
+ and not self._supports_limited_data_type_defaults
+ ):
return True
return super().skip_default(field)
@@ -34,10 +37,11 @@ class MySQLGISSchemaEditor(DatabaseSchemaEditor):
qn = self.connection.ops.quote_name
db_table = model._meta.db_table
self.geometry_sql.append(
- self.sql_add_spatial_index % {
- 'index': qn(self._create_spatial_index_name(model, field)),
- 'table': qn(db_table),
- 'column': qn(field.column),
+ self.sql_add_spatial_index
+ % {
+ "index": qn(self._create_spatial_index_name(model, field)),
+ "table": qn(db_table),
+ "column": qn(field.column),
}
)
return column_sql
@@ -54,21 +58,22 @@ class MySQLGISSchemaEditor(DatabaseSchemaEditor):
if isinstance(field, GeometryField) and field.spatial_index:
qn = self.connection.ops.quote_name
sql = self.sql_drop_spatial_index % {
- 'index': qn(self._create_spatial_index_name(model, field)),
- 'table': qn(model._meta.db_table),
+ "index": qn(self._create_spatial_index_name(model, field)),
+ "table": qn(model._meta.db_table),
}
try:
self.execute(sql)
except OperationalError:
logger.error(
"Couldn't remove spatial index: %s (may be expected "
- "if your storage engine doesn't support them).", sql
+ "if your storage engine doesn't support them).",
+ sql,
)
super().remove_field(model, field)
def _create_spatial_index_name(self, model, field):
- return '%s_%s_id' % (model._meta.db_table, field.column)
+ return "%s_%s_id" % (model._meta.db_table, field.column)
def create_spatial_indexes(self):
for sql in self.geometry_sql:
@@ -77,6 +82,7 @@ class MySQLGISSchemaEditor(DatabaseSchemaEditor):
except OperationalError:
logger.error(
"Cannot create SPATIAL INDEX %s. Only MyISAM and (as of "
- "MySQL 5.7.5) InnoDB support them.", sql
+ "MySQL 5.7.5) InnoDB support them.",
+ sql,
)
self.geometry_sql = []
diff --git a/django/contrib/gis/db/backends/oracle/adapter.py b/django/contrib/gis/db/backends/oracle/adapter.py
index 3f96178091..7556b121b8 100644
--- a/django/contrib/gis/db/backends/oracle/adapter.py
+++ b/django/contrib/gis/db/backends/oracle/adapter.py
@@ -19,7 +19,9 @@ class OracleSpatialAdapter(WKTAdapter):
if self._polygon_must_be_fixed(geom):
geom = self._fix_polygon(geom)
elif isinstance(geom, GeometryCollection):
- if any(isinstance(g, Polygon) and self._polygon_must_be_fixed(g) for g in geom):
+ if any(
+ isinstance(g, Polygon) and self._polygon_must_be_fixed(g) for g in geom
+ ):
geom = self._fix_geometry_collection(geom)
self.wkt = geom.wkt
@@ -27,12 +29,9 @@ class OracleSpatialAdapter(WKTAdapter):
@staticmethod
def _polygon_must_be_fixed(poly):
- return (
- not poly.empty and
- (
- not poly.exterior_ring.is_counterclockwise or
- any(x.is_counterclockwise for x in poly)
- )
+ return not poly.empty and (
+ not poly.exterior_ring.is_counterclockwise
+ or any(x.is_counterclockwise for x in poly)
)
@classmethod
diff --git a/django/contrib/gis/db/backends/oracle/base.py b/django/contrib/gis/db/backends/oracle/base.py
index 0093ef83bb..d43516a72f 100644
--- a/django/contrib/gis/db/backends/oracle/base.py
+++ b/django/contrib/gis/db/backends/oracle/base.py
@@ -1,6 +1,4 @@
-from django.db.backends.oracle.base import (
- DatabaseWrapper as OracleDatabaseWrapper,
-)
+from django.db.backends.oracle.base import DatabaseWrapper as OracleDatabaseWrapper
from .features import DatabaseFeatures
from .introspection import OracleIntrospection
diff --git a/django/contrib/gis/db/backends/oracle/features.py b/django/contrib/gis/db/backends/oracle/features.py
index 2ba951de42..ee4b296c07 100644
--- a/django/contrib/gis/db/backends/oracle/features.py
+++ b/django/contrib/gis/db/backends/oracle/features.py
@@ -12,14 +12,16 @@ class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures):
supports_perimeter_geodetic = True
supports_dwithin_distance_expr = False
supports_tolerance_parameter = True
- unsupported_geojson_options = {'bbox', 'crs', 'precision'}
+ unsupported_geojson_options = {"bbox", "crs", "precision"}
@cached_property
def django_test_skips(self):
skips = super().django_test_skips
- skips.update({
- "Oracle doesn't support spatial operators in constraints.": {
- 'gis_tests.gis_migrations.test_operations.OperationTests.test_add_check_constraint',
- },
- })
+ skips.update(
+ {
+ "Oracle doesn't support spatial operators in constraints.": {
+ "gis_tests.gis_migrations.test_operations.OperationTests.test_add_check_constraint",
+ },
+ }
+ )
return skips
diff --git a/django/contrib/gis/db/backends/oracle/introspection.py b/django/contrib/gis/db/backends/oracle/introspection.py
index 493fe74b46..096fee54e1 100644
--- a/django/contrib/gis/db/backends/oracle/introspection.py
+++ b/django/contrib/gis/db/backends/oracle/introspection.py
@@ -12,7 +12,7 @@ class OracleIntrospection(DatabaseIntrospection):
def data_types_reverse(self):
return {
**super().data_types_reverse,
- cx_Oracle.OBJECT: 'GeometryField',
+ cx_Oracle.OBJECT: "GeometryField",
}
def get_geometry_type(self, table_name, description):
@@ -22,26 +22,26 @@ class OracleIntrospection(DatabaseIntrospection):
cursor.execute(
'SELECT "DIMINFO", "SRID" FROM "USER_SDO_GEOM_METADATA" '
'WHERE "TABLE_NAME"=%s AND "COLUMN_NAME"=%s',
- (table_name.upper(), description.name.upper())
+ (table_name.upper(), description.name.upper()),
)
row = cursor.fetchone()
except Exception as exc:
raise Exception(
- 'Could not find entry in USER_SDO_GEOM_METADATA '
+ "Could not find entry in USER_SDO_GEOM_METADATA "
'corresponding to "%s"."%s"' % (table_name, description.name)
) from exc
# TODO: Research way to find a more specific geometry field type for
# the column's contents.
- field_type = 'GeometryField'
+ field_type = "GeometryField"
# Getting the field parameters.
field_params = {}
dim, srid = row
if srid != 4326:
- field_params['srid'] = srid
+ field_params["srid"] = srid
# Size of object array (SDO_DIM_ARRAY) is number of dimensions.
dim = dim.size()
if dim != 2:
- field_params['dim'] = dim
+ field_params["dim"] = dim
return field_type, field_params
diff --git a/django/contrib/gis/db/backends/oracle/models.py b/django/contrib/gis/db/backends/oracle/models.py
index 6876eecefd..f06f73148e 100644
--- a/django/contrib/gis/db/backends/oracle/models.py
+++ b/django/contrib/gis/db/backends/oracle/models.py
@@ -19,12 +19,12 @@ class OracleGeometryColumns(models.Model):
# TODO: Add support for `diminfo` column (type MDSYS.SDO_DIM_ARRAY).
class Meta:
- app_label = 'gis'
- db_table = 'USER_SDO_GEOM_METADATA'
+ app_label = "gis"
+ db_table = "USER_SDO_GEOM_METADATA"
managed = False
def __str__(self):
- return '%s - %s (SRID: %s)' % (self.table_name, self.column_name, self.srid)
+ return "%s - %s (SRID: %s)" % (self.table_name, self.column_name, self.srid)
@classmethod
def table_name_col(cls):
@@ -32,7 +32,7 @@ class OracleGeometryColumns(models.Model):
Return the name of the metadata column used to store the feature table
name.
"""
- return 'table_name'
+ return "table_name"
@classmethod
def geom_col_name(cls):
@@ -40,7 +40,7 @@ class OracleGeometryColumns(models.Model):
Return the name of the metadata column used to store the feature
geometry column.
"""
- return 'column_name'
+ return "column_name"
class OracleSpatialRefSys(models.Model, SpatialRefSysMixin):
@@ -55,8 +55,8 @@ class OracleSpatialRefSys(models.Model, SpatialRefSysMixin):
cs_bounds = models.PolygonField(null=True)
class Meta:
- app_label = 'gis'
- db_table = 'CS_SRS'
+ app_label = "gis"
+ db_table = "CS_SRS"
managed = False
@property
diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py
index 9b363aaf4e..45010ef517 100644
--- a/django/contrib/gis/db/backends/oracle/operations.py
+++ b/django/contrib/gis/db/backends/oracle/operations.py
@@ -10,9 +10,7 @@
import re
from django.contrib.gis.db import models
-from django.contrib.gis.db.backends.base.operations import (
- BaseSpatialOperations,
-)
+from django.contrib.gis.db.backends.base.operations import BaseSpatialOperations
from django.contrib.gis.db.backends.oracle.adapter import OracleSpatialAdapter
from django.contrib.gis.db.backends.utils import SpatialOperator
from django.contrib.gis.geos.geometry import GEOSGeometry, GEOSGeometryBase
@@ -20,7 +18,7 @@ from django.contrib.gis.geos.prototypes.io import wkb_r
from django.contrib.gis.measure import Distance
from django.db.backends.oracle.operations import DatabaseOperations
-DEFAULT_TOLERANCE = '0.05'
+DEFAULT_TOLERANCE = "0.05"
class SDOOperator(SpatialOperator):
@@ -32,57 +30,60 @@ class SDODWithin(SpatialOperator):
class SDODisjoint(SpatialOperator):
- sql_template = "SDO_GEOM.RELATE(%%(lhs)s, 'DISJOINT', %%(rhs)s, %s) = 'DISJOINT'" % DEFAULT_TOLERANCE
+ sql_template = (
+ "SDO_GEOM.RELATE(%%(lhs)s, 'DISJOINT', %%(rhs)s, %s) = 'DISJOINT'"
+ % DEFAULT_TOLERANCE
+ )
class SDORelate(SpatialOperator):
sql_template = "SDO_RELATE(%(lhs)s, %(rhs)s, 'mask=%(mask)s') = 'TRUE'"
def check_relate_argument(self, arg):
- masks = 'TOUCH|OVERLAPBDYDISJOINT|OVERLAPBDYINTERSECT|EQUAL|INSIDE|COVEREDBY|CONTAINS|COVERS|ANYINTERACT|ON'
- mask_regex = re.compile(r'^(%s)(\+(%s))*$' % (masks, masks), re.I)
+ masks = "TOUCH|OVERLAPBDYDISJOINT|OVERLAPBDYINTERSECT|EQUAL|INSIDE|COVEREDBY|CONTAINS|COVERS|ANYINTERACT|ON"
+ mask_regex = re.compile(r"^(%s)(\+(%s))*$" % (masks, masks), re.I)
if not isinstance(arg, str) or not mask_regex.match(arg):
raise ValueError('Invalid SDO_RELATE mask: "%s"' % arg)
def as_sql(self, connection, lookup, template_params, sql_params):
- template_params['mask'] = sql_params[-1]
+ template_params["mask"] = sql_params[-1]
return super().as_sql(connection, lookup, template_params, sql_params[:-1])
class OracleOperations(BaseSpatialOperations, DatabaseOperations):
- name = 'oracle'
+ name = "oracle"
oracle = True
disallowed_aggregates = (models.Collect, models.Extent3D, models.MakeLine)
Adapter = OracleSpatialAdapter
- extent = 'SDO_AGGR_MBR'
- unionagg = 'SDO_AGGR_UNION'
+ extent = "SDO_AGGR_MBR"
+ unionagg = "SDO_AGGR_UNION"
- from_text = 'SDO_GEOMETRY'
+ from_text = "SDO_GEOMETRY"
function_names = {
- 'Area': 'SDO_GEOM.SDO_AREA',
- 'AsGeoJSON': 'SDO_UTIL.TO_GEOJSON',
- 'AsWKB': 'SDO_UTIL.TO_WKBGEOMETRY',
- 'AsWKT': 'SDO_UTIL.TO_WKTGEOMETRY',
- 'BoundingCircle': 'SDO_GEOM.SDO_MBC',
- 'Centroid': 'SDO_GEOM.SDO_CENTROID',
- 'Difference': 'SDO_GEOM.SDO_DIFFERENCE',
- 'Distance': 'SDO_GEOM.SDO_DISTANCE',
- 'Envelope': 'SDO_GEOM_MBR',
- 'Intersection': 'SDO_GEOM.SDO_INTERSECTION',
- 'IsValid': 'SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT',
- 'Length': 'SDO_GEOM.SDO_LENGTH',
- 'NumGeometries': 'SDO_UTIL.GETNUMELEM',
- 'NumPoints': 'SDO_UTIL.GETNUMVERTICES',
- 'Perimeter': 'SDO_GEOM.SDO_LENGTH',
- 'PointOnSurface': 'SDO_GEOM.SDO_POINTONSURFACE',
- 'Reverse': 'SDO_UTIL.REVERSE_LINESTRING',
- 'SymDifference': 'SDO_GEOM.SDO_XOR',
- 'Transform': 'SDO_CS.TRANSFORM',
- 'Union': 'SDO_GEOM.SDO_UNION',
+ "Area": "SDO_GEOM.SDO_AREA",
+ "AsGeoJSON": "SDO_UTIL.TO_GEOJSON",
+ "AsWKB": "SDO_UTIL.TO_WKBGEOMETRY",
+ "AsWKT": "SDO_UTIL.TO_WKTGEOMETRY",
+ "BoundingCircle": "SDO_GEOM.SDO_MBC",
+ "Centroid": "SDO_GEOM.SDO_CENTROID",
+ "Difference": "SDO_GEOM.SDO_DIFFERENCE",
+ "Distance": "SDO_GEOM.SDO_DISTANCE",
+ "Envelope": "SDO_GEOM_MBR",
+ "Intersection": "SDO_GEOM.SDO_INTERSECTION",
+ "IsValid": "SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT",
+ "Length": "SDO_GEOM.SDO_LENGTH",
+ "NumGeometries": "SDO_UTIL.GETNUMELEM",
+ "NumPoints": "SDO_UTIL.GETNUMVERTICES",
+ "Perimeter": "SDO_GEOM.SDO_LENGTH",
+ "PointOnSurface": "SDO_GEOM.SDO_POINTONSURFACE",
+ "Reverse": "SDO_UTIL.REVERSE_LINESTRING",
+ "SymDifference": "SDO_GEOM.SDO_XOR",
+ "Transform": "SDO_CS.TRANSFORM",
+ "Union": "SDO_GEOM.SDO_UNION",
}
# We want to get SDO Geometries as WKT because it is much easier to
@@ -90,28 +91,39 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
# However, this adversely affects performance (i.e., Java is called
# to convert to WKT on every query). If someone wishes to write a
# SDO_GEOMETRY(...) parser in Python, let me know =)
- select = 'SDO_UTIL.TO_WKBGEOMETRY(%s)'
+ select = "SDO_UTIL.TO_WKBGEOMETRY(%s)"
gis_operators = {
- 'contains': SDOOperator(func='SDO_CONTAINS'),
- 'coveredby': SDOOperator(func='SDO_COVEREDBY'),
- 'covers': SDOOperator(func='SDO_COVERS'),
- 'disjoint': SDODisjoint(),
- 'intersects': SDOOperator(func='SDO_OVERLAPBDYINTERSECT'), # TODO: Is this really the same as ST_Intersects()?
- 'equals': SDOOperator(func='SDO_EQUAL'),
- 'exact': SDOOperator(func='SDO_EQUAL'),
- 'overlaps': SDOOperator(func='SDO_OVERLAPS'),
- 'same_as': SDOOperator(func='SDO_EQUAL'),
- 'relate': SDORelate(), # Oracle uses a different syntax, e.g., 'mask=inside+touch'
- 'touches': SDOOperator(func='SDO_TOUCH'),
- 'within': SDOOperator(func='SDO_INSIDE'),
- 'dwithin': SDODWithin(),
+ "contains": SDOOperator(func="SDO_CONTAINS"),
+ "coveredby": SDOOperator(func="SDO_COVEREDBY"),
+ "covers": SDOOperator(func="SDO_COVERS"),
+ "disjoint": SDODisjoint(),
+ "intersects": SDOOperator(
+ func="SDO_OVERLAPBDYINTERSECT"
+ ), # TODO: Is this really the same as ST_Intersects()?
+ "equals": SDOOperator(func="SDO_EQUAL"),
+ "exact": SDOOperator(func="SDO_EQUAL"),
+ "overlaps": SDOOperator(func="SDO_OVERLAPS"),
+ "same_as": SDOOperator(func="SDO_EQUAL"),
+ "relate": SDORelate(), # Oracle uses a different syntax, e.g., 'mask=inside+touch'
+ "touches": SDOOperator(func="SDO_TOUCH"),
+ "within": SDOOperator(func="SDO_INSIDE"),
+ "dwithin": SDODWithin(),
}
unsupported_functions = {
- 'AsKML', 'AsSVG', 'Azimuth', 'ForcePolygonCW', 'GeoHash',
- 'GeometryDistance', 'LineLocatePoint', 'MakeValid', 'MemSize',
- 'Scale', 'SnapToGrid', 'Translate',
+ "AsKML",
+ "AsSVG",
+ "Azimuth",
+ "ForcePolygonCW",
+ "GeoHash",
+ "GeometryDistance",
+ "LineLocatePoint",
+ "MakeValid",
+ "MemSize",
+ "Scale",
+ "SnapToGrid",
+ "Translate",
}
def geo_quote_name(self, name):
@@ -124,15 +136,17 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
# table.
ext_geom = GEOSGeometry(memoryview(clob.read()))
gtype = str(ext_geom.geom_type)
- if gtype == 'Polygon':
+ if gtype == "Polygon":
# Construct the 4-tuple from the coordinates in the polygon.
shell = ext_geom.shell
ll, ur = shell[0][:2], shell[2][:2]
- elif gtype == 'Point':
+ elif gtype == "Point":
ll = ext_geom.coords[:2]
ur = ll
else:
- raise Exception('Unexpected geometry type returned for extent: %s' % gtype)
+ raise Exception(
+ "Unexpected geometry type returned for extent: %s" % gtype
+ )
xmin, ymin = ll
xmax, ymax = ur
return (xmin, ymin, xmax, ymax)
@@ -145,7 +159,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
backends, no stored procedure is necessary and it's the same for all
geometry types.
"""
- return 'MDSYS.SDO_GEOMETRY'
+ return "MDSYS.SDO_GEOMETRY"
def get_distance(self, f, value, lookup_type):
"""
@@ -161,47 +175,47 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
if f.geodetic(self.connection):
dist_param = value.m
else:
- dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
+ dist_param = getattr(
+ value, Distance.unit_attname(f.units_name(self.connection))
+ )
else:
dist_param = value
# dwithin lookups on Oracle require a special string parameter
# that starts with "distance=".
- if lookup_type == 'dwithin':
- dist_param = 'distance=%s' % dist_param
+ if lookup_type == "dwithin":
+ dist_param = "distance=%s" % dist_param
return [dist_param]
def get_geom_placeholder(self, f, value, compiler):
if value is None:
- return 'NULL'
+ return "NULL"
return super().get_geom_placeholder(f, value, compiler)
def spatial_aggregate_name(self, agg_name):
"""
Return the spatial aggregate SQL name.
"""
- agg_name = 'unionagg' if agg_name.lower() == 'union' else agg_name.lower()
+ agg_name = "unionagg" if agg_name.lower() == "union" else agg_name.lower()
return getattr(self, agg_name)
# Routines for getting the OGC-compliant models.
def geometry_columns(self):
- from django.contrib.gis.db.backends.oracle.models import (
- OracleGeometryColumns,
- )
+ from django.contrib.gis.db.backends.oracle.models import OracleGeometryColumns
+
return OracleGeometryColumns
def spatial_ref_sys(self):
- from django.contrib.gis.db.backends.oracle.models import (
- OracleSpatialRefSys,
- )
+ from django.contrib.gis.db.backends.oracle.models import OracleSpatialRefSys
+
return OracleSpatialRefSys
def modify_insert_params(self, placeholder, params):
"""Drop out insert parameters for NULL placeholder. Needed for Oracle Spatial
backend due to #10888.
"""
- if placeholder == 'NULL':
+ if placeholder == "NULL":
return []
return super().modify_insert_params(placeholder, params)
@@ -218,7 +232,8 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
if srid:
geom.srid = srid
return geom
+
return converter
def get_area_att_for_field(self, field):
- return 'sq_m'
+ return "sq_m"
diff --git a/django/contrib/gis/db/backends/oracle/schema.py b/django/contrib/gis/db/backends/oracle/schema.py
index b281abc81b..edc692ffc7 100644
--- a/django/contrib/gis/db/backends/oracle/schema.py
+++ b/django/contrib/gis/db/backends/oracle/schema.py
@@ -4,7 +4,7 @@ from django.db.backends.utils import strip_quotes, truncate_name
class OracleGISSchemaEditor(DatabaseSchemaEditor):
- sql_add_geometry_metadata = ("""
+ sql_add_geometry_metadata = """
INSERT INTO USER_SDO_GEOM_METADATA
("TABLE_NAME", "COLUMN_NAME", "DIMINFO", "SRID")
VALUES (
@@ -15,13 +15,15 @@ class OracleGISSchemaEditor(DatabaseSchemaEditor):
MDSYS.SDO_DIM_ELEMENT('LAT', %(dim1)s, %(dim3)s, %(tolerance)s)
),
%(srid)s
- )""")
- sql_add_spatial_index = 'CREATE INDEX %(index)s ON %(table)s(%(column)s) INDEXTYPE IS MDSYS.SPATIAL_INDEX'
- sql_drop_spatial_index = 'DROP INDEX %(index)s'
- sql_clear_geometry_table_metadata = 'DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = %(table)s'
+ )"""
+ sql_add_spatial_index = "CREATE INDEX %(index)s ON %(table)s(%(column)s) INDEXTYPE IS MDSYS.SPATIAL_INDEX"
+ sql_drop_spatial_index = "DROP INDEX %(index)s"
+ sql_clear_geometry_table_metadata = (
+ "DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = %(table)s"
+ )
sql_clear_geometry_field_metadata = (
- 'DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = %(table)s '
- 'AND COLUMN_NAME = %(column)s'
+ "DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = %(table)s "
+ "AND COLUMN_NAME = %(column)s"
)
def __init__(self, *args, **kwargs):
@@ -41,23 +43,27 @@ class OracleGISSchemaEditor(DatabaseSchemaEditor):
if isinstance(field, GeometryField):
db_table = model._meta.db_table
self.geometry_sql.append(
- self.sql_add_geometry_metadata % {
- 'table': self.geo_quote_name(db_table),
- 'column': self.geo_quote_name(field.column),
- 'dim0': field._extent[0],
- 'dim1': field._extent[1],
- 'dim2': field._extent[2],
- 'dim3': field._extent[3],
- 'tolerance': field._tolerance,
- 'srid': field.srid,
+ self.sql_add_geometry_metadata
+ % {
+ "table": self.geo_quote_name(db_table),
+ "column": self.geo_quote_name(field.column),
+ "dim0": field._extent[0],
+ "dim1": field._extent[1],
+ "dim2": field._extent[2],
+ "dim3": field._extent[3],
+ "tolerance": field._tolerance,
+ "srid": field.srid,
}
)
if field.spatial_index:
self.geometry_sql.append(
- self.sql_add_spatial_index % {
- 'index': self.quote_name(self._create_spatial_index_name(model, field)),
- 'table': self.quote_name(db_table),
- 'column': self.quote_name(field.column),
+ self.sql_add_spatial_index
+ % {
+ "index": self.quote_name(
+ self._create_spatial_index_name(model, field)
+ ),
+ "table": self.quote_name(db_table),
+ "column": self.quote_name(field.column),
}
)
return column_sql
@@ -68,9 +74,12 @@ class OracleGISSchemaEditor(DatabaseSchemaEditor):
def delete_model(self, model):
super().delete_model(model)
- self.execute(self.sql_clear_geometry_table_metadata % {
- 'table': self.geo_quote_name(model._meta.db_table),
- })
+ self.execute(
+ self.sql_clear_geometry_table_metadata
+ % {
+ "table": self.geo_quote_name(model._meta.db_table),
+ }
+ )
def add_field(self, model, field):
super().add_field(model, field)
@@ -78,14 +87,22 @@ class OracleGISSchemaEditor(DatabaseSchemaEditor):
def remove_field(self, model, field):
if isinstance(field, GeometryField):
- self.execute(self.sql_clear_geometry_field_metadata % {
- 'table': self.geo_quote_name(model._meta.db_table),
- 'column': self.geo_quote_name(field.column),
- })
+ self.execute(
+ self.sql_clear_geometry_field_metadata
+ % {
+ "table": self.geo_quote_name(model._meta.db_table),
+ "column": self.geo_quote_name(field.column),
+ }
+ )
if field.spatial_index:
- self.execute(self.sql_drop_spatial_index % {
- 'index': self.quote_name(self._create_spatial_index_name(model, field)),
- })
+ self.execute(
+ self.sql_drop_spatial_index
+ % {
+ "index": self.quote_name(
+ self._create_spatial_index_name(model, field)
+ ),
+ }
+ )
super().remove_field(model, field)
def run_geometry_sql(self):
@@ -96,4 +113,6 @@ class OracleGISSchemaEditor(DatabaseSchemaEditor):
def _create_spatial_index_name(self, model, field):
# Oracle doesn't allow object names > 30 characters. Use this scheme
# instead of self._create_index_name() for backwards compatibility.
- return truncate_name('%s_%s_id' % (strip_quotes(model._meta.db_table), field.column), 30)
+ return truncate_name(
+ "%s_%s_id" % (strip_quotes(model._meta.db_table), field.column), 30
+ )
diff --git a/django/contrib/gis/db/backends/postgis/adapter.py b/django/contrib/gis/db/backends/postgis/adapter.py
index d6cb6ca47d..0e02427811 100644
--- a/django/contrib/gis/db/backends/postgis/adapter.py
+++ b/django/contrib/gis/db/backends/postgis/adapter.py
@@ -31,7 +31,9 @@ class PostGISAdapter:
if proto == ISQLQuote:
return self
else:
- raise Exception('Error implementing psycopg2 protocol. Is psycopg2 installed?')
+ raise Exception(
+ "Error implementing psycopg2 protocol. Is psycopg2 installed?"
+ )
def __eq__(self, other):
return isinstance(other, PostGISAdapter) and self.ewkb == other.ewkb
@@ -60,9 +62,9 @@ class PostGISAdapter:
"""
if self.is_geometry:
# Psycopg will figure out whether to use E'\\000' or '\000'.
- return b'%s(%s)' % (
- b'ST_GeogFromWKB' if self.geography else b'ST_GeomFromEWKB',
- self._adapter.getquoted()
+ return b"%s(%s)" % (
+ b"ST_GeogFromWKB" if self.geography else b"ST_GeomFromEWKB",
+ self._adapter.getquoted(),
)
else:
# For rasters, add explicit type cast to WKB string.
diff --git a/django/contrib/gis/db/backends/postgis/base.py b/django/contrib/gis/db/backends/postgis/base.py
index 5b93d7cf1e..87a30004a1 100644
--- a/django/contrib/gis/db/backends/postgis/base.py
+++ b/django/contrib/gis/db/backends/postgis/base.py
@@ -14,7 +14,7 @@ class DatabaseWrapper(Psycopg2DatabaseWrapper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- if kwargs.get('alias', '') != NO_DB_ALIAS:
+ if kwargs.get("alias", "") != NO_DB_ALIAS:
self.features = DatabaseFeatures(self)
self.ops = PostGISOperations(self)
self.introspection = PostGISIntrospection(self)
diff --git a/django/contrib/gis/db/backends/postgis/const.py b/django/contrib/gis/db/backends/postgis/const.py
index 193aa3fc36..d2ad51799f 100644
--- a/django/contrib/gis/db/backends/postgis/const.py
+++ b/django/contrib/gis/db/backends/postgis/const.py
@@ -15,13 +15,23 @@ POSTGIS_TO_GDAL = [1, 1, 1, 3, 1, 3, 2, 5, 4, None, 6, 7, None, None]
#
# Scale, origin, and skew have x and y values. PostGIS currently uses
# a fixed endianness (1) and there is only one version (0).
-POSTGIS_HEADER_STRUCTURE = 'B H H d d d d d d i H H'
+POSTGIS_HEADER_STRUCTURE = "B H H d d d d d d i H H"
# Lookup values to convert GDAL pixel types to struct characters. This is
# used to pack and unpack the pixel values of PostGIS raster bands.
GDAL_TO_STRUCT = [
- None, 'B', 'H', 'h', 'L', 'l', 'f', 'd',
- None, None, None, None,
+ None,
+ "B",
+ "H",
+ "h",
+ "L",
+ "l",
+ "f",
+ "d",
+ None,
+ None,
+ None,
+ None,
]
# Size of the packed value in bytes for different numerical types.
@@ -29,17 +39,17 @@ GDAL_TO_STRUCT = [
# when decomposing them into GDALRasters.
# See https://docs.python.org/library/struct.html#format-characters
STRUCT_SIZE = {
- 'b': 1, # Signed char
- 'B': 1, # Unsigned char
- '?': 1, # _Bool
- 'h': 2, # Short
- 'H': 2, # Unsigned short
- 'i': 4, # Integer
- 'I': 4, # Unsigned Integer
- 'l': 4, # Long
- 'L': 4, # Unsigned Long
- 'f': 4, # Float
- 'd': 8, # Double
+ "b": 1, # Signed char
+ "B": 1, # Unsigned char
+ "?": 1, # _Bool
+ "h": 2, # Short
+ "H": 2, # Unsigned short
+ "i": 4, # Integer
+ "I": 4, # Unsigned Integer
+ "l": 4, # Long
+ "L": 4, # Unsigned Long
+ "f": 4, # Float
+ "d": 8, # Double
}
# Pixel type specifies type of pixel values in a band. Storage flag specifies
diff --git a/django/contrib/gis/db/backends/postgis/introspection.py b/django/contrib/gis/db/backends/postgis/introspection.py
index 0647012b04..b12b7b912f 100644
--- a/django/contrib/gis/db/backends/postgis/introspection.py
+++ b/django/contrib/gis/db/backends/postgis/introspection.py
@@ -6,11 +6,11 @@ class PostGISIntrospection(DatabaseIntrospection):
postgis_oid_lookup = {} # Populated when introspection is performed.
ignored_tables = DatabaseIntrospection.ignored_tables + [
- 'geography_columns',
- 'geometry_columns',
- 'raster_columns',
- 'spatial_ref_sys',
- 'raster_overviews',
+ "geography_columns",
+ "geometry_columns",
+ "raster_columns",
+ "spatial_ref_sys",
+ "raster_overviews",
]
def get_field_type(self, data_type, description):
@@ -21,9 +21,13 @@ class PostGISIntrospection(DatabaseIntrospection):
# requests upon connection initialization, the `data_types_reverse`
# dictionary isn't updated until introspection is performed here.
with self.connection.cursor() as cursor:
- cursor.execute("SELECT oid, typname FROM pg_type WHERE typname IN ('geometry', 'geography')")
+ cursor.execute(
+ "SELECT oid, typname FROM pg_type WHERE typname IN ('geometry', 'geography')"
+ )
self.postgis_oid_lookup = dict(cursor.fetchall())
- self.data_types_reverse.update((oid, 'GeometryField') for oid in self.postgis_oid_lookup)
+ self.data_types_reverse.update(
+ (oid, "GeometryField") for oid in self.postgis_oid_lookup
+ )
return super().get_field_type(data_type, description)
def get_geometry_type(self, table_name, description):
@@ -34,27 +38,32 @@ class PostGISIntrospection(DatabaseIntrospection):
metadata tables to determine the geometry type.
"""
with self.connection.cursor() as cursor:
- cursor.execute("""
+ cursor.execute(
+ """
SELECT t.coord_dimension, t.srid, t.type FROM (
SELECT * FROM geometry_columns
UNION ALL
SELECT * FROM geography_columns
) AS t WHERE t.f_table_name = %s AND t.f_geometry_column = %s
- """, (table_name, description.name))
+ """,
+ (table_name, description.name),
+ )
row = cursor.fetchone()
if not row:
- raise Exception('Could not find a geometry or geography column for "%s"."%s"' %
- (table_name, description.name))
+ raise Exception(
+ 'Could not find a geometry or geography column for "%s"."%s"'
+ % (table_name, description.name)
+ )
dim, srid, field_type = row
# OGRGeomType does not require GDAL and makes it easy to convert
# from OGC geom type name to Django field.
field_type = OGRGeomType(field_type).django
# Getting any GeometryField keyword arguments that are not the default.
field_params = {}
- if self.postgis_oid_lookup.get(description.type_code) == 'geography':
- field_params['geography'] = True
+ if self.postgis_oid_lookup.get(description.type_code) == "geography":
+ field_params["geography"] = True
if srid != 4326:
- field_params['srid'] = srid
+ field_params["srid"] = srid
if dim != 2:
- field_params['dim'] = dim
+ field_params["dim"] = dim
return field_type, field_params
diff --git a/django/contrib/gis/db/backends/postgis/models.py b/django/contrib/gis/db/backends/postgis/models.py
index 0cd4d5505c..b7b568274a 100644
--- a/django/contrib/gis/db/backends/postgis/models.py
+++ b/django/contrib/gis/db/backends/postgis/models.py
@@ -10,6 +10,7 @@ class PostGISGeometryColumns(models.Model):
The 'geometry_columns' view from PostGIS. See the PostGIS
documentation at Ch. 4.3.2.
"""
+
f_table_catalog = models.CharField(max_length=256)
f_table_schema = models.CharField(max_length=256)
f_table_name = models.CharField(max_length=256)
@@ -19,12 +20,12 @@ class PostGISGeometryColumns(models.Model):
type = models.CharField(max_length=30)
class Meta:
- app_label = 'gis'
- db_table = 'geometry_columns'
+ app_label = "gis"
+ db_table = "geometry_columns"
managed = False
def __str__(self):
- return '%s.%s - %dD %s field (SRID: %d)' % (
+ return "%s.%s - %dD %s field (SRID: %d)" % (
self.f_table_name,
self.f_geometry_column,
self.coord_dimension,
@@ -38,7 +39,7 @@ class PostGISGeometryColumns(models.Model):
Return the name of the metadata column used to store the feature table
name.
"""
- return 'f_table_name'
+ return "f_table_name"
@classmethod
def geom_col_name(cls):
@@ -46,7 +47,7 @@ class PostGISGeometryColumns(models.Model):
Return the name of the metadata column used to store the feature
geometry column.
"""
- return 'f_geometry_column'
+ return "f_geometry_column"
class PostGISSpatialRefSys(models.Model, SpatialRefSysMixin):
@@ -54,6 +55,7 @@ class PostGISSpatialRefSys(models.Model, SpatialRefSysMixin):
The 'spatial_ref_sys' table from PostGIS. See the PostGIS
documentation at Ch. 4.2.1.
"""
+
srid = models.IntegerField(primary_key=True)
auth_name = models.CharField(max_length=256)
auth_srid = models.IntegerField()
@@ -61,8 +63,8 @@ class PostGISSpatialRefSys(models.Model, SpatialRefSysMixin):
proj4text = models.CharField(max_length=2048)
class Meta:
- app_label = 'gis'
- db_table = 'spatial_ref_sys'
+ app_label = "gis"
+ db_table = "spatial_ref_sys"
managed = False
@property
diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py
index 84110fce0f..b11b2efcf3 100644
--- a/django/contrib/gis/db/backends/postgis/operations.py
+++ b/django/contrib/gis/db/backends/postgis/operations.py
@@ -1,9 +1,7 @@
import re
from django.conf import settings
-from django.contrib.gis.db.backends.base.operations import (
- BaseSpatialOperations,
-)
+from django.contrib.gis.db.backends.base.operations import BaseSpatialOperations
from django.contrib.gis.db.backends.utils import SpatialOperator
from django.contrib.gis.db.models import GeometryField, RasterField
from django.contrib.gis.gdal import GDALRaster
@@ -22,7 +20,7 @@ from .models import PostGISGeometryColumns, PostGISSpatialRefSys
from .pgraster import from_pgraster
# Identifier to mark raster lookups as bilateral.
-BILATERAL = 'bilateral'
+BILATERAL = "bilateral"
class PostGISOperator(SpatialOperator):
@@ -39,56 +37,70 @@ class PostGISOperator(SpatialOperator):
def as_sql(self, connection, lookup, template_params, *args):
if lookup.lhs.output_field.geography and not self.geography:
- raise ValueError('PostGIS geography does not support the "%s" '
- 'function/operator.' % (self.func or self.op,))
+ raise ValueError(
+ 'PostGIS geography does not support the "%s" '
+ "function/operator." % (self.func or self.op,)
+ )
template_params = self.check_raster(lookup, template_params)
return super().as_sql(connection, lookup, template_params, *args)
def check_raster(self, lookup, template_params):
- spheroid = lookup.rhs_params and lookup.rhs_params[-1] == 'spheroid'
+ spheroid = lookup.rhs_params and lookup.rhs_params[-1] == "spheroid"
# Check which input is a raster.
- lhs_is_raster = lookup.lhs.field.geom_type == 'RASTER'
+ lhs_is_raster = lookup.lhs.field.geom_type == "RASTER"
rhs_is_raster = isinstance(lookup.rhs, GDALRaster)
# Look for band indices and inject them if provided.
if lookup.band_lhs is not None and lhs_is_raster:
if not self.func:
- raise ValueError('Band indices are not allowed for this operator, it works on bbox only.')
- template_params['lhs'] = '%s, %s' % (template_params['lhs'], lookup.band_lhs)
+ raise ValueError(
+ "Band indices are not allowed for this operator, it works on bbox only."
+ )
+ template_params["lhs"] = "%s, %s" % (
+ template_params["lhs"],
+ lookup.band_lhs,
+ )
if lookup.band_rhs is not None and rhs_is_raster:
if not self.func:
- raise ValueError('Band indices are not allowed for this operator, it works on bbox only.')
- template_params['rhs'] = '%s, %s' % (template_params['rhs'], lookup.band_rhs)
+ raise ValueError(
+ "Band indices are not allowed for this operator, it works on bbox only."
+ )
+ template_params["rhs"] = "%s, %s" % (
+ template_params["rhs"],
+ lookup.band_rhs,
+ )
# Convert rasters to polygons if necessary.
if not self.raster or spheroid:
# Operators without raster support.
if lhs_is_raster:
- template_params['lhs'] = 'ST_Polygon(%s)' % template_params['lhs']
+ template_params["lhs"] = "ST_Polygon(%s)" % template_params["lhs"]
if rhs_is_raster:
- template_params['rhs'] = 'ST_Polygon(%s)' % template_params['rhs']
+ template_params["rhs"] = "ST_Polygon(%s)" % template_params["rhs"]
elif self.raster == BILATERAL:
# Operators with raster support but don't support mixed (rast-geom)
# lookups.
if lhs_is_raster and not rhs_is_raster:
- template_params['lhs'] = 'ST_Polygon(%s)' % template_params['lhs']
+ template_params["lhs"] = "ST_Polygon(%s)" % template_params["lhs"]
elif rhs_is_raster and not lhs_is_raster:
- template_params['rhs'] = 'ST_Polygon(%s)' % template_params['rhs']
+ template_params["rhs"] = "ST_Polygon(%s)" % template_params["rhs"]
return template_params
class ST_Polygon(Func):
- function = 'ST_Polygon'
+ function = "ST_Polygon"
def __init__(self, expr):
super().__init__(expr)
expr = self.source_expressions[0]
if isinstance(expr, Value) and not expr._output_field_or_none:
- self.source_expressions[0] = Value(expr.value, output_field=RasterField(srid=expr.value.srid))
+ self.source_expressions[0] = Value(
+ expr.value, output_field=RasterField(srid=expr.value.srid)
+ )
@cached_property
def output_field(self):
@@ -96,64 +108,70 @@ class ST_Polygon(Func):
class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
- name = 'postgis'
+ name = "postgis"
postgis = True
- geom_func_prefix = 'ST_'
+ geom_func_prefix = "ST_"
Adapter = PostGISAdapter
- collect = geom_func_prefix + 'Collect'
- extent = geom_func_prefix + 'Extent'
- extent3d = geom_func_prefix + '3DExtent'
- length3d = geom_func_prefix + '3DLength'
- makeline = geom_func_prefix + 'MakeLine'
- perimeter3d = geom_func_prefix + '3DPerimeter'
- unionagg = geom_func_prefix + 'Union'
+ collect = geom_func_prefix + "Collect"
+ extent = geom_func_prefix + "Extent"
+ extent3d = geom_func_prefix + "3DExtent"
+ length3d = geom_func_prefix + "3DLength"
+ makeline = geom_func_prefix + "MakeLine"
+ perimeter3d = geom_func_prefix + "3DPerimeter"
+ unionagg = geom_func_prefix + "Union"
gis_operators = {
- 'bbcontains': PostGISOperator(op='~', raster=True),
- 'bboverlaps': PostGISOperator(op='&&', geography=True, raster=True),
- 'contained': PostGISOperator(op='@', raster=True),
- 'overlaps_left': PostGISOperator(op='&<', raster=BILATERAL),
- 'overlaps_right': PostGISOperator(op='&>', raster=BILATERAL),
- 'overlaps_below': PostGISOperator(op='&<|'),
- 'overlaps_above': PostGISOperator(op='|&>'),
- 'left': PostGISOperator(op='<<'),
- 'right': PostGISOperator(op='>>'),
- 'strictly_below': PostGISOperator(op='<<|'),
- 'strictly_above': PostGISOperator(op='|>>'),
- 'same_as': PostGISOperator(op='~=', raster=BILATERAL),
- 'exact': PostGISOperator(op='~=', raster=BILATERAL), # alias of same_as
- 'contains': PostGISOperator(func='ST_Contains', raster=BILATERAL),
- 'contains_properly': PostGISOperator(func='ST_ContainsProperly', raster=BILATERAL),
- 'coveredby': PostGISOperator(func='ST_CoveredBy', geography=True, raster=BILATERAL),
- 'covers': PostGISOperator(func='ST_Covers', geography=True, raster=BILATERAL),
- 'crosses': PostGISOperator(func='ST_Crosses'),
- 'disjoint': PostGISOperator(func='ST_Disjoint', raster=BILATERAL),
- 'equals': PostGISOperator(func='ST_Equals'),
- 'intersects': PostGISOperator(func='ST_Intersects', geography=True, raster=BILATERAL),
- 'overlaps': PostGISOperator(func='ST_Overlaps', raster=BILATERAL),
- 'relate': PostGISOperator(func='ST_Relate'),
- 'touches': PostGISOperator(func='ST_Touches', raster=BILATERAL),
- 'within': PostGISOperator(func='ST_Within', raster=BILATERAL),
- 'dwithin': PostGISOperator(func='ST_DWithin', geography=True, raster=BILATERAL),
+ "bbcontains": PostGISOperator(op="~", raster=True),
+ "bboverlaps": PostGISOperator(op="&&", geography=True, raster=True),
+ "contained": PostGISOperator(op="@", raster=True),
+ "overlaps_left": PostGISOperator(op="&<", raster=BILATERAL),
+ "overlaps_right": PostGISOperator(op="&>", raster=BILATERAL),
+ "overlaps_below": PostGISOperator(op="&<|"),
+ "overlaps_above": PostGISOperator(op="|&>"),
+ "left": PostGISOperator(op="<<"),
+ "right": PostGISOperator(op=">>"),
+ "strictly_below": PostGISOperator(op="<<|"),
+ "strictly_above": PostGISOperator(op="|>>"),
+ "same_as": PostGISOperator(op="~=", raster=BILATERAL),
+ "exact": PostGISOperator(op="~=", raster=BILATERAL), # alias of same_as
+ "contains": PostGISOperator(func="ST_Contains", raster=BILATERAL),
+ "contains_properly": PostGISOperator(
+ func="ST_ContainsProperly", raster=BILATERAL
+ ),
+ "coveredby": PostGISOperator(
+ func="ST_CoveredBy", geography=True, raster=BILATERAL
+ ),
+ "covers": PostGISOperator(func="ST_Covers", geography=True, raster=BILATERAL),
+ "crosses": PostGISOperator(func="ST_Crosses"),
+ "disjoint": PostGISOperator(func="ST_Disjoint", raster=BILATERAL),
+ "equals": PostGISOperator(func="ST_Equals"),
+ "intersects": PostGISOperator(
+ func="ST_Intersects", geography=True, raster=BILATERAL
+ ),
+ "overlaps": PostGISOperator(func="ST_Overlaps", raster=BILATERAL),
+ "relate": PostGISOperator(func="ST_Relate"),
+ "touches": PostGISOperator(func="ST_Touches", raster=BILATERAL),
+ "within": PostGISOperator(func="ST_Within", raster=BILATERAL),
+ "dwithin": PostGISOperator(func="ST_DWithin", geography=True, raster=BILATERAL),
}
unsupported_functions = set()
- select = '%s::bytea'
+ select = "%s::bytea"
select_extent = None
@cached_property
def function_names(self):
function_names = {
- 'AsWKB': 'ST_AsBinary',
- 'AsWKT': 'ST_AsText',
- 'BoundingCircle': 'ST_MinimumBoundingCircle',
- 'NumPoints': 'ST_NPoints',
+ "AsWKB": "ST_AsBinary",
+ "AsWKT": "ST_AsText",
+ "BoundingCircle": "ST_MinimumBoundingCircle",
+ "NumPoints": "ST_NPoints",
}
if self.spatial_version < (2, 4, 0):
- function_names['ForcePolygonCW'] = 'ST_ForceRHR'
+ function_names["ForcePolygonCW"] = "ST_ForceRHR"
return function_names
@cached_property
@@ -165,13 +183,13 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
# can be mitigated by setting `POSTGIS_VERSION` with a 3-tuple
# comprising user-supplied values for the major, minor, and
# subminor revision of PostGIS.
- if hasattr(settings, 'POSTGIS_VERSION'):
+ if hasattr(settings, "POSTGIS_VERSION"):
version = settings.POSTGIS_VERSION
else:
# Run a basic query to check the status of the connection so we're
# sure we only raise the error below if the problem comes from
# PostGIS and not from PostgreSQL itself (see #24862).
- self._get_postgis_func('version')
+ self._get_postgis_func("version")
try:
vtup = self.postgis_version_tuple()
@@ -179,9 +197,9 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
raise ImproperlyConfigured(
'Cannot determine PostGIS version for database "%s" '
'using command "SELECT postgis_lib_version()". '
- 'GeoDjango requires at least PostGIS version 2.4. '
- 'Was the database created from a spatial database '
- 'template?' % self.connection.settings_dict['NAME']
+ "GeoDjango requires at least PostGIS version 2.4. "
+ "Was the database created from a spatial database "
+ "template?" % self.connection.settings_dict["NAME"]
)
version = vtup[1:]
return version
@@ -194,7 +212,7 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
"""
if box is None:
return None
- ll, ur = box[4:-1].split(',')
+ ll, ur = box[4:-1].split(",")
xmin, ymin = map(float, ll.split())
xmax, ymax = map(float, ur.split())
return (xmin, ymin, xmax, ymax)
@@ -207,7 +225,7 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
"""
if box3d is None:
return None
- ll, ur = box3d[6:-1].split(',')
+ ll, ur = box3d[6:-1].split(",")
xmin, ymin, zmin = map(float, ll.split())
xmax, ymax, zmax = map(float, ur.split())
return (xmin, ymin, zmin, xmax, ymax, zmax)
@@ -216,22 +234,24 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
"""
Return the database field type for the given spatial field.
"""
- if f.geom_type == 'RASTER':
- return 'raster'
+ if f.geom_type == "RASTER":
+ return "raster"
# Type-based geometries.
# TODO: Support 'M' extension.
if f.dim == 3:
- geom_type = f.geom_type + 'Z'
+ geom_type = f.geom_type + "Z"
else:
geom_type = f.geom_type
if f.geography:
if f.srid != 4326:
- raise NotSupportedError('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:
- return 'geometry(%s,%d)' % (geom_type, f.srid)
+ return "geometry(%s,%d)" % (geom_type, f.srid)
def get_distance(self, f, dist_val, lookup_type):
"""
@@ -254,12 +274,16 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
if geography:
dist_param = value.m
elif geodetic:
- if lookup_type == 'dwithin':
- raise ValueError('Only numeric values of degree units are '
- 'allowed on geographic DWithin queries.')
+ if lookup_type == "dwithin":
+ raise ValueError(
+ "Only numeric values of degree units are "
+ "allowed on geographic DWithin queries."
+ )
dist_param = value.m
else:
- dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
+ dist_param = getattr(
+ value, Distance.unit_attname(f.units_name(self.connection))
+ )
else:
# Assuming the distance is in the units of the field.
dist_param = value
@@ -272,12 +296,12 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
not in the SRID of the field. Specifically, this routine will
substitute in the ST_Transform() function call.
"""
- transform_func = self.spatial_function_name('Transform')
- if hasattr(value, 'as_sql'):
+ transform_func = self.spatial_function_name("Transform")
+ if hasattr(value, "as_sql"):
if value.field.srid == f.srid:
- placeholder = '%s'
+ placeholder = "%s"
else:
- placeholder = '%s(%%s, %s)' % (transform_func, f.srid)
+ placeholder = "%s(%%s, %s)" % (transform_func, f.srid)
return placeholder
# Get the srid for this object
@@ -289,9 +313,9 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
# Adding Transform() to the SQL placeholder if the value srid
# is not equal to the field srid.
if value_srid is None or value_srid == f.srid:
- placeholder = '%s'
+ placeholder = "%s"
else:
- placeholder = '%s(%%s, %s)' % (transform_func, f.srid)
+ placeholder = "%s(%%s, %s)" % (transform_func, f.srid)
return placeholder
@@ -301,28 +325,28 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
"""
# Close out the connection. See #9437.
with self.connection.temporary_connection() as cursor:
- cursor.execute('SELECT %s()' % func)
+ cursor.execute("SELECT %s()" % func)
return cursor.fetchone()[0]
def postgis_geos_version(self):
"Return the version of the GEOS library used with PostGIS."
- return self._get_postgis_func('postgis_geos_version')
+ return self._get_postgis_func("postgis_geos_version")
def postgis_lib_version(self):
"Return the version number of the PostGIS library used with PostgreSQL."
- return self._get_postgis_func('postgis_lib_version')
+ return self._get_postgis_func("postgis_lib_version")
def postgis_proj_version(self):
"""Return the version of the PROJ library used with PostGIS."""
- return self._get_postgis_func('postgis_proj_version')
+ return self._get_postgis_func("postgis_proj_version")
def postgis_version(self):
"Return PostGIS version number and compile-time options."
- return self._get_postgis_func('postgis_version')
+ return self._get_postgis_func("postgis_version")
def postgis_full_version(self):
"Return PostGIS version number and compile-time options."
- return self._get_postgis_func('postgis_full_version')
+ return self._get_postgis_func("postgis_full_version")
def postgis_version_tuple(self):
"""
@@ -337,16 +361,16 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
Return the version of PROJ used by PostGIS as a tuple of the
major, minor, and subminor release numbers.
"""
- proj_regex = re.compile(r'(\d+)\.(\d+)\.(\d+)')
+ proj_regex = re.compile(r"(\d+)\.(\d+)\.(\d+)")
proj_ver_str = self.postgis_proj_version()
m = proj_regex.search(proj_ver_str)
if m:
return tuple(map(int, m.groups()))
else:
- raise Exception('Could not determine PROJ version from PostGIS.')
+ raise Exception("Could not determine PROJ version from PostGIS.")
def spatial_aggregate_name(self, agg_name):
- if agg_name == 'Extent3D':
+ if agg_name == "Extent3D":
return self.extent3d
else:
return self.geom_func_prefix + agg_name
@@ -366,15 +390,15 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
return super().distance_expr_for_lookup(
self._normalize_distance_lookup_arg(lhs),
self._normalize_distance_lookup_arg(rhs),
- **kwargs
+ **kwargs,
)
@staticmethod
def _normalize_distance_lookup_arg(arg):
is_raster = (
- arg.field.geom_type == 'RASTER'
- if hasattr(arg, 'field') else
- isinstance(arg, GDALRaster)
+ arg.field.geom_type == "RASTER"
+ if hasattr(arg, "field")
+ else isinstance(arg, GDALRaster)
)
return ST_Polygon(arg) if is_raster else arg
@@ -384,7 +408,8 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
def converter(value, expression, connection):
return None if value is None else GEOSGeometryBase(read(value), geom_class)
+
return converter
def get_area_att_for_field(self, field):
- return 'sq_m'
+ return "sq_m"
diff --git a/django/contrib/gis/db/backends/postgis/pgraster.py b/django/contrib/gis/db/backends/postgis/pgraster.py
index bfdeb6faf3..22794342ca 100644
--- a/django/contrib/gis/db/backends/postgis/pgraster.py
+++ b/django/contrib/gis/db/backends/postgis/pgraster.py
@@ -3,8 +3,13 @@ import struct
from django.core.exceptions import ValidationError
from .const import (
- BANDTYPE_FLAG_HASNODATA, BANDTYPE_PIXTYPE_MASK, GDAL_TO_POSTGIS,
- GDAL_TO_STRUCT, POSTGIS_HEADER_STRUCTURE, POSTGIS_TO_GDAL, STRUCT_SIZE,
+ BANDTYPE_FLAG_HASNODATA,
+ BANDTYPE_PIXTYPE_MASK,
+ GDAL_TO_POSTGIS,
+ GDAL_TO_STRUCT,
+ POSTGIS_HEADER_STRUCTURE,
+ POSTGIS_TO_GDAL,
+ STRUCT_SIZE,
)
@@ -12,14 +17,14 @@ def pack(structure, data):
"""
Pack data into hex string with little endian format.
"""
- return struct.pack('<' + structure, *data)
+ return struct.pack("<" + structure, *data)
def unpack(structure, data):
"""
Unpack little endian hexlified binary string into a list.
"""
- return struct.unpack('<' + structure, bytes.fromhex(data))
+ return struct.unpack("<" + structure, bytes.fromhex(data))
def chunk(data, index):
@@ -46,7 +51,7 @@ def from_pgraster(data):
while data:
# Get pixel type for this band
pixeltype_with_flags, data = chunk(data, 2)
- pixeltype_with_flags = unpack('B', pixeltype_with_flags)[0]
+ pixeltype_with_flags = unpack("B", pixeltype_with_flags)[0]
pixeltype = pixeltype_with_flags & BANDTYPE_PIXTYPE_MASK
# Convert datatype from PostGIS to GDAL & get pack type and size
@@ -62,11 +67,11 @@ def from_pgraster(data):
# Chunk and unpack band data (pack size times nr of pixels)
band, data = chunk(data, pack_size * header[10] * header[11])
- band_result = {'data': bytes.fromhex(band)}
+ band_result = {"data": bytes.fromhex(band)}
# Set the nodata value if the nodata flag is set.
if pixeltype_with_flags & BANDTYPE_FLAG_HASNODATA:
- band_result['nodata_value'] = nodata
+ band_result["nodata_value"] = nodata
# Append band data to band list
bands.append(band_result)
@@ -81,13 +86,14 @@ def from_pgraster(data):
raise ValidationError("Band pixeltypes are not all equal.")
return {
- 'srid': int(header[9]),
- 'width': header[10], 'height': header[11],
- 'datatype': pixeltypes[0],
- 'origin': (header[5], header[6]),
- 'scale': (header[3], header[4]),
- 'skew': (header[7], header[8]),
- 'bands': bands,
+ "srid": int(header[9]),
+ "width": header[10],
+ "height": header[11],
+ "datatype": pixeltypes[0],
+ "origin": (header[5], header[6]),
+ "scale": (header[3], header[4]),
+ "skew": (header[7], header[8]),
+ "bands": bands,
}
@@ -99,9 +105,18 @@ def to_pgraster(rast):
# the endianness and the PostGIS Raster Version, both are fixed by
# PostGIS at the moment.
rasterheader = (
- 1, 0, len(rast.bands), rast.scale.x, rast.scale.y,
- rast.origin.x, rast.origin.y, rast.skew.x, rast.skew.y,
- rast.srs.srid, rast.width, rast.height,
+ 1,
+ 0,
+ len(rast.bands),
+ rast.scale.x,
+ rast.scale.y,
+ rast.origin.x,
+ rast.origin.y,
+ rast.skew.x,
+ rast.skew.y,
+ rast.srs.srid,
+ rast.width,
+ rast.height,
)
# Pack raster header.
@@ -119,7 +134,7 @@ def to_pgraster(rast):
# For example, if the byte value is 71, then the datatype is
# 71 & ~BANDTYPE_FLAG_HASNODATA = 7 (32BSI)
# and the nodata value is True.
- structure = 'B' + GDAL_TO_STRUCT[band.datatype()]
+ structure = "B" + GDAL_TO_STRUCT[band.datatype()]
# Get band pixel type in PostGIS notation
pixeltype = GDAL_TO_POSTGIS[band.datatype()]
diff --git a/django/contrib/gis/db/backends/postgis/schema.py b/django/contrib/gis/db/backends/postgis/schema.py
index c574bed84f..77a9096ef4 100644
--- a/django/contrib/gis/db/backends/postgis/schema.py
+++ b/django/contrib/gis/db/backends/postgis/schema.py
@@ -3,29 +3,33 @@ from django.db.models.expressions import Col, Func
class PostGISSchemaEditor(DatabaseSchemaEditor):
- geom_index_type = 'GIST'
- geom_index_ops_nd = 'GIST_GEOMETRY_OPS_ND'
- rast_index_template = 'ST_ConvexHull(%(expressions)s)'
+ geom_index_type = "GIST"
+ geom_index_ops_nd = "GIST_GEOMETRY_OPS_ND"
+ rast_index_template = "ST_ConvexHull(%(expressions)s)"
- sql_alter_column_to_3d = "ALTER COLUMN %(column)s TYPE %(type)s USING ST_Force3D(%(column)s)::%(type)s"
- sql_alter_column_to_2d = "ALTER COLUMN %(column)s TYPE %(type)s USING ST_Force2D(%(column)s)::%(type)s"
+ sql_alter_column_to_3d = (
+ "ALTER COLUMN %(column)s TYPE %(type)s USING ST_Force3D(%(column)s)::%(type)s"
+ )
+ sql_alter_column_to_2d = (
+ "ALTER COLUMN %(column)s TYPE %(type)s USING ST_Force2D(%(column)s)::%(type)s"
+ )
def geo_quote_name(self, name):
return self.connection.ops.geo_quote_name(name)
def _field_should_be_indexed(self, model, field):
- if getattr(field, 'spatial_index', False):
+ if getattr(field, "spatial_index", False):
return True
return super()._field_should_be_indexed(model, field)
def _create_index_sql(self, model, *, fields=None, **kwargs):
- if fields is None or len(fields) != 1 or not hasattr(fields[0], 'geodetic'):
+ if fields is None or len(fields) != 1 or not hasattr(fields[0], "geodetic"):
return super()._create_index_sql(model, fields=fields, **kwargs)
field = fields[0]
expressions = None
opclasses = None
- if field.geom_type == 'RASTER':
+ if field.geom_type == "RASTER":
# For raster fields, wrap index creation SQL statement with ST_ConvexHull.
# Indexes on raster columns are based on the convex hull of the raster.
expressions = Func(Col(None, field), template=self.rast_index_template)
@@ -33,15 +37,15 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
elif field.dim > 2 and not field.geography:
# Use "nd" ops which are fast on multidimensional cases
opclasses = [self.geom_index_ops_nd]
- name = kwargs.get('name')
+ name = kwargs.get("name")
if not name:
- name = self._create_index_name(model._meta.db_table, [field.column], '_id')
+ name = self._create_index_name(model._meta.db_table, [field.column], "_id")
return super()._create_index_sql(
model,
fields=fields,
name=name,
- using=' USING %s' % self.geom_index_type,
+ using=" USING %s" % self.geom_index_type,
opclasses=opclasses,
expressions=expressions,
)
@@ -50,7 +54,7 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
"""
Special case when dimension changed.
"""
- if not hasattr(old_field, 'dim') or not hasattr(new_field, 'dim'):
+ if not hasattr(old_field, "dim") or not hasattr(new_field, "dim"):
return super()._alter_column_type_sql(table, old_field, new_field, new_type)
if old_field.dim == 2 and new_field.dim == 3:
@@ -61,7 +65,8 @@ class PostGISSchemaEditor(DatabaseSchemaEditor):
sql_alter = self.sql_alter_column_type
return (
(
- sql_alter % {
+ sql_alter
+ % {
"column": self.quote_name(new_field.column),
"type": new_type,
},
diff --git a/django/contrib/gis/db/backends/spatialite/adapter.py b/django/contrib/gis/db/backends/spatialite/adapter.py
index 2a36159b06..91d14dc3c7 100644
--- a/django/contrib/gis/db/backends/spatialite/adapter.py
+++ b/django/contrib/gis/db/backends/spatialite/adapter.py
@@ -4,6 +4,7 @@ from django.db.backends.sqlite3.base import Database
class SpatiaLiteAdapter(WKTAdapter):
"SQLite adapter for geometry objects."
+
def __conform__(self, protocol):
if protocol is Database.PrepareProtocol:
return str(self)
diff --git a/django/contrib/gis/db/backends/spatialite/base.py b/django/contrib/gis/db/backends/spatialite/base.py
index fef7de62af..3359a7a971 100644
--- a/django/contrib/gis/db/backends/spatialite/base.py
+++ b/django/contrib/gis/db/backends/spatialite/base.py
@@ -2,9 +2,7 @@ from ctypes.util import find_library
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
-from django.db.backends.sqlite3.base import (
- DatabaseWrapper as SQLiteDatabaseWrapper,
-)
+from django.db.backends.sqlite3.base import DatabaseWrapper as SQLiteDatabaseWrapper
from .client import SpatiaLiteClient
from .features import DatabaseFeatures
@@ -27,12 +25,16 @@ class DatabaseWrapper(SQLiteDatabaseWrapper):
# (`libspatialite`). If it's not in the system library path (e.g., it
# cannot be found by `ctypes.util.find_library`), then it may be set
# manually in the settings via the `SPATIALITE_LIBRARY_PATH` setting.
- self.lib_spatialite_paths = [name for name in [
- getattr(settings, 'SPATIALITE_LIBRARY_PATH', None),
- 'mod_spatialite.so',
- 'mod_spatialite',
- find_library('spatialite'),
- ] if name is not None]
+ self.lib_spatialite_paths = [
+ name
+ for name in [
+ getattr(settings, "SPATIALITE_LIBRARY_PATH", None),
+ "mod_spatialite.so",
+ "mod_spatialite",
+ find_library("spatialite"),
+ ]
+ if name is not None
+ ]
super().__init__(*args, **kwargs)
def get_new_connection(self, conn_params):
@@ -42,26 +44,26 @@ class DatabaseWrapper(SQLiteDatabaseWrapper):
conn.enable_load_extension(True)
except AttributeError:
raise ImproperlyConfigured(
- 'SpatiaLite requires SQLite to be configured to allow '
- 'extension loading.'
+ "SpatiaLite requires SQLite to be configured to allow "
+ "extension loading."
)
# Load the SpatiaLite library extension on the connection.
for path in self.lib_spatialite_paths:
try:
conn.load_extension(path)
except Exception:
- if getattr(settings, 'SPATIALITE_LIBRARY_PATH', None):
+ if getattr(settings, "SPATIALITE_LIBRARY_PATH", None):
raise ImproperlyConfigured(
- 'Unable to load the SpatiaLite library extension '
- 'as specified in your SPATIALITE_LIBRARY_PATH setting.'
+ "Unable to load the SpatiaLite library extension "
+ "as specified in your SPATIALITE_LIBRARY_PATH setting."
)
continue
else:
break
else:
raise ImproperlyConfigured(
- 'Unable to load the SpatiaLite library extension. '
- 'Library names tried: %s' % ', '.join(self.lib_spatialite_paths)
+ "Unable to load the SpatiaLite library extension. "
+ "Library names tried: %s" % ", ".join(self.lib_spatialite_paths)
)
return conn
@@ -72,6 +74,6 @@ class DatabaseWrapper(SQLiteDatabaseWrapper):
cursor.execute("PRAGMA table_info(geometry_columns);")
if cursor.fetchall() == []:
if self.ops.spatial_version < (5,):
- cursor.execute('SELECT InitSpatialMetaData(1)')
+ cursor.execute("SELECT InitSpatialMetaData(1)")
else:
- cursor.execute('SELECT InitSpatialMetaDataFull(1)')
+ cursor.execute("SELECT InitSpatialMetaDataFull(1)")
diff --git a/django/contrib/gis/db/backends/spatialite/client.py b/django/contrib/gis/db/backends/spatialite/client.py
index c9dfd1a527..527fe153bb 100644
--- a/django/contrib/gis/db/backends/spatialite/client.py
+++ b/django/contrib/gis/db/backends/spatialite/client.py
@@ -2,4 +2,4 @@ from django.db.backends.sqlite3.client import DatabaseClient
class SpatiaLiteClient(DatabaseClient):
- executable_name = 'spatialite'
+ executable_name = "spatialite"
diff --git a/django/contrib/gis/db/backends/spatialite/features.py b/django/contrib/gis/db/backends/spatialite/features.py
index b6c1746c07..9504bb0949 100644
--- a/django/contrib/gis/db/backends/spatialite/features.py
+++ b/django/contrib/gis/db/backends/spatialite/features.py
@@ -16,9 +16,11 @@ class DatabaseFeatures(BaseSpatialFeatures, SQLiteDatabaseFeatures):
@cached_property
def django_test_skips(self):
skips = super().django_test_skips
- skips.update({
- "SpatiaLite doesn't support distance lookups with Distance objects.": {
- 'gis_tests.geogapp.tests.GeographyTest.test02_distance_lookup',
- },
- })
+ skips.update(
+ {
+ "SpatiaLite doesn't support distance lookups with Distance objects.": {
+ "gis_tests.geogapp.tests.GeographyTest.test02_distance_lookup",
+ },
+ }
+ )
return skips
diff --git a/django/contrib/gis/db/backends/spatialite/introspection.py b/django/contrib/gis/db/backends/spatialite/introspection.py
index 0feeb24397..8d0003fd53 100644
--- a/django/contrib/gis/db/backends/spatialite/introspection.py
+++ b/django/contrib/gis/db/backends/spatialite/introspection.py
@@ -1,6 +1,7 @@
from django.contrib.gis.gdal import OGRGeomType
from django.db.backends.sqlite3.introspection import (
- DatabaseIntrospection, FlexibleFieldLookupDict,
+ DatabaseIntrospection,
+ FlexibleFieldLookupDict,
)
@@ -9,15 +10,16 @@ class GeoFlexibleFieldLookupDict(FlexibleFieldLookupDict):
Subclass that includes updates the `base_data_types_reverse` dict
for geometry field types.
"""
+
base_data_types_reverse = {
**FlexibleFieldLookupDict.base_data_types_reverse,
- 'point': 'GeometryField',
- 'linestring': 'GeometryField',
- 'polygon': 'GeometryField',
- 'multipoint': 'GeometryField',
- 'multilinestring': 'GeometryField',
- 'multipolygon': 'GeometryField',
- 'geometrycollection': 'GeometryField',
+ "point": "GeometryField",
+ "linestring": "GeometryField",
+ "polygon": "GeometryField",
+ "multipoint": "GeometryField",
+ "multilinestring": "GeometryField",
+ "multipolygon": "GeometryField",
+ "geometrycollection": "GeometryField",
}
@@ -27,14 +29,18 @@ class SpatiaLiteIntrospection(DatabaseIntrospection):
def get_geometry_type(self, table_name, description):
with self.connection.cursor() as cursor:
# Querying the `geometry_columns` table to get additional metadata.
- cursor.execute('SELECT coord_dimension, srid, geometry_type '
- 'FROM geometry_columns '
- 'WHERE f_table_name=%s AND f_geometry_column=%s',
- (table_name, description.name))
+ cursor.execute(
+ "SELECT coord_dimension, srid, geometry_type "
+ "FROM geometry_columns "
+ "WHERE f_table_name=%s AND f_geometry_column=%s",
+ (table_name, description.name),
+ )
row = cursor.fetchone()
if not row:
- raise Exception('Could not find a geometry column for "%s"."%s"' %
- (table_name, description.name))
+ raise Exception(
+ 'Could not find a geometry column for "%s"."%s"'
+ % (table_name, description.name)
+ )
# OGRGeomType does not require GDAL and makes it easy to convert
# from OGC geom type name to Django field.
@@ -51,18 +57,21 @@ class SpatiaLiteIntrospection(DatabaseIntrospection):
srid = row[1]
field_params = {}
if srid != 4326:
- field_params['srid'] = srid
- if (isinstance(dim, str) and 'Z' in dim) or dim == 3:
- field_params['dim'] = 3
+ field_params["srid"] = srid
+ if (isinstance(dim, str) and "Z" in dim) or dim == 3:
+ field_params["dim"] = 3
return field_type, field_params
def get_constraints(self, cursor, table_name):
constraints = super().get_constraints(cursor, table_name)
- cursor.execute('SELECT f_geometry_column '
- 'FROM geometry_columns '
- 'WHERE f_table_name=%s AND spatial_index_enabled=1', (table_name,))
+ cursor.execute(
+ "SELECT f_geometry_column "
+ "FROM geometry_columns "
+ "WHERE f_table_name=%s AND spatial_index_enabled=1",
+ (table_name,),
+ )
for row in cursor.fetchall():
- constraints['%s__spatial__index' % row[0]] = {
+ constraints["%s__spatial__index" % row[0]] = {
"columns": [row[0]],
"primary_key": False,
"unique": False,
diff --git a/django/contrib/gis/db/backends/spatialite/models.py b/django/contrib/gis/db/backends/spatialite/models.py
index 577c7236e3..7cc98ae126 100644
--- a/django/contrib/gis/db/backends/spatialite/models.py
+++ b/django/contrib/gis/db/backends/spatialite/models.py
@@ -9,20 +9,21 @@ class SpatialiteGeometryColumns(models.Model):
"""
The 'geometry_columns' table from SpatiaLite.
"""
+
f_table_name = models.CharField(max_length=256)
f_geometry_column = models.CharField(max_length=256)
coord_dimension = models.IntegerField()
srid = models.IntegerField(primary_key=True)
spatial_index_enabled = models.IntegerField()
- type = models.IntegerField(db_column='geometry_type')
+ type = models.IntegerField(db_column="geometry_type")
class Meta:
- app_label = 'gis'
- db_table = 'geometry_columns'
+ app_label = "gis"
+ db_table = "geometry_columns"
managed = False
def __str__(self):
- return '%s.%s - %dD %s field (SRID: %d)' % (
+ return "%s.%s - %dD %s field (SRID: %d)" % (
self.f_table_name,
self.f_geometry_column,
self.coord_dimension,
@@ -36,7 +37,7 @@ class SpatialiteGeometryColumns(models.Model):
Return the name of the metadata column used to store the feature table
name.
"""
- return 'f_table_name'
+ return "f_table_name"
@classmethod
def geom_col_name(cls):
@@ -44,13 +45,14 @@ class SpatialiteGeometryColumns(models.Model):
Return the name of the metadata column used to store the feature
geometry column.
"""
- return 'f_geometry_column'
+ return "f_geometry_column"
class SpatialiteSpatialRefSys(models.Model, SpatialRefSysMixin):
"""
The 'spatial_ref_sys' table from SpatiaLite.
"""
+
srid = models.IntegerField(primary_key=True)
auth_name = models.CharField(max_length=256)
auth_srid = models.IntegerField()
@@ -59,8 +61,8 @@ class SpatialiteSpatialRefSys(models.Model, SpatialRefSysMixin):
srtext = models.CharField(max_length=2048)
class Meta:
- app_label = 'gis'
- db_table = 'spatial_ref_sys'
+ app_label = "gis"
+ db_table = "spatial_ref_sys"
managed = False
@property
diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py
index 8dcd62de9b..8003fcb6c6 100644
--- a/django/contrib/gis/db/backends/spatialite/operations.py
+++ b/django/contrib/gis/db/backends/spatialite/operations.py
@@ -3,9 +3,7 @@ SQL functions reference lists:
https://www.gaia-gis.it/gaia-sins/spatialite-sql-4.3.0.html
"""
from django.contrib.gis.db import models
-from django.contrib.gis.db.backends.base.operations import (
- BaseSpatialOperations,
-)
+from django.contrib.gis.db.backends.base.operations import BaseSpatialOperations
from django.contrib.gis.db.backends.spatialite.adapter import SpatiaLiteAdapter
from django.contrib.gis.db.backends.utils import SpatialOperator
from django.contrib.gis.geos.geometry import GEOSGeometry, GEOSGeometryBase
@@ -20,69 +18,69 @@ from django.utils.version import get_version_tuple
class SpatialiteNullCheckOperator(SpatialOperator):
def as_sql(self, connection, lookup, template_params, sql_params):
sql, params = super().as_sql(connection, lookup, template_params, sql_params)
- return '%s > 0' % sql, params
+ return "%s > 0" % sql, params
class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
- name = 'spatialite'
+ name = "spatialite"
spatialite = True
Adapter = SpatiaLiteAdapter
- collect = 'Collect'
- extent = 'Extent'
- makeline = 'MakeLine'
- unionagg = 'GUnion'
+ collect = "Collect"
+ extent = "Extent"
+ makeline = "MakeLine"
+ unionagg = "GUnion"
- from_text = 'GeomFromText'
+ from_text = "GeomFromText"
gis_operators = {
# Binary predicates
- 'equals': SpatialiteNullCheckOperator(func='Equals'),
- 'disjoint': SpatialiteNullCheckOperator(func='Disjoint'),
- 'touches': SpatialiteNullCheckOperator(func='Touches'),
- 'crosses': SpatialiteNullCheckOperator(func='Crosses'),
- 'within': SpatialiteNullCheckOperator(func='Within'),
- 'overlaps': SpatialiteNullCheckOperator(func='Overlaps'),
- 'contains': SpatialiteNullCheckOperator(func='Contains'),
- 'intersects': SpatialiteNullCheckOperator(func='Intersects'),
- 'relate': SpatialiteNullCheckOperator(func='Relate'),
- 'coveredby': SpatialiteNullCheckOperator(func='CoveredBy'),
- 'covers': SpatialiteNullCheckOperator(func='Covers'),
+ "equals": SpatialiteNullCheckOperator(func="Equals"),
+ "disjoint": SpatialiteNullCheckOperator(func="Disjoint"),
+ "touches": SpatialiteNullCheckOperator(func="Touches"),
+ "crosses": SpatialiteNullCheckOperator(func="Crosses"),
+ "within": SpatialiteNullCheckOperator(func="Within"),
+ "overlaps": SpatialiteNullCheckOperator(func="Overlaps"),
+ "contains": SpatialiteNullCheckOperator(func="Contains"),
+ "intersects": SpatialiteNullCheckOperator(func="Intersects"),
+ "relate": SpatialiteNullCheckOperator(func="Relate"),
+ "coveredby": SpatialiteNullCheckOperator(func="CoveredBy"),
+ "covers": SpatialiteNullCheckOperator(func="Covers"),
# Returns true if B's bounding box completely contains A's bounding box.
- 'contained': SpatialOperator(func='MbrWithin'),
+ "contained": SpatialOperator(func="MbrWithin"),
# Returns true if A's bounding box completely contains B's bounding box.
- 'bbcontains': SpatialOperator(func='MbrContains'),
+ "bbcontains": SpatialOperator(func="MbrContains"),
# Returns true if A's bounding box overlaps B's bounding box.
- 'bboverlaps': SpatialOperator(func='MbrOverlaps'),
+ "bboverlaps": SpatialOperator(func="MbrOverlaps"),
# These are implemented here as synonyms for Equals
- 'same_as': SpatialiteNullCheckOperator(func='Equals'),
- 'exact': SpatialiteNullCheckOperator(func='Equals'),
+ "same_as": SpatialiteNullCheckOperator(func="Equals"),
+ "exact": SpatialiteNullCheckOperator(func="Equals"),
# Distance predicates
- 'dwithin': SpatialOperator(func='PtDistWithin'),
+ "dwithin": SpatialOperator(func="PtDistWithin"),
}
disallowed_aggregates = (models.Extent3D,)
- select = 'CAST (AsEWKB(%s) AS BLOB)'
+ select = "CAST (AsEWKB(%s) AS BLOB)"
function_names = {
- 'AsWKB': 'St_AsBinary',
- 'ForcePolygonCW': 'ST_ForceLHR',
- 'Length': 'ST_Length',
- 'LineLocatePoint': 'ST_Line_Locate_Point',
- 'NumPoints': 'ST_NPoints',
- 'Reverse': 'ST_Reverse',
- 'Scale': 'ScaleCoords',
- 'Translate': 'ST_Translate',
- 'Union': 'ST_Union',
+ "AsWKB": "St_AsBinary",
+ "ForcePolygonCW": "ST_ForceLHR",
+ "Length": "ST_Length",
+ "LineLocatePoint": "ST_Line_Locate_Point",
+ "NumPoints": "ST_NPoints",
+ "Reverse": "ST_Reverse",
+ "Scale": "ScaleCoords",
+ "Translate": "ST_Translate",
+ "Union": "ST_Union",
}
@cached_property
def unsupported_functions(self):
- unsupported = {'BoundingCircle', 'GeometryDistance', 'MemSize'}
+ unsupported = {"BoundingCircle", "GeometryDistance", "MemSize"}
if not self.geom_lib_version():
- unsupported |= {'Azimuth', 'GeoHash', 'MakeValid'}
+ unsupported |= {"Azimuth", "GeoHash", "MakeValid"}
return unsupported
@cached_property
@@ -93,12 +91,11 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
except Exception as exc:
raise ImproperlyConfigured(
'Cannot determine the SpatiaLite version for the "%s" database. '
- 'Was the SpatiaLite initialization SQL loaded on this database?' % (
- self.connection.settings_dict['NAME'],
- )
+ "Was the SpatiaLite initialization SQL loaded on this database?"
+ % (self.connection.settings_dict["NAME"],)
) from exc
if version < (4, 3, 0):
- raise ImproperlyConfigured('GeoDjango supports SpatiaLite 4.3.0 and above.')
+ raise ImproperlyConfigured("GeoDjango supports SpatiaLite 4.3.0 and above.")
return version
def convert_extent(self, box):
@@ -129,14 +126,16 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
value = value[0]
if isinstance(value, Distance):
if f.geodetic(self.connection):
- if lookup_type == 'dwithin':
+ if lookup_type == "dwithin":
raise ValueError(
- 'Only numeric values of degree units are allowed on '
- 'geographic DWithin queries.'
+ "Only numeric values of degree units are allowed on "
+ "geographic DWithin queries."
)
dist_param = value.m
else:
- dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
+ dist_param = getattr(
+ value, Distance.unit_attname(f.units_name(self.connection))
+ )
else:
dist_param = value
return [dist_param]
@@ -149,7 +148,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
"""
cursor = self.connection._cursor()
try:
- cursor.execute('SELECT %s' % func)
+ cursor.execute("SELECT %s" % func)
row = cursor.fetchone()
finally:
cursor.close()
@@ -157,19 +156,19 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
def geos_version(self):
"Return the version of GEOS used by SpatiaLite as a string."
- return self._get_spatialite_func('geos_version()')
+ return self._get_spatialite_func("geos_version()")
def proj_version(self):
"""Return the version of the PROJ library used by SpatiaLite."""
- return self._get_spatialite_func('proj4_version()')
+ return self._get_spatialite_func("proj4_version()")
def lwgeom_version(self):
"""Return the version of LWGEOM library used by SpatiaLite."""
- return self._get_spatialite_func('lwgeom_version()')
+ return self._get_spatialite_func("lwgeom_version()")
def rttopo_version(self):
"""Return the version of RTTOPO library used by SpatiaLite."""
- return self._get_spatialite_func('rttopo_version()')
+ return self._get_spatialite_func("rttopo_version()")
def geom_lib_version(self):
"""
@@ -183,7 +182,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
def spatialite_version(self):
"Return the SpatiaLite library version as a string."
- return self._get_spatialite_func('spatialite_version()')
+ return self._get_spatialite_func("spatialite_version()")
def spatialite_version_tuple(self):
"""
@@ -198,7 +197,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
Return the spatial aggregate SQL template and function for the
given Aggregate instance.
"""
- agg_name = 'unionagg' if agg_name.lower() == 'union' else agg_name.lower()
+ agg_name = "unionagg" if agg_name.lower() == "union" else agg_name.lower()
return getattr(self, agg_name)
# Routines for getting the OGC-compliant models.
@@ -206,12 +205,14 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
from django.contrib.gis.db.backends.spatialite.models import (
SpatialiteGeometryColumns,
)
+
return SpatialiteGeometryColumns
def spatial_ref_sys(self):
from django.contrib.gis.db.backends.spatialite.models import (
SpatialiteSpatialRefSys,
)
+
return SpatialiteSpatialRefSys
def get_geometry_converter(self, expression):
@@ -220,4 +221,5 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
def converter(value, expression, connection):
return None if value is None else GEOSGeometryBase(read(value), geom_class)
+
return converter
diff --git a/django/contrib/gis/db/backends/spatialite/schema.py b/django/contrib/gis/db/backends/spatialite/schema.py
index 066ce6d732..d37632edf8 100644
--- a/django/contrib/gis/db/backends/spatialite/schema.py
+++ b/django/contrib/gis/db/backends/spatialite/schema.py
@@ -14,7 +14,9 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
"%(geom_type)s, %(dim)s)"
)
sql_remove_geometry_metadata = "SELECT DiscardGeometryColumn(%(table)s, %(column)s)"
- sql_discard_geometry_columns = "DELETE FROM %(geom_table)s WHERE f_table_name = %(table)s"
+ sql_discard_geometry_columns = (
+ "DELETE FROM %(geom_table)s WHERE f_table_name = %(table)s"
+ )
sql_update_geometry_columns = (
"UPDATE %(geom_table)s SET f_table_name = %(new_table)s "
"WHERE f_table_name = %(old_table)s"
@@ -36,12 +38,14 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
def column_sql(self, model, field, include_default=False):
from django.contrib.gis.db.models import GeometryField
+
if not isinstance(field, GeometryField):
return super().column_sql(model, field, include_default)
# Geometry columns are created by the `AddGeometryColumn` function
self.geometry_sql.append(
- self.sql_add_geometry_column % {
+ self.sql_add_geometry_column
+ % {
"table": self.geo_quote_name(model._meta.db_table),
"column": self.geo_quote_name(field.column),
"srid": field.srid,
@@ -53,7 +57,8 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
if field.spatial_index:
self.geometry_sql.append(
- self.sql_add_spatial_index % {
+ self.sql_add_spatial_index
+ % {
"table": self.quote_name(model._meta.db_table),
"column": self.quote_name(field.column),
}
@@ -62,13 +67,15 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
def remove_geometry_metadata(self, model, field):
self.execute(
- self.sql_remove_geometry_metadata % {
+ self.sql_remove_geometry_metadata
+ % {
"table": self.quote_name(model._meta.db_table),
"column": self.quote_name(field.column),
}
)
self.execute(
- self.sql_drop_spatial_index % {
+ self.sql_drop_spatial_index
+ % {
"table": model._meta.db_table,
"column": field.column,
}
@@ -92,7 +99,8 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
for geom_table in self.geometry_tables:
try:
self.execute(
- self.sql_discard_geometry_columns % {
+ self.sql_discard_geometry_columns
+ % {
"geom_table": geom_table,
"table": self.quote_name(model._meta.db_table),
}
@@ -103,6 +111,7 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
def add_field(self, model, field):
from django.contrib.gis.db.models import GeometryField
+
if isinstance(field, GeometryField):
# Populate self.geometry_sql
self.column_sql(model, field)
@@ -125,14 +134,17 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
else:
super().remove_field(model, field)
- def alter_db_table(self, model, old_db_table, new_db_table, disable_constraints=True):
+ def alter_db_table(
+ self, model, old_db_table, new_db_table, disable_constraints=True
+ ):
from django.contrib.gis.db.models import GeometryField
# Remove geometry-ness from temp table
for field in model._meta.local_fields:
if isinstance(field, GeometryField):
self.execute(
- self.sql_remove_geometry_metadata % {
+ self.sql_remove_geometry_metadata
+ % {
"table": self.quote_name(old_db_table),
"column": self.quote_name(field.column),
}
@@ -143,7 +155,8 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
for geom_table in self.geometry_tables:
try:
self.execute(
- self.sql_update_geometry_columns % {
+ self.sql_update_geometry_columns
+ % {
"geom_table": geom_table,
"old_table": self.quote_name(old_db_table),
"new_table": self.quote_name(new_db_table),
@@ -154,15 +167,25 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
# Re-add geometry-ness and rename spatial index tables
for field in model._meta.local_fields:
if isinstance(field, GeometryField):
- self.execute(self.sql_recover_geometry_metadata % {
- "table": self.geo_quote_name(new_db_table),
- "column": self.geo_quote_name(field.column),
- "srid": field.srid,
- "geom_type": self.geo_quote_name(field.geom_type),
- "dim": field.dim,
- })
- if getattr(field, 'spatial_index', False):
- self.execute(self.sql_rename_table % {
- "old_table": self.quote_name("idx_%s_%s" % (old_db_table, field.column)),
- "new_table": self.quote_name("idx_%s_%s" % (new_db_table, field.column)),
- })
+ self.execute(
+ self.sql_recover_geometry_metadata
+ % {
+ "table": self.geo_quote_name(new_db_table),
+ "column": self.geo_quote_name(field.column),
+ "srid": field.srid,
+ "geom_type": self.geo_quote_name(field.geom_type),
+ "dim": field.dim,
+ }
+ )
+ if getattr(field, "spatial_index", False):
+ self.execute(
+ self.sql_rename_table
+ % {
+ "old_table": self.quote_name(
+ "idx_%s_%s" % (old_db_table, field.column)
+ ),
+ "new_table": self.quote_name(
+ "idx_%s_%s" % (new_db_table, field.column)
+ ),
+ }
+ )
diff --git a/django/contrib/gis/db/backends/utils.py b/django/contrib/gis/db/backends/utils.py
index d479009d4e..ffb7420019 100644
--- a/django/contrib/gis/db/backends/utils.py
+++ b/django/contrib/gis/db/backends/utils.py
@@ -8,6 +8,7 @@ class SpatialOperator:
"""
Class encapsulating the behavior specific to a GIS operation (used by lookups).
"""
+
sql_template = None
def __init__(self, op=None, func=None):
@@ -17,11 +18,11 @@ class SpatialOperator:
@property
def default_template(self):
if self.func:
- return '%(func)s(%(lhs)s, %(rhs)s)'
+ return "%(func)s(%(lhs)s, %(rhs)s)"
else:
- return '%(lhs)s %(op)s %(rhs)s'
+ return "%(lhs)s %(op)s %(rhs)s"
def as_sql(self, connection, lookup, template_params, sql_params):
sql_template = self.sql_template or lookup.sql_template or self.default_template
- template_params.update({'op': self.op, 'func': self.func})
+ template_params.update({"op": self.op, "func": self.func})
return sql_template % template_params, sql_params
diff --git a/django/contrib/gis/db/models/__init__.py b/django/contrib/gis/db/models/__init__.py
index 2e472557d8..0d5d45d272 100644
--- a/django/contrib/gis/db/models/__init__.py
+++ b/django/contrib/gis/db/models/__init__.py
@@ -5,14 +5,26 @@ import django.contrib.gis.db.models.lookups # NOQA
from django.contrib.gis.db.models.aggregates import * # NOQA
from django.contrib.gis.db.models.aggregates import __all__ as aggregates_all
from django.contrib.gis.db.models.fields import (
- GeometryCollectionField, GeometryField, LineStringField,
- MultiLineStringField, MultiPointField, MultiPolygonField, PointField,
- PolygonField, RasterField,
+ GeometryCollectionField,
+ GeometryField,
+ LineStringField,
+ MultiLineStringField,
+ MultiPointField,
+ MultiPolygonField,
+ PointField,
+ PolygonField,
+ RasterField,
)
__all__ = models_all + aggregates_all
__all__ += [
- 'GeometryCollectionField', 'GeometryField', 'LineStringField',
- 'MultiLineStringField', 'MultiPointField', 'MultiPolygonField', 'PointField',
- 'PolygonField', 'RasterField',
+ "GeometryCollectionField",
+ "GeometryField",
+ "LineStringField",
+ "MultiLineStringField",
+ "MultiPointField",
+ "MultiPolygonField",
+ "PointField",
+ "PolygonField",
+ "RasterField",
]
diff --git a/django/contrib/gis/db/models/aggregates.py b/django/contrib/gis/db/models/aggregates.py
index 3aa46a52c0..c19cbd06c3 100644
--- a/django/contrib/gis/db/models/aggregates.py
+++ b/django/contrib/gis/db/models/aggregates.py
@@ -1,10 +1,13 @@
from django.contrib.gis.db.models.fields import (
- ExtentField, GeometryCollectionField, GeometryField, LineStringField,
+ ExtentField,
+ GeometryCollectionField,
+ GeometryField,
+ LineStringField,
)
from django.db.models import Aggregate, Value
from django.utils.functional import cached_property
-__all__ = ['Collect', 'Extent', 'Extent3D', 'MakeLine', 'Union']
+__all__ = ["Collect", "Extent", "Extent3D", "MakeLine", "Union"]
class GeoAggregate(Aggregate):
@@ -23,37 +26,45 @@ class GeoAggregate(Aggregate):
compiler,
connection,
function=function or connection.ops.spatial_aggregate_name(self.name),
- **extra_context
+ **extra_context,
)
def as_oracle(self, compiler, connection, **extra_context):
if not self.is_extent:
- tolerance = self.extra.get('tolerance') or getattr(self, 'tolerance', 0.05)
+ tolerance = self.extra.get("tolerance") or getattr(self, "tolerance", 0.05)
clone = self.copy()
- clone.set_source_expressions([
- *self.get_source_expressions(),
- Value(tolerance),
- ])
- template = '%(function)s(SDOAGGRTYPE(%(expressions)s))'
- return clone.as_sql(compiler, connection, template=template, **extra_context)
+ clone.set_source_expressions(
+ [
+ *self.get_source_expressions(),
+ Value(tolerance),
+ ]
+ )
+ template = "%(function)s(SDOAGGRTYPE(%(expressions)s))"
+ return clone.as_sql(
+ compiler, connection, template=template, **extra_context
+ )
return self.as_sql(compiler, connection, **extra_context)
- def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
+ def resolve_expression(
+ self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False
+ ):
c = super().resolve_expression(query, allow_joins, reuse, summarize, for_save)
for expr in c.get_source_expressions():
- if not hasattr(expr.field, 'geom_type'):
- raise ValueError('Geospatial aggregates only allowed on geometry fields.')
+ if not hasattr(expr.field, "geom_type"):
+ raise ValueError(
+ "Geospatial aggregates only allowed on geometry fields."
+ )
return c
class Collect(GeoAggregate):
- name = 'Collect'
+ name = "Collect"
output_field_class = GeometryCollectionField
class Extent(GeoAggregate):
- name = 'Extent'
- is_extent = '2D'
+ name = "Extent"
+ is_extent = "2D"
def __init__(self, expression, **extra):
super().__init__(expression, output_field=ExtentField(), **extra)
@@ -63,8 +74,8 @@ class Extent(GeoAggregate):
class Extent3D(GeoAggregate):
- name = 'Extent3D'
- is_extent = '3D'
+ name = "Extent3D"
+ is_extent = "3D"
def __init__(self, expression, **extra):
super().__init__(expression, output_field=ExtentField(), **extra)
@@ -74,10 +85,10 @@ class Extent3D(GeoAggregate):
class MakeLine(GeoAggregate):
- name = 'MakeLine'
+ name = "MakeLine"
output_field_class = LineStringField
class Union(GeoAggregate):
- name = 'Union'
+ name = "Union"
output_field_class = GeometryField
diff --git a/django/contrib/gis/db/models/fields.py b/django/contrib/gis/db/models/fields.py
index 16b3bb5d08..889c1cfe84 100644
--- a/django/contrib/gis/db/models/fields.py
+++ b/django/contrib/gis/db/models/fields.py
@@ -4,8 +4,15 @@ from django.contrib.gis import forms, gdal
from django.contrib.gis.db.models.proxy import SpatialProxy
from django.contrib.gis.gdal.error import GDALException
from django.contrib.gis.geos import (
- GeometryCollection, GEOSException, GEOSGeometry, LineString,
- MultiLineString, MultiPoint, MultiPolygon, Point, Polygon,
+ GeometryCollection,
+ GEOSException,
+ GEOSGeometry,
+ LineString,
+ MultiLineString,
+ MultiPoint,
+ MultiPolygon,
+ Point,
+ Polygon,
)
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Field
@@ -17,7 +24,9 @@ from django.utils.translation import gettext_lazy as _
_srid_cache = defaultdict(dict)
-SRIDCacheEntry = namedtuple('SRIDCacheEntry', ['units', 'units_name', 'spheroid', 'geodetic'])
+SRIDCacheEntry = namedtuple(
+ "SRIDCacheEntry", ["units", "units_name", "spheroid", "geodetic"]
+)
def get_srid_info(srid, connection):
@@ -27,6 +36,7 @@ def get_srid_info(srid, connection):
table for the given database connection. These results are cached.
"""
from django.contrib.gis.gdal import SpatialReference
+
global _srid_cache
try:
@@ -36,9 +46,14 @@ def get_srid_info(srid, connection):
SpatialRefSys = None
alias, get_srs = (
- (connection.alias, lambda srid: SpatialRefSys.objects.using(connection.alias).get(srid=srid).srs)
- if SpatialRefSys else
- (None, SpatialReference)
+ (
+ connection.alias,
+ lambda srid: SpatialRefSys.objects.using(connection.alias)
+ .get(srid=srid)
+ .srs,
+ )
+ if SpatialRefSys
+ else (None, SpatialReference)
)
if srid not in _srid_cache[alias]:
srs = get_srs(srid)
@@ -46,7 +61,8 @@ def get_srid_info(srid, connection):
_srid_cache[alias][srid] = SRIDCacheEntry(
units=units,
units_name=units_name,
- spheroid='SPHEROID["%s",%s,%s]' % (srs['spheroid'], srs.semi_major, srs.inverse_flattening),
+ spheroid='SPHEROID["%s",%s,%s]'
+ % (srs["spheroid"], srs.semi_major, srs.inverse_flattening),
geodetic=srs.geographic,
)
@@ -61,6 +77,7 @@ class BaseSpatialField(Field):
properties that are common to all GIS fields such as the characteristics
of the spatial reference system of the field.
"""
+
description = _("The base GIS field.")
empty_strings_allowed = False
@@ -88,7 +105,7 @@ class BaseSpatialField(Field):
# Setting the verbose_name keyword argument with the positional
# first parameter, so this works like normal fields.
- kwargs['verbose_name'] = verbose_name
+ kwargs["verbose_name"] = verbose_name
super().__init__(**kwargs)
@@ -96,9 +113,9 @@ class BaseSpatialField(Field):
name, path, args, kwargs = super().deconstruct()
# Always include SRID for less fragility; include spatial index if it's
# not the default value.
- kwargs['srid'] = self.srid
+ kwargs["srid"] = self.srid
if self.spatial_index is not True:
- kwargs['spatial_index'] = self.spatial_index
+ kwargs["spatial_index"] = self.spatial_index
return name, path, args, kwargs
def db_type(self, connection):
@@ -146,10 +163,10 @@ class BaseSpatialField(Field):
return connection.ops.Adapter(
super().get_db_prep_value(value, connection, *args, **kwargs),
**(
- {'geography': True}
+ {"geography": True}
if self.geography and connection.features.supports_geography
else {}
- )
+ ),
)
def get_raster_prep_value(self, value, is_candidate):
@@ -167,7 +184,9 @@ class BaseSpatialField(Field):
try:
return gdal.GDALRaster(value)
except GDALException:
- raise ValueError("Couldn't create spatial object from lookup value '%s'." % value)
+ raise ValueError(
+ "Couldn't create spatial object from lookup value '%s'." % value
+ )
def get_prep_value(self, value):
obj = super().get_prep_value(value)
@@ -179,7 +198,9 @@ class BaseSpatialField(Field):
pass
else:
# Check if input is a candidate for conversion to raster or geometry.
- is_candidate = isinstance(obj, (bytes, str)) or hasattr(obj, '__geo_interface__')
+ is_candidate = isinstance(obj, (bytes, str)) or hasattr(
+ obj, "__geo_interface__"
+ )
# Try to convert the input to raster.
raster = self.get_raster_prep_value(obj, is_candidate)
@@ -189,9 +210,14 @@ class BaseSpatialField(Field):
try:
obj = GEOSGeometry(obj)
except (GEOSException, GDALException):
- raise ValueError("Couldn't create spatial object from lookup value '%s'." % obj)
+ raise ValueError(
+ "Couldn't create spatial object from lookup value '%s'." % obj
+ )
else:
- raise ValueError('Cannot use object with type %s for a spatial lookup parameter.' % type(obj).__name__)
+ raise ValueError(
+ "Cannot use object with type %s for a spatial lookup parameter."
+ % type(obj).__name__
+ )
# Assigning the SRID value.
obj.srid = self.get_srid(obj)
@@ -202,14 +228,25 @@ class GeometryField(BaseSpatialField):
"""
The base Geometry field -- maps to the OpenGIS Specification Geometry type.
"""
- description = _('The base Geometry field — maps to the OpenGIS Specification Geometry type.')
+
+ description = _(
+ "The base Geometry field — maps to the OpenGIS Specification Geometry type."
+ )
form_class = forms.GeometryField
# The OpenGIS Geometry name.
- geom_type = 'GEOMETRY'
+ geom_type = "GEOMETRY"
geom_class = None
- def __init__(self, verbose_name=None, dim=2, geography=False, *, extent=(-180.0, -90.0, 180.0, 90.0),
- tolerance=0.05, **kwargs):
+ def __init__(
+ self,
+ verbose_name=None,
+ dim=2,
+ geography=False,
+ *,
+ extent=(-180.0, -90.0, 180.0, 90.0),
+ tolerance=0.05,
+ **kwargs,
+ ):
"""
The initialization function for geometry fields. In addition to the
parameters from BaseSpatialField, it takes the following as keyword
@@ -244,30 +281,36 @@ class GeometryField(BaseSpatialField):
name, path, args, kwargs = super().deconstruct()
# Include kwargs if they're not the default values.
if self.dim != 2:
- kwargs['dim'] = self.dim
+ kwargs["dim"] = self.dim
if self.geography is not False:
- kwargs['geography'] = self.geography
+ kwargs["geography"] = self.geography
if self._extent != (-180.0, -90.0, 180.0, 90.0):
- kwargs['extent'] = self._extent
+ kwargs["extent"] = self._extent
if self._tolerance != 0.05:
- kwargs['tolerance'] = self._tolerance
+ kwargs["tolerance"] = self._tolerance
return name, path, args, kwargs
def contribute_to_class(self, cls, name, **kwargs):
super().contribute_to_class(cls, name, **kwargs)
# Setup for lazy-instantiated Geometry object.
- setattr(cls, self.attname, SpatialProxy(self.geom_class or GEOSGeometry, self, load_func=GEOSGeometry))
+ setattr(
+ cls,
+ self.attname,
+ SpatialProxy(self.geom_class or GEOSGeometry, self, load_func=GEOSGeometry),
+ )
def formfield(self, **kwargs):
defaults = {
- 'form_class': self.form_class,
- 'geom_type': self.geom_type,
- 'srid': self.srid,
+ "form_class": self.form_class,
+ "geom_type": self.geom_type,
+ "srid": self.srid,
**kwargs,
}
- if self.dim > 2 and not getattr(defaults['form_class'].widget, 'supports_3d', False):
- defaults.setdefault('widget', forms.Textarea)
+ if self.dim > 2 and not getattr(
+ defaults["form_class"].widget, "supports_3d", False
+ ):
+ defaults.setdefault("widget", forms.Textarea)
return super().formfield(**defaults)
def select_format(self, compiler, sql, params):
@@ -283,49 +326,49 @@ class GeometryField(BaseSpatialField):
# The OpenGIS Geometry Type Fields
class PointField(GeometryField):
- geom_type = 'POINT'
+ geom_type = "POINT"
geom_class = Point
form_class = forms.PointField
description = _("Point")
class LineStringField(GeometryField):
- geom_type = 'LINESTRING'
+ geom_type = "LINESTRING"
geom_class = LineString
form_class = forms.LineStringField
description = _("Line string")
class PolygonField(GeometryField):
- geom_type = 'POLYGON'
+ geom_type = "POLYGON"
geom_class = Polygon
form_class = forms.PolygonField
description = _("Polygon")
class MultiPointField(GeometryField):
- geom_type = 'MULTIPOINT'
+ geom_type = "MULTIPOINT"
geom_class = MultiPoint
form_class = forms.MultiPointField
description = _("Multi-point")
class MultiLineStringField(GeometryField):
- geom_type = 'MULTILINESTRING'
+ geom_type = "MULTILINESTRING"
geom_class = MultiLineString
form_class = forms.MultiLineStringField
description = _("Multi-line string")
class MultiPolygonField(GeometryField):
- geom_type = 'MULTIPOLYGON'
+ geom_type = "MULTIPOLYGON"
geom_class = MultiPolygon
form_class = forms.MultiPolygonField
description = _("Multi polygon")
class GeometryCollectionField(GeometryField):
- geom_type = 'GEOMETRYCOLLECTION'
+ geom_type = "GEOMETRYCOLLECTION"
geom_class = GeometryCollection
form_class = forms.GeometryCollectionField
description = _("Geometry collection")
@@ -350,13 +393,18 @@ class RasterField(BaseSpatialField):
"""
description = _("Raster Field")
- geom_type = 'RASTER'
+ geom_type = "RASTER"
geography = False
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:
- raise ImproperlyConfigured('Raster fields require backends with raster support.')
+ if (
+ not connection.features.gis_enabled
+ or not connection.features.supports_raster
+ ):
+ raise ImproperlyConfigured(
+ "Raster fields require backends with raster support."
+ )
def db_type(self, connection):
self._check_connection(connection)
@@ -375,12 +423,13 @@ class RasterField(BaseSpatialField):
def get_transform(self, name):
from django.contrib.gis.db.models.lookups import RasterBandTransform
+
try:
band_index = int(name)
return type(
- 'SpecificRasterBandTransform',
+ "SpecificRasterBandTransform",
(RasterBandTransform,),
- {'band_index': band_index}
+ {"band_index": band_index},
)
except ValueError:
pass
diff --git a/django/contrib/gis/db/models/functions.py b/django/contrib/gis/db/models/functions.py
index 1f2d372ebb..c7b071c7c9 100644
--- a/django/contrib/gis/db/models/functions.py
+++ b/django/contrib/gis/db/models/functions.py
@@ -6,8 +6,14 @@ from django.contrib.gis.geos import GEOSGeometry
from django.core.exceptions import FieldError
from django.db import NotSupportedError
from django.db.models import (
- BinaryField, BooleanField, FloatField, Func, IntegerField, TextField,
- Transform, Value,
+ BinaryField,
+ BooleanField,
+ FloatField,
+ Func,
+ IntegerField,
+ TextField,
+ Transform,
+ Value,
)
from django.db.models.functions import Cast
from django.utils.functional import cached_property
@@ -32,12 +38,21 @@ class GeoFuncMixin:
except FieldError:
output_field = None
geom = expr.value
- if not isinstance(geom, GEOSGeometry) or output_field and not isinstance(output_field, GeometryField):
- raise TypeError("%s function requires a geometric argument in position %d." % (self.name, pos + 1))
+ if (
+ not isinstance(geom, GEOSGeometry)
+ or output_field
+ and not isinstance(output_field, GeometryField)
+ ):
+ raise TypeError(
+ "%s function requires a geometric argument in position %d."
+ % (self.name, pos + 1)
+ )
if not geom.srid and not output_field:
raise ValueError("SRID is required for all geometries.")
if not output_field:
- self.source_expressions[pos] = Value(geom, output_field=GeometryField(srid=geom.srid))
+ self.source_expressions[pos] = Value(
+ geom, output_field=GeometryField(srid=geom.srid)
+ )
@property
def name(self):
@@ -61,8 +76,11 @@ class GeoFuncMixin:
field = source_fields[pos]
if not isinstance(field, GeometryField):
raise TypeError(
- "%s function requires a GeometryField in position %s, got %s." % (
- self.name, pos + 1, type(field).__name__,
+ "%s function requires a GeometryField in position %s, got %s."
+ % (
+ self.name,
+ pos + 1,
+ type(field).__name__,
)
)
@@ -72,15 +90,17 @@ class GeoFuncMixin:
expr_srid = expr.output_field.srid
if expr_srid != base_srid:
# Automatic SRID conversion so objects are comparable.
- res.source_expressions[pos] = Transform(expr, base_srid).resolve_expression(*args, **kwargs)
+ res.source_expressions[pos] = Transform(
+ expr, base_srid
+ ).resolve_expression(*args, **kwargs)
return res
- def _handle_param(self, value, param_name='', check_types=None):
- if not hasattr(value, 'resolve_expression'):
+ def _handle_param(self, value, param_name="", check_types=None):
+ if not hasattr(value, "resolve_expression"):
if check_types and not isinstance(value, check_types):
raise TypeError(
- "The %s parameter has the wrong type: should be %s." % (
- param_name, check_types)
+ "The %s parameter has the wrong type: should be %s."
+ % (param_name, check_types)
)
return value
@@ -100,13 +120,17 @@ class SQLiteDecimalToFloatMixin:
By default, Decimal values are converted to str by the SQLite backend, which
is not acceptable by the GIS functions expecting numeric values.
"""
+
def as_sqlite(self, compiler, connection, **extra_context):
copy = self.copy()
- copy.set_source_expressions([
- Value(float(expr.value)) if hasattr(expr, 'value') and isinstance(expr.value, Decimal)
- else expr
- for expr in copy.get_source_expressions()
- ])
+ copy.set_source_expressions(
+ [
+ Value(float(expr.value))
+ if hasattr(expr, "value") and isinstance(expr.value, Decimal)
+ else expr
+ for expr in copy.get_source_expressions()
+ ]
+ )
return copy.as_sql(compiler, connection, **extra_context)
@@ -114,11 +138,13 @@ class OracleToleranceMixin:
tolerance = 0.05
def as_oracle(self, compiler, connection, **extra_context):
- tolerance = Value(self._handle_param(
- self.extra.get('tolerance', self.tolerance),
- 'tolerance',
- NUMERIC_TYPES,
- ))
+ tolerance = Value(
+ self._handle_param(
+ self.extra.get("tolerance", self.tolerance),
+ "tolerance",
+ NUMERIC_TYPES,
+ )
+ )
clone = self.copy()
clone.set_source_expressions([*self.get_source_expressions(), tolerance])
return clone.as_sql(compiler, connection, **extra_context)
@@ -132,14 +158,18 @@ class Area(OracleToleranceMixin, GeoFunc):
return AreaField(self.geo_field)
def as_sql(self, compiler, connection, **extra_context):
- if not connection.features.supports_area_geodetic and self.geo_field.geodetic(connection):
- raise NotSupportedError('Area on geodetic coordinate systems not supported.')
+ if not connection.features.supports_area_geodetic and self.geo_field.geodetic(
+ connection
+ ):
+ raise NotSupportedError(
+ "Area on geodetic coordinate systems not supported."
+ )
return super().as_sql(compiler, connection, **extra_context)
def as_sqlite(self, compiler, connection, **extra_context):
if self.geo_field.geodetic(connection):
- extra_context['template'] = '%(function)s(%(expressions)s, %(spheroid)d)'
- extra_context['spheroid'] = True
+ extra_context["template"] = "%(function)s(%(expressions)s, %(spheroid)d)"
+ extra_context["spheroid"] = True
return self.as_sql(compiler, connection, **extra_context)
@@ -155,7 +185,7 @@ class AsGeoJSON(GeoFunc):
def __init__(self, expression, bbox=False, crs=False, precision=8, **extra):
expressions = [expression]
if precision is not None:
- expressions.append(self._handle_param(precision, 'precision', int))
+ expressions.append(self._handle_param(precision, "precision", int))
options = 0
if crs and bbox:
options = 3
@@ -181,7 +211,7 @@ class AsGML(GeoFunc):
def __init__(self, expression, version=2, precision=8, **extra):
expressions = [version, expression]
if precision is not None:
- expressions.append(self._handle_param(precision, 'precision', int))
+ expressions.append(self._handle_param(precision, "precision", int))
super().__init__(*expressions, **extra)
def as_oracle(self, compiler, connection, **extra_context):
@@ -189,7 +219,11 @@ class AsGML(GeoFunc):
version = source_expressions[0]
clone = self.copy()
clone.set_source_expressions([source_expressions[1]])
- extra_context['function'] = 'SDO_UTIL.TO_GML311GEOMETRY' if version.value == 3 else 'SDO_UTIL.TO_GMLGEOMETRY'
+ extra_context["function"] = (
+ "SDO_UTIL.TO_GML311GEOMETRY"
+ if version.value == 3
+ else "SDO_UTIL.TO_GMLGEOMETRY"
+ )
return super(AsGML, clone).as_sql(compiler, connection, **extra_context)
@@ -199,7 +233,7 @@ class AsKML(GeoFunc):
def __init__(self, expression, precision=8, **extra):
expressions = [expression]
if precision is not None:
- expressions.append(self._handle_param(precision, 'precision', int))
+ expressions.append(self._handle_param(precision, "precision", int))
super().__init__(*expressions, **extra)
@@ -207,11 +241,13 @@ class AsSVG(GeoFunc):
output_field = TextField()
def __init__(self, expression, relative=False, precision=8, **extra):
- relative = relative if hasattr(relative, 'resolve_expression') else int(relative)
+ relative = (
+ relative if hasattr(relative, "resolve_expression") else int(relative)
+ )
expressions = [
expression,
relative,
- self._handle_param(precision, 'precision', int),
+ self._handle_param(precision, "precision", int),
]
super().__init__(*expressions, **extra)
@@ -233,7 +269,9 @@ class BoundingCircle(OracleToleranceMixin, GeomOutputGeoFunc):
def as_oracle(self, compiler, connection, **extra_context):
clone = self.copy()
clone.set_source_expressions([self.get_source_expressions()[0]])
- return super(BoundingCircle, clone).as_oracle(compiler, connection, **extra_context)
+ return super(BoundingCircle, clone).as_oracle(
+ compiler, connection, **extra_context
+ )
class Centroid(OracleToleranceMixin, GeomOutputGeoFunc):
@@ -261,7 +299,7 @@ class Distance(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
def __init__(self, expr1, expr2, spheroid=None, **extra):
expressions = [expr1, expr2]
if spheroid is not None:
- self.spheroid = self._handle_param(spheroid, 'spheroid', bool)
+ self.spheroid = self._handle_param(spheroid, "spheroid", bool)
super().__init__(*expressions, **extra)
def as_postgresql(self, compiler, connection, **extra_context):
@@ -282,18 +320,24 @@ class Distance(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
# Geometry fields with geodetic (lon/lat) coordinates need special distance functions
if self.spheroid:
# DistanceSpheroid is more accurate and resource intensive than DistanceSphere
- function = connection.ops.spatial_function_name('DistanceSpheroid')
+ function = connection.ops.spatial_function_name("DistanceSpheroid")
# Replace boolean param by the real spheroid of the base field
- clone.source_expressions.append(Value(self.geo_field.spheroid(connection)))
+ clone.source_expressions.append(
+ Value(self.geo_field.spheroid(connection))
+ )
else:
- function = connection.ops.spatial_function_name('DistanceSphere')
- return super(Distance, clone).as_sql(compiler, connection, function=function, **extra_context)
+ function = connection.ops.spatial_function_name("DistanceSphere")
+ return super(Distance, clone).as_sql(
+ compiler, connection, function=function, **extra_context
+ )
def as_sqlite(self, compiler, connection, **extra_context):
if self.geo_field.geodetic(connection):
# SpatiaLite returns NULL instead of zero on geodetic coordinates
- extra_context['template'] = 'COALESCE(%(function)s(%(expressions)s, %(spheroid)s), 0)'
- extra_context['spheroid'] = int(bool(self.spheroid))
+ extra_context[
+ "template"
+ ] = "COALESCE(%(function)s(%(expressions)s, %(spheroid)s), 0)"
+ extra_context["spheroid"] = int(bool(self.spheroid))
return super().as_sql(compiler, connection, **extra_context)
@@ -311,7 +355,7 @@ class GeoHash(GeoFunc):
def __init__(self, expression, precision=None, **extra):
expressions = [expression]
if precision is not None:
- expressions.append(self._handle_param(precision, 'precision', int))
+ expressions.append(self._handle_param(precision, "precision", int))
super().__init__(*expressions, **extra)
def as_mysql(self, compiler, connection, **extra_context):
@@ -325,8 +369,8 @@ class GeoHash(GeoFunc):
class GeometryDistance(GeoFunc):
output_field = FloatField()
arity = 2
- function = ''
- arg_joiner = ' <-> '
+ function = ""
+ arg_joiner = " <-> "
geom_param_pos = (0, 1)
@@ -337,7 +381,7 @@ class Intersection(OracleToleranceMixin, GeomOutputGeoFunc):
@BaseSpatialField.register_lookup
class IsValid(OracleToleranceMixin, GeoFuncMixin, Transform):
- lookup_name = 'isvalid'
+ lookup_name = "isvalid"
output_field = BooleanField()
def as_oracle(self, compiler, connection, **extra_context):
@@ -351,8 +395,13 @@ class Length(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
super().__init__(expr1, **extra)
def as_sql(self, compiler, connection, **extra_context):
- if self.geo_field.geodetic(connection) and not connection.features.supports_length_geodetic:
- raise NotSupportedError("This backend doesn't support Length on geodetic fields")
+ if (
+ self.geo_field.geodetic(connection)
+ and not connection.features.supports_length_geodetic
+ ):
+ raise NotSupportedError(
+ "This backend doesn't support Length on geodetic fields"
+ )
return super().as_sql(compiler, connection, **extra_context)
def as_postgresql(self, compiler, connection, **extra_context):
@@ -362,18 +411,20 @@ class Length(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
clone.source_expressions.append(Value(self.spheroid))
elif self.geo_field.geodetic(connection):
# Geometry fields with geodetic (lon/lat) coordinates need length_spheroid
- function = connection.ops.spatial_function_name('LengthSpheroid')
+ function = connection.ops.spatial_function_name("LengthSpheroid")
clone.source_expressions.append(Value(self.geo_field.spheroid(connection)))
else:
dim = min(f.dim for f in self.get_source_fields() if f)
if dim > 2:
function = connection.ops.length3d
- return super(Length, clone).as_sql(compiler, connection, function=function, **extra_context)
+ return super(Length, clone).as_sql(
+ compiler, connection, function=function, **extra_context
+ )
def as_sqlite(self, compiler, connection, **extra_context):
function = None
if self.geo_field.geodetic(connection):
- function = 'GeodesicLength' if self.spheroid else 'GreatCircleLength'
+ function = "GeodesicLength" if self.spheroid else "GreatCircleLength"
return super().as_sql(compiler, connection, function=function, **extra_context)
@@ -408,7 +459,9 @@ class Perimeter(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
def as_postgresql(self, compiler, connection, **extra_context):
function = None
if self.geo_field.geodetic(connection) and not self.source_is_geography():
- raise NotSupportedError("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())
if dim > 2:
function = connection.ops.perimeter3d
@@ -432,11 +485,11 @@ class Scale(SQLiteDecimalToFloatMixin, GeomOutputGeoFunc):
def __init__(self, expression, x, y, z=0.0, **extra):
expressions = [
expression,
- self._handle_param(x, 'x', NUMERIC_TYPES),
- self._handle_param(y, 'y', NUMERIC_TYPES),
+ self._handle_param(x, "x", NUMERIC_TYPES),
+ self._handle_param(y, "y", NUMERIC_TYPES),
]
if z != 0.0:
- expressions.append(self._handle_param(z, 'z', NUMERIC_TYPES))
+ expressions.append(self._handle_param(z, "z", NUMERIC_TYPES))
super().__init__(*expressions, **extra)
@@ -446,16 +499,16 @@ class SnapToGrid(SQLiteDecimalToFloatMixin, GeomOutputGeoFunc):
expressions = [expression]
if nargs in (1, 2):
expressions.extend(
- [self._handle_param(arg, '', NUMERIC_TYPES) for arg in args]
+ [self._handle_param(arg, "", NUMERIC_TYPES) for arg in args]
)
elif nargs == 4:
# Reverse origin and size param ordering
expressions += [
- *(self._handle_param(arg, '', NUMERIC_TYPES) for arg in args[2:]),
- *(self._handle_param(arg, '', NUMERIC_TYPES) for arg in args[0:2]),
+ *(self._handle_param(arg, "", NUMERIC_TYPES) for arg in args[2:]),
+ *(self._handle_param(arg, "", NUMERIC_TYPES) for arg in args[0:2]),
]
else:
- raise ValueError('Must provide 1, 2, or 4 arguments to `SnapToGrid`.')
+ raise ValueError("Must provide 1, 2, or 4 arguments to `SnapToGrid`.")
super().__init__(*expressions, **extra)
@@ -468,10 +521,10 @@ class Transform(GeomOutputGeoFunc):
def __init__(self, expression, srid, **extra):
expressions = [
expression,
- self._handle_param(srid, 'srid', int),
+ self._handle_param(srid, "srid", int),
]
- if 'output_field' not in extra:
- extra['output_field'] = GeometryField(srid=srid)
+ if "output_field" not in extra:
+ extra["output_field"] = GeometryField(srid=srid)
super().__init__(*expressions, **extra)
diff --git a/django/contrib/gis/db/models/lookups.py b/django/contrib/gis/db/models/lookups.py
index c1d021b28e..9c06922508 100644
--- a/django/contrib/gis/db/models/lookups.py
+++ b/django/contrib/gis/db/models/lookups.py
@@ -27,10 +27,10 @@ class GISLookup(Lookup):
def process_rhs_params(self):
if self.rhs_params:
# Check if a band index was passed in the query argument.
- if len(self.rhs_params) == (2 if self.lookup_name == 'relate' else 1):
+ if len(self.rhs_params) == (2 if self.lookup_name == "relate" else 1):
self.process_band_indices()
elif len(self.rhs_params) > 1:
- raise ValueError('Tuple too long for lookup %s.' % self.lookup_name)
+ raise ValueError("Tuple too long for lookup %s." % self.lookup_name)
elif isinstance(self.lhs, RasterBandTransform):
self.process_band_indices(only_lhs=True)
@@ -55,7 +55,7 @@ class GISLookup(Lookup):
def get_db_prep_lookup(self, value, connection):
# get_db_prep_lookup is called by process_rhs from super class
- return ('%s', [connection.ops.Adapter(value)])
+ return ("%s", [connection.ops.Adapter(value)])
def process_rhs(self, compiler, connection):
if isinstance(self.rhs, Query):
@@ -64,7 +64,9 @@ class GISLookup(Lookup):
if isinstance(self.rhs, Expression):
self.rhs = self.rhs.resolve_expression(compiler.query)
rhs, rhs_params = super().process_rhs(compiler, connection)
- placeholder = connection.ops.get_geom_placeholder(self.lhs.output_field, self.rhs, compiler)
+ placeholder = connection.ops.get_geom_placeholder(
+ self.lhs.output_field, self.rhs, compiler
+ )
return placeholder % rhs, rhs_params
def get_rhs_op(self, connection, rhs):
@@ -78,7 +80,12 @@ class GISLookup(Lookup):
rhs_sql, rhs_params = self.process_rhs(compiler, connection)
sql_params = (*lhs_params, *rhs_params)
- template_params = {'lhs': lhs_sql, 'rhs': rhs_sql, 'value': '%s', **self.template_params}
+ template_params = {
+ "lhs": lhs_sql,
+ "rhs": rhs_sql,
+ "value": "%s",
+ **self.template_params,
+ }
rhs_op = self.get_rhs_op(connection, rhs_sql)
return rhs_op.as_sql(connection, self, template_params, sql_params)
@@ -87,13 +94,15 @@ class GISLookup(Lookup):
# Geometry operators
# ------------------
+
@BaseSpatialField.register_lookup
class OverlapsLeftLookup(GISLookup):
"""
The overlaps_left operator returns true if A's bounding box overlaps or is to the
left of B's bounding box.
"""
- lookup_name = 'overlaps_left'
+
+ lookup_name = "overlaps_left"
@BaseSpatialField.register_lookup
@@ -102,7 +111,8 @@ class OverlapsRightLookup(GISLookup):
The 'overlaps_right' operator returns true if A's bounding box overlaps or is to the
right of B's bounding box.
"""
- lookup_name = 'overlaps_right'
+
+ lookup_name = "overlaps_right"
@BaseSpatialField.register_lookup
@@ -111,7 +121,8 @@ class OverlapsBelowLookup(GISLookup):
The 'overlaps_below' operator returns true if A's bounding box overlaps or is below
B's bounding box.
"""
- lookup_name = 'overlaps_below'
+
+ lookup_name = "overlaps_below"
@BaseSpatialField.register_lookup
@@ -120,7 +131,8 @@ class OverlapsAboveLookup(GISLookup):
The 'overlaps_above' operator returns true if A's bounding box overlaps or is above
B's bounding box.
"""
- lookup_name = 'overlaps_above'
+
+ lookup_name = "overlaps_above"
@BaseSpatialField.register_lookup
@@ -129,7 +141,8 @@ class LeftLookup(GISLookup):
The 'left' operator returns true if A's bounding box is strictly to the left
of B's bounding box.
"""
- lookup_name = 'left'
+
+ lookup_name = "left"
@BaseSpatialField.register_lookup
@@ -138,7 +151,8 @@ class RightLookup(GISLookup):
The 'right' operator returns true if A's bounding box is strictly to the right
of B's bounding box.
"""
- lookup_name = 'right'
+
+ lookup_name = "right"
@BaseSpatialField.register_lookup
@@ -147,7 +161,8 @@ class StrictlyBelowLookup(GISLookup):
The 'strictly_below' operator returns true if A's bounding box is strictly below B's
bounding box.
"""
- lookup_name = 'strictly_below'
+
+ lookup_name = "strictly_below"
@BaseSpatialField.register_lookup
@@ -156,7 +171,8 @@ class StrictlyAboveLookup(GISLookup):
The 'strictly_above' operator returns true if A's bounding box is strictly above B's
bounding box.
"""
- lookup_name = 'strictly_above'
+
+ lookup_name = "strictly_above"
@BaseSpatialField.register_lookup
@@ -166,10 +182,11 @@ class SameAsLookup(GISLookup):
equality of two features. So if A and B are the same feature,
vertex-by-vertex, the operator returns true.
"""
- lookup_name = 'same_as'
+ lookup_name = "same_as"
-BaseSpatialField.register_lookup(SameAsLookup, 'exact')
+
+BaseSpatialField.register_lookup(SameAsLookup, "exact")
@BaseSpatialField.register_lookup
@@ -178,7 +195,8 @@ class BBContainsLookup(GISLookup):
The 'bbcontains' operator returns true if A's bounding box completely contains
by B's bounding box.
"""
- lookup_name = 'bbcontains'
+
+ lookup_name = "bbcontains"
@BaseSpatialField.register_lookup
@@ -186,7 +204,8 @@ class BBOverlapsLookup(GISLookup):
"""
The 'bboverlaps' operator returns true if A's bounding box overlaps B's bounding box.
"""
- lookup_name = 'bboverlaps'
+
+ lookup_name = "bboverlaps"
@BaseSpatialField.register_lookup
@@ -195,69 +214,71 @@ class ContainedLookup(GISLookup):
The 'contained' operator returns true if A's bounding box is completely contained
by B's bounding box.
"""
- lookup_name = 'contained'
+
+ lookup_name = "contained"
# ------------------
# Geometry functions
# ------------------
+
@BaseSpatialField.register_lookup
class ContainsLookup(GISLookup):
- lookup_name = 'contains'
+ lookup_name = "contains"
@BaseSpatialField.register_lookup
class ContainsProperlyLookup(GISLookup):
- lookup_name = 'contains_properly'
+ lookup_name = "contains_properly"
@BaseSpatialField.register_lookup
class CoveredByLookup(GISLookup):
- lookup_name = 'coveredby'
+ lookup_name = "coveredby"
@BaseSpatialField.register_lookup
class CoversLookup(GISLookup):
- lookup_name = 'covers'
+ lookup_name = "covers"
@BaseSpatialField.register_lookup
class CrossesLookup(GISLookup):
- lookup_name = 'crosses'
+ lookup_name = "crosses"
@BaseSpatialField.register_lookup
class DisjointLookup(GISLookup):
- lookup_name = 'disjoint'
+ lookup_name = "disjoint"
@BaseSpatialField.register_lookup
class EqualsLookup(GISLookup):
- lookup_name = 'equals'
+ lookup_name = "equals"
@BaseSpatialField.register_lookup
class IntersectsLookup(GISLookup):
- lookup_name = 'intersects'
+ lookup_name = "intersects"
@BaseSpatialField.register_lookup
class OverlapsLookup(GISLookup):
- lookup_name = 'overlaps'
+ lookup_name = "overlaps"
@BaseSpatialField.register_lookup
class RelateLookup(GISLookup):
- lookup_name = 'relate'
- sql_template = '%(func)s(%(lhs)s, %(rhs)s, %%s)'
- pattern_regex = _lazy_re_compile(r'^[012TF\*]{9}$')
+ lookup_name = "relate"
+ sql_template = "%(func)s(%(lhs)s, %(rhs)s, %%s)"
+ pattern_regex = _lazy_re_compile(r"^[012TF\*]{9}$")
def process_rhs(self, compiler, connection):
# Check the pattern argument
pattern = self.rhs_params[0]
backend_op = connection.ops.gis_operators[self.lookup_name]
- if hasattr(backend_op, 'check_relate_argument'):
+ if hasattr(backend_op, "check_relate_argument"):
backend_op.check_relate_argument(pattern)
elif not isinstance(pattern, str) or not self.pattern_regex.match(pattern):
raise ValueError('Invalid intersection matrix pattern "%s".' % pattern)
@@ -267,93 +288,106 @@ class RelateLookup(GISLookup):
@BaseSpatialField.register_lookup
class TouchesLookup(GISLookup):
- lookup_name = 'touches'
+ lookup_name = "touches"
@BaseSpatialField.register_lookup
class WithinLookup(GISLookup):
- lookup_name = 'within'
+ lookup_name = "within"
class DistanceLookupBase(GISLookup):
distance = True
- sql_template = '%(func)s(%(lhs)s, %(rhs)s) %(op)s %(value)s'
+ sql_template = "%(func)s(%(lhs)s, %(rhs)s) %(op)s %(value)s"
def process_rhs_params(self):
if not 1 <= len(self.rhs_params) <= 3:
- raise ValueError("2, 3, or 4-element tuple required for '%s' lookup." % self.lookup_name)
- elif len(self.rhs_params) == 3 and self.rhs_params[2] != 'spheroid':
- raise ValueError("For 4-element tuples the last argument must be the 'spheroid' directive.")
+ raise ValueError(
+ "2, 3, or 4-element tuple required for '%s' lookup." % self.lookup_name
+ )
+ elif len(self.rhs_params) == 3 and self.rhs_params[2] != "spheroid":
+ raise ValueError(
+ "For 4-element tuples the last argument must be the 'spheroid' directive."
+ )
# Check if the second parameter is a band index.
- if len(self.rhs_params) > 1 and self.rhs_params[1] != 'spheroid':
+ if len(self.rhs_params) > 1 and self.rhs_params[1] != "spheroid":
self.process_band_indices()
def process_distance(self, compiler, connection):
dist_param = self.rhs_params[0]
return (
compiler.compile(dist_param.resolve_expression(compiler.query))
- if hasattr(dist_param, 'resolve_expression') else
- ('%s', connection.ops.get_distance(self.lhs.output_field, self.rhs_params, self.lookup_name))
+ if hasattr(dist_param, "resolve_expression")
+ else (
+ "%s",
+ connection.ops.get_distance(
+ self.lhs.output_field, self.rhs_params, self.lookup_name
+ ),
+ )
)
@BaseSpatialField.register_lookup
class DWithinLookup(DistanceLookupBase):
- lookup_name = 'dwithin'
- sql_template = '%(func)s(%(lhs)s, %(rhs)s, %(value)s)'
+ lookup_name = "dwithin"
+ sql_template = "%(func)s(%(lhs)s, %(rhs)s, %(value)s)"
def process_distance(self, compiler, connection):
dist_param = self.rhs_params[0]
if (
- not connection.features.supports_dwithin_distance_expr and
- hasattr(dist_param, 'resolve_expression') and
- not isinstance(dist_param, Distance)
+ not connection.features.supports_dwithin_distance_expr
+ and hasattr(dist_param, "resolve_expression")
+ and not isinstance(dist_param, Distance)
):
raise NotSupportedError(
- 'This backend does not support expressions for specifying '
- 'distance in the dwithin lookup.'
+ "This backend does not support expressions for specifying "
+ "distance in the dwithin lookup."
)
return super().process_distance(compiler, connection)
def process_rhs(self, compiler, connection):
dist_sql, dist_params = self.process_distance(compiler, connection)
- self.template_params['value'] = dist_sql
+ self.template_params["value"] = dist_sql
rhs_sql, params = super().process_rhs(compiler, connection)
return rhs_sql, params + dist_params
class DistanceLookupFromFunction(DistanceLookupBase):
def as_sql(self, compiler, connection):
- spheroid = (len(self.rhs_params) == 2 and self.rhs_params[-1] == 'spheroid') or None
- distance_expr = connection.ops.distance_expr_for_lookup(self.lhs, self.rhs, spheroid=spheroid)
+ spheroid = (
+ len(self.rhs_params) == 2 and self.rhs_params[-1] == "spheroid"
+ ) or None
+ distance_expr = connection.ops.distance_expr_for_lookup(
+ self.lhs, self.rhs, spheroid=spheroid
+ )
sql, params = compiler.compile(distance_expr.resolve_expression(compiler.query))
dist_sql, dist_params = self.process_distance(compiler, connection)
return (
- '%(func)s %(op)s %(dist)s' % {'func': sql, 'op': self.op, 'dist': dist_sql},
+ "%(func)s %(op)s %(dist)s" % {"func": sql, "op": self.op, "dist": dist_sql},
params + dist_params,
)
@BaseSpatialField.register_lookup
class DistanceGTLookup(DistanceLookupFromFunction):
- lookup_name = 'distance_gt'
- op = '>'
+ lookup_name = "distance_gt"
+ op = ">"
@BaseSpatialField.register_lookup
class DistanceGTELookup(DistanceLookupFromFunction):
- lookup_name = 'distance_gte'
- op = '>='
+ lookup_name = "distance_gte"
+ op = ">="
@BaseSpatialField.register_lookup
class DistanceLTLookup(DistanceLookupFromFunction):
- lookup_name = 'distance_lt'
- op = '<'
+ lookup_name = "distance_lt"
+ op = "<"
@BaseSpatialField.register_lookup
class DistanceLTELookup(DistanceLookupFromFunction):
- lookup_name = 'distance_lte'
- op = '<='
+ lookup_name = "distance_lte"
+ op = "<="
diff --git a/django/contrib/gis/db/models/proxy.py b/django/contrib/gis/db/models/proxy.py
index 07b26e9910..4db365dc16 100644
--- a/django/contrib/gis/db/models/proxy.py
+++ b/django/contrib/gis/db/models/proxy.py
@@ -37,7 +37,7 @@ class SpatialProxy(DeferredAttribute):
if isinstance(geo_value, self._klass):
geo_obj = geo_value
- elif (geo_value is None) or (geo_value == ''):
+ elif (geo_value is None) or (geo_value == ""):
geo_obj = None
else:
# Otherwise, a geometry or raster object is built using the field's
@@ -57,7 +57,9 @@ class SpatialProxy(DeferredAttribute):
# The geographic type of the field.
gtype = self.field.geom_type
- if gtype == 'RASTER' and (value is None or isinstance(value, (str, dict, self._klass))):
+ if gtype == "RASTER" and (
+ value is None or isinstance(value, (str, dict, self._klass))
+ ):
# For raster fields, ensure input is None or a string, dict, or
# raster instance.
pass
@@ -71,8 +73,10 @@ class SpatialProxy(DeferredAttribute):
# Set geometries with None, WKT, HEX, or WKB
pass
else:
- raise TypeError('Cannot set %s SpatialProxy (%s) with value of type: %s' % (
- instance.__class__.__name__, gtype, type(value)))
+ raise TypeError(
+ "Cannot set %s SpatialProxy (%s) with value of type: %s"
+ % (instance.__class__.__name__, gtype, type(value))
+ )
# Setting the objects dictionary with the value, and returning.
instance.__dict__[self.field.attname] = value
diff --git a/django/contrib/gis/db/models/sql/__init__.py b/django/contrib/gis/db/models/sql/__init__.py
index 850c644d5d..1376e8d7d1 100644
--- a/django/contrib/gis/db/models/sql/__init__.py
+++ b/django/contrib/gis/db/models/sql/__init__.py
@@ -1,7 +1,6 @@
-from django.contrib.gis.db.models.sql.conversion import (
- AreaField, DistanceField,
-)
+from django.contrib.gis.db.models.sql.conversion import AreaField, DistanceField
__all__ = [
- 'AreaField', 'DistanceField',
+ "AreaField",
+ "DistanceField",
]
diff --git a/django/contrib/gis/db/models/sql/conversion.py b/django/contrib/gis/db/models/sql/conversion.py
index 99ab51e239..be712319fb 100644
--- a/django/contrib/gis/db/models/sql/conversion.py
+++ b/django/contrib/gis/db/models/sql/conversion.py
@@ -10,13 +10,14 @@ from django.db import models
class AreaField(models.FloatField):
"Wrapper for Area values."
+
def __init__(self, geo_field):
super().__init__()
self.geo_field = geo_field
def get_prep_value(self, value):
if not isinstance(value, Area):
- raise ValueError('AreaField only accepts Area measurement objects.')
+ raise ValueError("AreaField only accepts Area measurement objects.")
return value
def get_db_prep_value(self, value, connection, prepared=False):
@@ -37,11 +38,12 @@ class AreaField(models.FloatField):
return Area(**{area_att: value}) if area_att else value
def get_internal_type(self):
- return 'AreaField'
+ return "AreaField"
class DistanceField(models.FloatField):
"Wrapper for Distance values."
+
def __init__(self, geo_field):
super().__init__()
self.geo_field = geo_field
@@ -56,7 +58,9 @@ class DistanceField(models.FloatField):
return value
distance_att = connection.ops.get_distance_att_for_field(self.geo_field)
if not distance_att:
- raise ValueError('Distance measure is supplied, but units are unknown for result.')
+ raise ValueError(
+ "Distance measure is supplied, but units are unknown for result."
+ )
return getattr(value, distance_att)
def from_db_value(self, value, expression, connection):
@@ -66,4 +70,4 @@ class DistanceField(models.FloatField):
return Distance(**{distance_att: value}) if distance_att else value
def get_internal_type(self):
- return 'DistanceField'
+ return "DistanceField"
diff --git a/django/contrib/gis/feeds.py b/django/contrib/gis/feeds.py
index cfc078b781..ebd4511889 100644
--- a/django/contrib/gis/feeds.py
+++ b/django/contrib/gis/feeds.py
@@ -14,7 +14,7 @@ class GeoFeedMixin:
a single white space. Given a tuple of coordinates, return a string
GeoRSS representation.
"""
- return ' '.join('%f %f' % (coord[1], coord[0]) for coord in coords)
+ return " ".join("%f %f" % (coord[1], coord[0]) for coord in coords)
def add_georss_point(self, handler, coords, w3c_geo=False):
"""
@@ -24,15 +24,15 @@ class GeoFeedMixin:
"""
if w3c_geo:
lon, lat = coords[:2]
- handler.addQuickElement('geo:lat', '%f' % lat)
- handler.addQuickElement('geo:lon', '%f' % lon)
+ handler.addQuickElement("geo:lat", "%f" % lat)
+ handler.addQuickElement("geo:lon", "%f" % lon)
else:
- handler.addQuickElement('georss:point', self.georss_coords((coords,)))
+ handler.addQuickElement("georss:point", self.georss_coords((coords,)))
def add_georss_element(self, handler, item, w3c_geo=False):
"""Add a GeoRSS XML element using the given item and handler."""
# Getting the Geometry object.
- geom = item.get('geometry')
+ geom = item.get("geometry")
if geom is not None:
if isinstance(geom, (list, tuple)):
# Special case if a tuple/list was passed in. The tuple may be
@@ -43,7 +43,7 @@ class GeoFeedMixin:
if len(geom) == 2:
box_coords = geom
else:
- raise ValueError('Only should be two sets of coordinates.')
+ raise ValueError("Only should be two sets of coordinates.")
else:
if len(geom) == 2:
# Point: (X, Y)
@@ -52,36 +52,46 @@ class GeoFeedMixin:
# Box: (X0, Y0, X1, Y1)
box_coords = (geom[:2], geom[2:])
else:
- raise ValueError('Only should be 2 or 4 numeric elements.')
+ raise ValueError("Only should be 2 or 4 numeric elements.")
# If a GeoRSS box was given via tuple.
if box_coords is not None:
if w3c_geo:
- raise ValueError('Cannot use simple GeoRSS box in W3C Geo feeds.')
- handler.addQuickElement('georss:box', self.georss_coords(box_coords))
+ raise ValueError(
+ "Cannot use simple GeoRSS box in W3C Geo feeds."
+ )
+ handler.addQuickElement(
+ "georss:box", self.georss_coords(box_coords)
+ )
else:
# Getting the lowercase geometry type.
gtype = str(geom.geom_type).lower()
- if gtype == 'point':
+ if gtype == "point":
self.add_georss_point(handler, geom.coords, w3c_geo=w3c_geo)
else:
if w3c_geo:
- raise ValueError('W3C Geo only supports Point geometries.')
+ raise ValueError("W3C Geo only supports Point geometries.")
# For formatting consistent w/the GeoRSS simple standard:
# http://georss.org/1.0#simple
- if gtype in ('linestring', 'linearring'):
- handler.addQuickElement('georss:line', self.georss_coords(geom.coords))
- elif gtype in ('polygon',):
+ if gtype in ("linestring", "linearring"):
+ handler.addQuickElement(
+ "georss:line", self.georss_coords(geom.coords)
+ )
+ elif gtype in ("polygon",):
# Only support the exterior ring.
- handler.addQuickElement('georss:polygon', self.georss_coords(geom[0].coords))
+ handler.addQuickElement(
+ "georss:polygon", self.georss_coords(geom[0].coords)
+ )
else:
- raise ValueError('Geometry type "%s" not supported.' % geom.geom_type)
+ raise ValueError(
+ 'Geometry type "%s" not supported.' % geom.geom_type
+ )
# ### SyndicationFeed subclasses ###
class GeoRSSFeed(Rss201rev2Feed, GeoFeedMixin):
def rss_attributes(self):
attrs = super().rss_attributes()
- attrs['xmlns:georss'] = 'http://www.georss.org/georss'
+ attrs["xmlns:georss"] = "http://www.georss.org/georss"
return attrs
def add_item_elements(self, handler, item):
@@ -96,7 +106,7 @@ class GeoRSSFeed(Rss201rev2Feed, GeoFeedMixin):
class GeoAtom1Feed(Atom1Feed, GeoFeedMixin):
def root_attributes(self):
attrs = super().root_attributes()
- attrs['xmlns:georss'] = 'http://www.georss.org/georss'
+ attrs["xmlns:georss"] = "http://www.georss.org/georss"
return attrs
def add_item_elements(self, handler, item):
@@ -111,7 +121,7 @@ class GeoAtom1Feed(Atom1Feed, GeoFeedMixin):
class W3CGeoFeed(Rss201rev2Feed, GeoFeedMixin):
def rss_attributes(self):
attrs = super().rss_attributes()
- attrs['xmlns:geo'] = 'http://www.w3.org/2003/01/geo/wgs84_pos#'
+ attrs["xmlns:geo"] = "http://www.w3.org/2003/01/geo/wgs84_pos#"
return attrs
def add_item_elements(self, handler, item):
@@ -131,10 +141,11 @@ class Feed(BaseFeed):
methods on their own subclasses so that geo-referenced information may
placed in the feed.
"""
+
feed_type = GeoRSSFeed
def feed_extra_kwargs(self, obj):
- return {'geometry': self._get_dynamic_attr('geometry', obj)}
+ return {"geometry": self._get_dynamic_attr("geometry", obj)}
def item_extra_kwargs(self, item):
- return {'geometry': self._get_dynamic_attr('item_geometry', item)}
+ return {"geometry": self._get_dynamic_attr("item_geometry", item)}
diff --git a/django/contrib/gis/forms/__init__.py b/django/contrib/gis/forms/__init__.py
index 237cbace8d..c07720b2d0 100644
--- a/django/contrib/gis/forms/__init__.py
+++ b/django/contrib/gis/forms/__init__.py
@@ -1,8 +1,13 @@
from django.forms import * # NOQA
from .fields import ( # NOQA
- GeometryCollectionField, GeometryField, LineStringField,
- MultiLineStringField, MultiPointField, MultiPolygonField, PointField,
+ GeometryCollectionField,
+ GeometryField,
+ LineStringField,
+ MultiLineStringField,
+ MultiPointField,
+ MultiPolygonField,
+ PointField,
PolygonField,
)
from .widgets import BaseGeometryWidget, OpenLayersWidget, OSMWidget # NOQA
diff --git a/django/contrib/gis/forms/fields.py b/django/contrib/gis/forms/fields.py
index 301d770836..1fd31530c1 100644
--- a/django/contrib/gis/forms/fields.py
+++ b/django/contrib/gis/forms/fields.py
@@ -13,15 +13,18 @@ class GeometryField(forms.Field):
accepted by GEOSGeometry is accepted by this form. By default,
this includes WKT, HEXEWKB, WKB (in a buffer), and GeoJSON.
"""
+
widget = OpenLayersWidget
- geom_type = 'GEOMETRY'
+ geom_type = "GEOMETRY"
default_error_messages = {
- 'required': _('No geometry value provided.'),
- 'invalid_geom': _('Invalid geometry value.'),
- 'invalid_geom_type': _('Invalid geometry type.'),
- 'transform_error': _('An error occurred when transforming the geometry '
- 'to the SRID of the geometry form field.'),
+ "required": _("No geometry value provided."),
+ "invalid_geom": _("Invalid geometry value."),
+ "invalid_geom_type": _("Invalid geometry type."),
+ "transform_error": _(
+ "An error occurred when transforming the geometry "
+ "to the SRID of the geometry form field."
+ ),
}
def __init__(self, *, srid=None, geom_type=None, **kwargs):
@@ -29,7 +32,7 @@ class GeometryField(forms.Field):
if geom_type is not None:
self.geom_type = geom_type
super().__init__(**kwargs)
- self.widget.attrs['geom_type'] = self.geom_type
+ self.widget.attrs["geom_type"] = self.geom_type
def to_python(self, value):
"""Transform the value to a Geometry object."""
@@ -37,7 +40,7 @@ class GeometryField(forms.Field):
return None
if not isinstance(value, GEOSGeometry):
- if hasattr(self.widget, 'deserialize'):
+ if hasattr(self.widget, "deserialize"):
try:
value = self.widget.deserialize(value)
except GDALException:
@@ -48,7 +51,9 @@ class GeometryField(forms.Field):
except (GEOSException, ValueError, TypeError):
value = None
if value is None:
- raise ValidationError(self.error_messages['invalid_geom'], code='invalid_geom')
+ raise ValidationError(
+ self.error_messages["invalid_geom"], code="invalid_geom"
+ )
# Try to set the srid
if not value.srid:
@@ -71,8 +76,13 @@ class GeometryField(forms.Field):
# Ensuring that the geometry is of the correct type (indicated
# using the OGC string label).
- if str(geom.geom_type).upper() != self.geom_type and self.geom_type != 'GEOMETRY':
- raise ValidationError(self.error_messages['invalid_geom_type'], code='invalid_geom_type')
+ if (
+ str(geom.geom_type).upper() != self.geom_type
+ and self.geom_type != "GEOMETRY"
+ ):
+ raise ValidationError(
+ self.error_messages["invalid_geom_type"], code="invalid_geom_type"
+ )
# Transforming the geometry if the SRID was set.
if self.srid and self.srid != -1 and self.srid != geom.srid:
@@ -80,12 +90,13 @@ class GeometryField(forms.Field):
geom.transform(self.srid)
except GEOSException:
raise ValidationError(
- self.error_messages['transform_error'], code='transform_error')
+ self.error_messages["transform_error"], code="transform_error"
+ )
return geom
def has_changed(self, initial, data):
- """ Compare geographic value of data with its initial value. """
+ """Compare geographic value of data with its initial value."""
try:
data = self.to_python(data)
@@ -106,28 +117,28 @@ class GeometryField(forms.Field):
class GeometryCollectionField(GeometryField):
- geom_type = 'GEOMETRYCOLLECTION'
+ geom_type = "GEOMETRYCOLLECTION"
class PointField(GeometryField):
- geom_type = 'POINT'
+ geom_type = "POINT"
class MultiPointField(GeometryField):
- geom_type = 'MULTIPOINT'
+ geom_type = "MULTIPOINT"
class LineStringField(GeometryField):
- geom_type = 'LINESTRING'
+ geom_type = "LINESTRING"
class MultiLineStringField(GeometryField):
- geom_type = 'MULTILINESTRING'
+ geom_type = "MULTILINESTRING"
class PolygonField(GeometryField):
- geom_type = 'POLYGON'
+ geom_type = "POLYGON"
class MultiPolygonField(GeometryField):
- geom_type = 'MULTIPOLYGON'
+ geom_type = "MULTIPOLYGON"
diff --git a/django/contrib/gis/forms/widgets.py b/django/contrib/gis/forms/widgets.py
index e38f173a98..0f53ee2e96 100644
--- a/django/contrib/gis/forms/widgets.py
+++ b/django/contrib/gis/forms/widgets.py
@@ -7,7 +7,7 @@ from django.contrib.gis.geos import GEOSException, GEOSGeometry
from django.forms.widgets import Widget
from django.utils import translation
-logger = logging.getLogger('django.contrib.gis')
+logger = logging.getLogger("django.contrib.gis")
class BaseGeometryWidget(Widget):
@@ -15,24 +15,25 @@ class BaseGeometryWidget(Widget):
The base class for rich geometry widgets.
Render a map using the WKT of the geometry.
"""
- geom_type = 'GEOMETRY'
+
+ geom_type = "GEOMETRY"
map_srid = 4326
map_width = 600
map_height = 400
display_raw = False
supports_3d = False
- template_name = '' # set on subclasses
+ template_name = "" # set on subclasses
def __init__(self, attrs=None):
self.attrs = {}
- for key in ('geom_type', 'map_srid', 'map_width', 'map_height', 'display_raw'):
+ for key in ("geom_type", "map_srid", "map_width", "map_height", "display_raw"):
self.attrs[key] = getattr(self, key)
if attrs:
self.attrs.update(attrs)
def serialize(self, value):
- return value.wkt if value else ''
+ return value.wkt if value else ""
def deserialize(self, value):
try:
@@ -58,40 +59,47 @@ class BaseGeometryWidget(Widget):
except gdal.GDALException as err:
logger.error(
"Error transforming geometry from srid '%s' to srid '%s' (%s)",
- value.srid, self.map_srid, err
+ value.srid,
+ self.map_srid,
+ err,
)
- geom_type = gdal.OGRGeomType(self.attrs['geom_type']).name
- context.update(self.build_attrs(self.attrs, {
- 'name': name,
- 'module': 'geodjango_%s' % name.replace('-', '_'), # JS-safe
- 'serialized': self.serialize(value),
- 'geom_type': 'Geometry' if geom_type == 'Unknown' else geom_type,
- 'STATIC_URL': settings.STATIC_URL,
- 'LANGUAGE_BIDI': translation.get_language_bidi(),
- **(attrs or {}),
- }))
+ geom_type = gdal.OGRGeomType(self.attrs["geom_type"]).name
+ context.update(
+ self.build_attrs(
+ self.attrs,
+ {
+ "name": name,
+ "module": "geodjango_%s" % name.replace("-", "_"), # JS-safe
+ "serialized": self.serialize(value),
+ "geom_type": "Geometry" if geom_type == "Unknown" else geom_type,
+ "STATIC_URL": settings.STATIC_URL,
+ "LANGUAGE_BIDI": translation.get_language_bidi(),
+ **(attrs or {}),
+ },
+ )
+ )
return context
class OpenLayersWidget(BaseGeometryWidget):
- template_name = 'gis/openlayers.html'
+ template_name = "gis/openlayers.html"
map_srid = 3857
class Media:
css = {
- 'all': (
- 'https://cdnjs.cloudflare.com/ajax/libs/ol3/4.6.5/ol.css',
- 'gis/css/ol3.css',
+ "all": (
+ "https://cdnjs.cloudflare.com/ajax/libs/ol3/4.6.5/ol.css",
+ "gis/css/ol3.css",
)
}
js = (
- 'https://cdnjs.cloudflare.com/ajax/libs/ol3/4.6.5/ol.js',
- 'gis/js/OLMapWidget.js',
+ "https://cdnjs.cloudflare.com/ajax/libs/ol3/4.6.5/ol.js",
+ "gis/js/OLMapWidget.js",
)
def serialize(self, value):
- return value.json if value else ''
+ return value.json if value else ""
def deserialize(self, value):
geom = super().deserialize(value)
@@ -105,14 +113,15 @@ class OSMWidget(OpenLayersWidget):
"""
An OpenLayers/OpenStreetMap-based widget.
"""
- template_name = 'gis/openlayers-osm.html'
+
+ template_name = "gis/openlayers-osm.html"
default_lon = 5
default_lat = 47
default_zoom = 12
def __init__(self, attrs=None):
super().__init__()
- for key in ('default_lon', 'default_lat', 'default_zoom'):
+ for key in ("default_lon", "default_lat", "default_zoom"):
self.attrs[key] = getattr(self, key)
if attrs:
self.attrs.update(attrs)
diff --git a/django/contrib/gis/gdal/__init__.py b/django/contrib/gis/gdal/__init__.py
index 1d8c6884bd..9ed6e31156 100644
--- a/django/contrib/gis/gdal/__init__.py
+++ b/django/contrib/gis/gdal/__init__.py
@@ -28,22 +28,31 @@
from django.contrib.gis.gdal.datasource import DataSource
from django.contrib.gis.gdal.driver import Driver
from django.contrib.gis.gdal.envelope import Envelope
-from django.contrib.gis.gdal.error import (
- GDALException, SRSException, check_err,
-)
+from django.contrib.gis.gdal.error import GDALException, SRSException, check_err
from django.contrib.gis.gdal.geometries import OGRGeometry
from django.contrib.gis.gdal.geomtype import OGRGeomType
from django.contrib.gis.gdal.libgdal import (
- GDAL_VERSION, gdal_full_version, gdal_version,
+ GDAL_VERSION,
+ gdal_full_version,
+ gdal_version,
)
from django.contrib.gis.gdal.raster.source import GDALRaster
-from django.contrib.gis.gdal.srs import (
- AxisOrder, CoordTransform, SpatialReference,
-)
+from django.contrib.gis.gdal.srs import AxisOrder, CoordTransform, SpatialReference
__all__ = (
- 'AxisOrder', 'Driver', 'DataSource', 'CoordTransform', 'Envelope',
- 'GDALException', 'GDALRaster', 'GDAL_VERSION', 'OGRGeometry',
- 'OGRGeomType', 'SpatialReference', 'SRSException', 'check_err',
- 'gdal_version', 'gdal_full_version',
+ "AxisOrder",
+ "Driver",
+ "DataSource",
+ "CoordTransform",
+ "Envelope",
+ "GDALException",
+ "GDALRaster",
+ "GDAL_VERSION",
+ "OGRGeometry",
+ "OGRGeomType",
+ "SpatialReference",
+ "SRSException",
+ "check_err",
+ "gdal_version",
+ "gdal_full_version",
)
diff --git a/django/contrib/gis/gdal/datasource.py b/django/contrib/gis/gdal/datasource.py
index f2091c864a..dfd043ab0c 100644
--- a/django/contrib/gis/gdal/datasource.py
+++ b/django/contrib/gis/gdal/datasource.py
@@ -52,7 +52,7 @@ class DataSource(GDALBase):
"Wraps an OGR Data Source object."
destructor = capi.destroy_ds
- def __init__(self, ds_input, ds_driver=False, write=False, encoding='utf-8'):
+ def __init__(self, ds_input, ds_driver=False, write=False, encoding="utf-8"):
# The write flag.
if write:
self._write = 1
@@ -73,10 +73,12 @@ class DataSource(GDALBase):
# Making the error message more clear rather than something
# like "Invalid pointer returned from OGROpen".
raise GDALException('Could not open the datasource at "%s"' % ds_input)
- elif isinstance(ds_input, self.ptr_type) and isinstance(ds_driver, Driver.ptr_type):
+ elif isinstance(ds_input, self.ptr_type) and isinstance(
+ ds_driver, Driver.ptr_type
+ ):
ds = ds_input
else:
- raise GDALException('Invalid data source input type: %s' % type(ds_input))
+ raise GDALException("Invalid data source input type: %s" % type(ds_input))
if ds:
self.ptr = ds
@@ -91,14 +93,17 @@ class DataSource(GDALBase):
try:
layer = capi.get_layer_by_name(self.ptr, force_bytes(index))
except GDALException:
- raise IndexError('Invalid OGR layer name given: %s.' % index)
+ raise IndexError("Invalid OGR layer name given: %s." % index)
elif isinstance(index, int):
if 0 <= index < self.layer_count:
layer = capi.get_layer(self._ptr, index)
else:
- raise IndexError('Index out of range when accessing layers in a datasource: %s.' % index)
+ raise IndexError(
+ "Index out of range when accessing layers in a datasource: %s."
+ % index
+ )
else:
- raise TypeError('Invalid index type: %s' % type(index))
+ raise TypeError("Invalid index type: %s" % type(index))
return Layer(layer, self)
def __len__(self):
@@ -107,7 +112,7 @@ class DataSource(GDALBase):
def __str__(self):
"Return OGR GetName and Driver for the Data Source."
- return '%s (%s)' % (self.name, self.driver)
+ return "%s (%s)" % (self.name, self.driver)
@property
def layer_count(self):
diff --git a/django/contrib/gis/gdal/driver.py b/django/contrib/gis/gdal/driver.py
index f90b886251..0ce7a2cdc8 100644
--- a/django/contrib/gis/gdal/driver.py
+++ b/django/contrib/gis/gdal/driver.py
@@ -2,7 +2,8 @@ from ctypes import c_void_p
from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import GDALException
-from django.contrib.gis.gdal.prototypes import ds as vcapi, raster as rcapi
+from django.contrib.gis.gdal.prototypes import ds as vcapi
+from django.contrib.gis.gdal.prototypes import raster as rcapi
from django.utils.encoding import force_bytes, force_str
@@ -20,16 +21,16 @@ class Driver(GDALBase):
# https://gdal.org/drivers/raster/
_alias = {
# vector
- 'esri': 'ESRI Shapefile',
- 'shp': 'ESRI Shapefile',
- 'shape': 'ESRI Shapefile',
- 'tiger': 'TIGER',
- 'tiger/line': 'TIGER',
+ "esri": "ESRI Shapefile",
+ "shp": "ESRI Shapefile",
+ "shape": "ESRI Shapefile",
+ "tiger": "TIGER",
+ "tiger/line": "TIGER",
# raster
- 'tiff': 'GTiff',
- 'tif': 'GTiff',
- 'jpeg': 'JPEG',
- 'jpg': 'JPEG',
+ "tiff": "GTiff",
+ "tif": "GTiff",
+ "jpeg": "JPEG",
+ "jpg": "JPEG",
}
def __init__(self, dr_input):
@@ -61,11 +62,15 @@ class Driver(GDALBase):
elif isinstance(dr_input, c_void_p):
driver = dr_input
else:
- raise GDALException('Unrecognized input type for GDAL/OGR Driver: %s' % type(dr_input))
+ raise GDALException(
+ "Unrecognized input type for GDAL/OGR Driver: %s" % type(dr_input)
+ )
# Making sure we get a valid pointer to the OGR Driver
if not driver:
- raise GDALException('Could not initialize GDAL/OGR Driver on input: %s' % dr_input)
+ raise GDALException(
+ "Could not initialize GDAL/OGR Driver on input: %s" % dr_input
+ )
self.ptr = driver
def __str__(self):
diff --git a/django/contrib/gis/gdal/envelope.py b/django/contrib/gis/gdal/envelope.py
index 98c333f483..4c2c1e4a1a 100644
--- a/django/contrib/gis/gdal/envelope.py
+++ b/django/contrib/gis/gdal/envelope.py
@@ -20,11 +20,12 @@ from django.contrib.gis.gdal.error import GDALException
# https://gdal.org/doxygen/ogr__core_8h_source.html
class OGREnvelope(Structure):
"Represent the OGREnvelope C Structure."
- _fields_ = [("MinX", c_double),
- ("MaxX", c_double),
- ("MinY", c_double),
- ("MaxY", c_double),
- ]
+ _fields_ = [
+ ("MinX", c_double),
+ ("MaxX", c_double),
+ ("MinY", c_double),
+ ("MaxY", c_double),
+ ]
class Envelope:
@@ -47,23 +48,25 @@ class Envelope:
elif isinstance(args[0], (tuple, list)):
# A tuple was passed in.
if len(args[0]) != 4:
- raise GDALException('Incorrect number of tuple elements (%d).' % len(args[0]))
+ raise GDALException(
+ "Incorrect number of tuple elements (%d)." % len(args[0])
+ )
else:
self._from_sequence(args[0])
else:
- raise TypeError('Incorrect type of argument: %s' % type(args[0]))
+ raise TypeError("Incorrect type of argument: %s" % type(args[0]))
elif len(args) == 4:
# Individual parameters passed in.
# Thanks to ww for the help
self._from_sequence([float(a) for a in args])
else:
- raise GDALException('Incorrect number (%d) of arguments.' % len(args))
+ raise GDALException("Incorrect number (%d) of arguments." % len(args))
# Checking the x,y coordinates
if self.min_x > self.max_x:
- raise GDALException('Envelope minimum X > maximum X.')
+ raise GDALException("Envelope minimum X > maximum X.")
if self.min_y > self.max_y:
- raise GDALException('Envelope minimum Y > maximum Y.')
+ raise GDALException("Envelope minimum Y > maximum Y.")
def __eq__(self, other):
"""
@@ -71,13 +74,21 @@ class Envelope:
other Envelopes and 4-tuples.
"""
if isinstance(other, Envelope):
- return (self.min_x == other.min_x) and (self.min_y == other.min_y) and \
- (self.max_x == other.max_x) and (self.max_y == other.max_y)
+ return (
+ (self.min_x == other.min_x)
+ and (self.min_y == other.min_y)
+ and (self.max_x == other.max_x)
+ and (self.max_y == other.max_y)
+ )
elif isinstance(other, tuple) and len(other) == 4:
- return (self.min_x == other[0]) and (self.min_y == other[1]) and \
- (self.max_x == other[2]) and (self.max_y == other[3])
+ return (
+ (self.min_x == other[0])
+ and (self.min_y == other[1])
+ and (self.max_x == other[2])
+ and (self.max_y == other[3])
+ )
else:
- raise GDALException('Equivalence testing only works with other Envelopes.')
+ raise GDALException("Equivalence testing only works with other Envelopes.")
def __str__(self):
"Return a string representation of the tuple."
@@ -104,12 +115,16 @@ class Envelope:
if len(args) == 1:
if isinstance(args[0], Envelope):
return self.expand_to_include(args[0].tuple)
- elif hasattr(args[0], 'x') and hasattr(args[0], 'y'):
- return self.expand_to_include(args[0].x, args[0].y, args[0].x, args[0].y)
+ elif hasattr(args[0], "x") and hasattr(args[0], "y"):
+ return self.expand_to_include(
+ args[0].x, args[0].y, args[0].x, args[0].y
+ )
elif isinstance(args[0], (tuple, list)):
# A tuple was passed in.
if len(args[0]) == 2:
- return self.expand_to_include((args[0][0], args[0][1], args[0][0], args[0][1]))
+ return self.expand_to_include(
+ (args[0][0], args[0][1], args[0][0], args[0][1])
+ )
elif len(args[0]) == 4:
(minx, miny, maxx, maxy) = args[0]
if minx < self._envelope.MinX:
@@ -121,9 +136,11 @@ class Envelope:
if maxy > self._envelope.MaxY:
self._envelope.MaxY = maxy
else:
- raise GDALException('Incorrect number of tuple elements (%d).' % len(args[0]))
+ raise GDALException(
+ "Incorrect number of tuple elements (%d)." % len(args[0])
+ )
else:
- raise TypeError('Incorrect type of argument: %s' % type(args[0]))
+ raise TypeError("Incorrect type of argument: %s" % type(args[0]))
elif len(args) == 2:
# An x and an y parameter were passed in
return self.expand_to_include((args[0], args[1], args[0], args[1]))
@@ -131,7 +148,7 @@ class Envelope:
# Individual parameters passed in.
return self.expand_to_include(args)
else:
- raise GDALException('Incorrect number (%d) of arguments.' % len(args[0]))
+ raise GDALException("Incorrect number (%d) of arguments." % len(args[0]))
@property
def min_x(self):
@@ -172,7 +189,15 @@ class Envelope:
def wkt(self):
"Return WKT representing a Polygon for this envelope."
# TODO: Fix significant figures.
- return 'POLYGON((%s %s,%s %s,%s %s,%s %s,%s %s))' % \
- (self.min_x, self.min_y, self.min_x, self.max_y,
- self.max_x, self.max_y, self.max_x, self.min_y,
- self.min_x, self.min_y)
+ return "POLYGON((%s %s,%s %s,%s %s,%s %s,%s %s))" % (
+ self.min_x,
+ self.min_y,
+ self.min_x,
+ self.max_y,
+ self.max_x,
+ self.max_y,
+ self.max_x,
+ self.min_y,
+ self.min_x,
+ self.min_y,
+ )
diff --git a/django/contrib/gis/gdal/error.py b/django/contrib/gis/gdal/error.py
index b5646dd751..df19c2e4a7 100644
--- a/django/contrib/gis/gdal/error.py
+++ b/django/contrib/gis/gdal/error.py
@@ -18,29 +18,29 @@ class SRSException(Exception):
# OGR Error Codes
OGRERR_DICT = {
- 1: (GDALException, 'Not enough data.'),
- 2: (GDALException, 'Not enough memory.'),
- 3: (GDALException, 'Unsupported geometry type.'),
- 4: (GDALException, 'Unsupported operation.'),
- 5: (GDALException, 'Corrupt data.'),
- 6: (GDALException, 'OGR failure.'),
- 7: (SRSException, 'Unsupported SRS.'),
- 8: (GDALException, 'Invalid handle.'),
+ 1: (GDALException, "Not enough data."),
+ 2: (GDALException, "Not enough memory."),
+ 3: (GDALException, "Unsupported geometry type."),
+ 4: (GDALException, "Unsupported operation."),
+ 5: (GDALException, "Corrupt data."),
+ 6: (GDALException, "OGR failure."),
+ 7: (SRSException, "Unsupported SRS."),
+ 8: (GDALException, "Invalid handle."),
}
# CPL Error Codes
# https://gdal.org/api/cpl.html#cpl-error-h
CPLERR_DICT = {
- 1: (GDALException, 'AppDefined'),
- 2: (GDALException, 'OutOfMemory'),
- 3: (GDALException, 'FileIO'),
- 4: (GDALException, 'OpenFailed'),
- 5: (GDALException, 'IllegalArg'),
- 6: (GDALException, 'NotSupported'),
- 7: (GDALException, 'AssertionFailed'),
- 8: (GDALException, 'NoWriteAccess'),
- 9: (GDALException, 'UserInterrupt'),
- 10: (GDALException, 'ObjectNull'),
+ 1: (GDALException, "AppDefined"),
+ 2: (GDALException, "OutOfMemory"),
+ 3: (GDALException, "FileIO"),
+ 4: (GDALException, "OpenFailed"),
+ 5: (GDALException, "IllegalArg"),
+ 6: (GDALException, "NotSupported"),
+ 7: (GDALException, "AssertionFailed"),
+ 8: (GDALException, "NoWriteAccess"),
+ 9: (GDALException, "UserInterrupt"),
+ 10: (GDALException, "ObjectNull"),
}
ERR_NONE = 0
diff --git a/django/contrib/gis/gdal/feature.py b/django/contrib/gis/gdal/feature.py
index 82a9089c16..6f08969984 100644
--- a/django/contrib/gis/gdal/feature.py
+++ b/django/contrib/gis/gdal/feature.py
@@ -2,7 +2,8 @@ from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import GDALException
from django.contrib.gis.gdal.field import Field
from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
-from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api
+from django.contrib.gis.gdal.prototypes import ds as capi
+from django.contrib.gis.gdal.prototypes import geom as geom_api
from django.utils.encoding import force_bytes, force_str
@@ -15,6 +16,7 @@ class Feature(GDALBase):
This class that wraps an OGR Feature, needs to be instantiated
from a Layer object.
"""
+
destructor = capi.destroy_feature
def __init__(self, feat, layer):
@@ -22,7 +24,7 @@ class Feature(GDALBase):
Initialize Feature from a pointer and its Layer object.
"""
if not feat:
- raise GDALException('Cannot create OGR Feature, invalid pointer given.')
+ raise GDALException("Cannot create OGR Feature, invalid pointer given.")
self.ptr = feat
self._layer = layer
@@ -38,7 +40,9 @@ class Feature(GDALBase):
elif 0 <= index < self.num_fields:
i = index
else:
- raise IndexError('Index out of range when accessing field in a feature: %s.' % index)
+ raise IndexError(
+ "Index out of range when accessing field in a feature: %s." % index
+ )
return Field(self, i)
def __len__(self):
@@ -47,7 +51,7 @@ class Feature(GDALBase):
def __str__(self):
"The string name of the feature."
- return 'Feature FID %d in Layer<%s>' % (self.fid, self.layer_name)
+ return "Feature FID %d in Layer<%s>" % (self.fid, self.layer_name)
def __eq__(self, other):
"Do equivalence testing on the features."
@@ -81,8 +85,9 @@ class Feature(GDALBase):
force_str(
capi.get_field_name(capi.get_field_defn(self._layer._ldefn, i)),
self.encoding,
- strings_only=True
- ) for i in range(self.num_fields)
+ strings_only=True,
+ )
+ for i in range(self.num_fields)
]
@property
@@ -104,12 +109,12 @@ class Feature(GDALBase):
object. May take a string of the field name or a Field object as
parameters.
"""
- field_name = getattr(field, 'name', field)
+ field_name = getattr(field, "name", field)
return self[field_name].value
def index(self, field_name):
"Return the index of the given field name."
i = capi.get_field_index(self.ptr, force_bytes(field_name))
if i < 0:
- raise IndexError('Invalid OFT field name given: %s.' % field_name)
+ raise IndexError("Invalid OFT field name given: %s." % field_name)
return i
diff --git a/django/contrib/gis/gdal/field.py b/django/contrib/gis/gdal/field.py
index e803886182..5374f6c3cb 100644
--- a/django/contrib/gis/gdal/field.py
+++ b/django/contrib/gis/gdal/field.py
@@ -28,7 +28,7 @@ class Field(GDALBase):
# Getting the pointer for this field.
fld_ptr = capi.get_feat_field_defn(feat.ptr, index)
if not fld_ptr:
- raise GDALException('Cannot create OGR Field, invalid pointer given.')
+ raise GDALException("Cannot create OGR Field, invalid pointer given.")
self.ptr = fld_ptr
# Setting the class depending upon the OGR Field Type (OFT)
@@ -41,14 +41,26 @@ class Field(GDALBase):
# #### Field Methods ####
def as_double(self):
"Retrieve the Field's value as a double (float)."
- return capi.get_field_as_double(self._feat.ptr, self._index) if self.is_set else None
+ return (
+ capi.get_field_as_double(self._feat.ptr, self._index)
+ if self.is_set
+ else None
+ )
def as_int(self, is_64=False):
"Retrieve the Field's value as an integer."
if is_64:
- return capi.get_field_as_integer64(self._feat.ptr, self._index) if self.is_set else None
+ return (
+ capi.get_field_as_integer64(self._feat.ptr, self._index)
+ if self.is_set
+ else None
+ )
else:
- return capi.get_field_as_integer(self._feat.ptr, self._index) if self.is_set else None
+ return (
+ capi.get_field_as_integer(self._feat.ptr, self._index)
+ if self.is_set
+ else None
+ )
def as_string(self):
"Retrieve the Field's value as a string."
@@ -63,12 +75,22 @@ class Field(GDALBase):
return None
yy, mm, dd, hh, mn, ss, tz = [c_int() for i in range(7)]
status = capi.get_field_as_datetime(
- self._feat.ptr, self._index, byref(yy), byref(mm), byref(dd),
- byref(hh), byref(mn), byref(ss), byref(tz))
+ self._feat.ptr,
+ self._index,
+ byref(yy),
+ byref(mm),
+ byref(dd),
+ byref(hh),
+ byref(mn),
+ byref(ss),
+ byref(tz),
+ )
if status:
return (yy, mm, dd, hh, mn, ss, tz)
else:
- raise GDALException('Unable to retrieve date & time information from the field.')
+ raise GDALException(
+ "Unable to retrieve date & time information from the field."
+ )
# #### Field Properties ####
@property
diff --git a/django/contrib/gis/gdal/geometries.py b/django/contrib/gis/gdal/geometries.py
index d807b3e8b9..dbb391f75f 100644
--- a/django/contrib/gis/gdal/geometries.py
+++ b/django/contrib/gis/gdal/geometries.py
@@ -46,7 +46,8 @@ from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.error import GDALException, SRSException
from django.contrib.gis.gdal.geomtype import OGRGeomType
-from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api
+from django.contrib.gis.gdal.prototypes import geom as capi
+from django.contrib.gis.gdal.prototypes import srs as srs_api
from django.contrib.gis.gdal.srs import CoordTransform, SpatialReference
from django.contrib.gis.geometry import hex_regex, json_regex, wkt_regex
from django.utils.encoding import force_bytes
@@ -58,6 +59,7 @@ from django.utils.encoding import force_bytes
# The OGR_G_* routines are relevant here.
class OGRGeometry(GDALBase):
"""Encapsulate an OGR geometry."""
+
destructor = capi.destroy_geom
def __init__(self, geom_input, srs=None):
@@ -74,16 +76,18 @@ class OGRGeometry(GDALBase):
wkt_m = wkt_regex.match(geom_input)
json_m = json_regex.match(geom_input)
if wkt_m:
- if wkt_m['srid']:
+ if wkt_m["srid"]:
# If there's EWKT, set the SRS w/value of the SRID.
- srs = int(wkt_m['srid'])
- if wkt_m['type'].upper() == 'LINEARRING':
+ srs = int(wkt_m["srid"])
+ if wkt_m["type"].upper() == "LINEARRING":
# OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
# See https://trac.osgeo.org/gdal/ticket/1992.
- g = capi.create_geom(OGRGeomType(wkt_m['type']).num)
- capi.import_wkt(g, byref(c_char_p(wkt_m['wkt'].encode())))
+ g = capi.create_geom(OGRGeomType(wkt_m["type"]).num)
+ capi.import_wkt(g, byref(c_char_p(wkt_m["wkt"].encode())))
else:
- g = capi.from_wkt(byref(c_char_p(wkt_m['wkt'].encode())), None, byref(c_void_p()))
+ g = capi.from_wkt(
+ byref(c_char_p(wkt_m["wkt"].encode())), None, byref(c_void_p())
+ )
elif json_m:
g = self._from_json(geom_input.encode())
else:
@@ -101,12 +105,17 @@ class OGRGeometry(GDALBase):
# OGR pointer (c_void_p) was the input.
g = geom_input
else:
- raise GDALException('Invalid input type for OGR Geometry construction: %s' % type(geom_input))
+ raise GDALException(
+ "Invalid input type for OGR Geometry construction: %s"
+ % type(geom_input)
+ )
# Now checking the Geometry pointer before finishing initialization
# by setting the pointer for the object.
if not g:
- raise GDALException('Cannot create OGR Geometry from input: %s' % geom_input)
+ raise GDALException(
+ "Cannot create OGR Geometry from input: %s" % geom_input
+ )
self.ptr = g
# Assigning the SpatialReference object to the geometry, if valid.
@@ -129,13 +138,15 @@ class OGRGeometry(GDALBase):
wkb, srs = state
ptr = capi.from_wkb(wkb, None, byref(c_void_p()), len(wkb))
if not ptr:
- raise GDALException('Invalid OGRGeometry loaded from pickled state.')
+ raise GDALException("Invalid OGRGeometry loaded from pickled state.")
self.ptr = ptr
self.srs = srs
@classmethod
def _from_wkb(cls, geom_input):
- return capi.from_wkb(bytes(geom_input), None, byref(c_void_p()), len(geom_input))
+ return capi.from_wkb(
+ bytes(geom_input), None, byref(c_void_p()), len(geom_input)
+ )
@staticmethod
def _from_json(geom_input):
@@ -145,8 +156,10 @@ class OGRGeometry(GDALBase):
def from_bbox(cls, bbox):
"Construct a Polygon from a bounding box (4-tuple)."
x0, y0, x1, y1 = bbox
- return OGRGeometry('POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' % (
- x0, y0, x0, y1, x1, y1, x1, y0, x0, y0))
+ return OGRGeometry(
+ "POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))"
+ % (x0, y0, x0, y1, x1, y1, x1, y0, x0, y0)
+ )
@staticmethod
def from_json(geom_input):
@@ -198,7 +211,7 @@ class OGRGeometry(GDALBase):
def _set_coord_dim(self, dim):
"Set the coordinate dimension of this Geometry."
if dim not in (2, 3):
- raise ValueError('Geometry dimension must be either 2 or 3')
+ raise ValueError("Geometry dimension must be either 2 or 3")
capi.set_coord_dim(self.ptr, dim)
coord_dim = property(_get_coord_dim, _set_coord_dim)
@@ -278,7 +291,9 @@ class OGRGeometry(GDALBase):
elif srs is None:
srs_ptr = None
else:
- raise TypeError('Cannot assign spatial reference with object of type: %s' % type(srs))
+ raise TypeError(
+ "Cannot assign spatial reference with object of type: %s" % type(srs)
+ )
capi.assign_srs(self.ptr, srs_ptr)
srs = property(_get_srs, _set_srs)
@@ -294,19 +309,21 @@ class OGRGeometry(GDALBase):
if isinstance(srid, int) or srid is None:
self.srs = srid
else:
- raise TypeError('SRID must be set with an integer.')
+ raise TypeError("SRID must be set with an integer.")
srid = property(_get_srid, _set_srid)
# #### Output Methods ####
def _geos_ptr(self):
from django.contrib.gis.geos import GEOSGeometry
+
return GEOSGeometry._from_wkb(self.wkb)
@property
def geos(self):
"Return a GEOSGeometry object from this OGRGeometry."
from django.contrib.gis.geos import GEOSGeometry
+
return GEOSGeometry(self._geos_ptr(), self.srid)
@property
@@ -325,6 +342,7 @@ class OGRGeometry(GDALBase):
Return the GeoJSON representation of this Geometry.
"""
return capi.to_json(self.ptr)
+
geojson = json
@property
@@ -340,7 +358,7 @@ class OGRGeometry(GDALBase):
@property
def wkb(self):
"Return the WKB representation of the Geometry."
- if sys.byteorder == 'little':
+ if sys.byteorder == "little":
byteorder = 1 # wkbNDR (from ogr_core.h)
else:
byteorder = 0 # wkbXDR
@@ -361,7 +379,7 @@ class OGRGeometry(GDALBase):
"Return the EWKT representation of the Geometry."
srs = self.srs
if srs and srs.srid:
- return 'SRID=%s;%s' % (srs.srid, self.wkt)
+ return "SRID=%s;%s" % (srs.srid, self.wkt)
else:
return self.wkt
@@ -402,15 +420,19 @@ class OGRGeometry(GDALBase):
sr = SpatialReference(coord_trans)
capi.geom_transform_to(self.ptr, sr.ptr)
else:
- raise TypeError('Transform only accepts CoordTransform, '
- 'SpatialReference, string, and integer objects.')
+ raise TypeError(
+ "Transform only accepts CoordTransform, "
+ "SpatialReference, string, and integer objects."
+ )
# #### Topology Methods ####
def _topology(self, func, other):
"""A generalized function for topology operations, takes a GDAL function and
the other geometry to perform the operation on."""
if not isinstance(other, OGRGeometry):
- raise TypeError('Must use another OGRGeometry object for topology operations!')
+ raise TypeError(
+ "Must use another OGRGeometry object for topology operations!"
+ )
# Returning the output of the given function with the other geometry's
# pointer.
@@ -500,14 +522,14 @@ class OGRGeometry(GDALBase):
# The subclasses for OGR Geometry.
class Point(OGRGeometry):
-
def _geos_ptr(self):
from django.contrib.gis import geos
+
return geos.Point._create_empty() if self.empty else super()._geos_ptr()
@classmethod
def _create_empty(cls):
- return capi.create_geom(OGRGeomType('point').num)
+ return capi.create_geom(OGRGeomType("point").num)
@property
def x(self):
@@ -532,11 +554,11 @@ class Point(OGRGeometry):
return (self.x, self.y)
elif self.coord_dim == 3:
return (self.x, self.y, self.z)
+
coords = tuple
class LineString(OGRGeometry):
-
def __getitem__(self, index):
"Return the Point at the given index."
if 0 <= index < self.point_count:
@@ -550,7 +572,9 @@ class LineString(OGRGeometry):
elif dim == 3:
return (x.value, y.value, z.value)
else:
- raise IndexError('Index out of range when accessing points of a line string: %s.' % index)
+ raise IndexError(
+ "Index out of range when accessing points of a line string: %s." % index
+ )
def __len__(self):
"Return the number of points in the LineString."
@@ -560,6 +584,7 @@ class LineString(OGRGeometry):
def tuple(self):
"Return the tuple representation of this LineString."
return tuple(self[i] for i in range(len(self)))
+
coords = tuple
def _listarr(self, func):
@@ -592,7 +617,6 @@ class LinearRing(LineString):
class Polygon(OGRGeometry):
-
def __len__(self):
"Return the number of interior rings in this Polygon."
return self.geom_count
@@ -600,21 +624,27 @@ class Polygon(OGRGeometry):
def __getitem__(self, index):
"Get the ring at the specified index."
if 0 <= index < self.geom_count:
- return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
+ return OGRGeometry(
+ capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs
+ )
else:
- raise IndexError('Index out of range when accessing rings of a polygon: %s.' % index)
+ raise IndexError(
+ "Index out of range when accessing rings of a polygon: %s." % index
+ )
# Polygon Properties
@property
def shell(self):
"Return the shell of this Polygon."
return self[0] # First ring is the shell
+
exterior_ring = shell
@property
def tuple(self):
"Return a tuple of LinearRing coordinate tuples."
return tuple(self[i].tuple for i in range(self.geom_count))
+
coords = tuple
@property
@@ -627,7 +657,7 @@ class Polygon(OGRGeometry):
def centroid(self):
"Return the centroid (a Point) of this Polygon."
# The centroid is a Point, create a geometry for this.
- p = OGRGeometry(OGRGeomType('Point'))
+ p = OGRGeometry(OGRGeomType("Point"))
capi.get_centroid(self.ptr, p.ptr)
return p
@@ -639,9 +669,14 @@ class GeometryCollection(OGRGeometry):
def __getitem__(self, index):
"Get the Geometry at the specified index."
if 0 <= index < self.geom_count:
- return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
+ return OGRGeometry(
+ capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs
+ )
else:
- raise IndexError('Index out of range when accessing geometry in a collection: %s.' % index)
+ raise IndexError(
+ "Index out of range when accessing geometry in a collection: %s."
+ % index
+ )
def __len__(self):
"Return the number of geometries in this Geometry Collection."
@@ -659,7 +694,7 @@ class GeometryCollection(OGRGeometry):
tmp = OGRGeometry(geom)
capi.add_geom(self.ptr, tmp.ptr)
else:
- raise GDALException('Must add an OGRGeometry.')
+ raise GDALException("Must add an OGRGeometry.")
@property
def point_count(self):
@@ -671,6 +706,7 @@ class GeometryCollection(OGRGeometry):
def tuple(self):
"Return a tuple representation of this Geometry Collection."
return tuple(self[i].tuple for i in range(self.geom_count))
+
coords = tuple
diff --git a/django/contrib/gis/gdal/geomtype.py b/django/contrib/gis/gdal/geomtype.py
index 591c680c59..8b77cafa34 100644
--- a/django/contrib/gis/gdal/geomtype.py
+++ b/django/contrib/gis/gdal/geomtype.py
@@ -8,24 +8,24 @@ class OGRGeomType:
# Dictionary of acceptable OGRwkbGeometryType s and their string names.
_types = {
- 0: 'Unknown',
- 1: 'Point',
- 2: 'LineString',
- 3: 'Polygon',
- 4: 'MultiPoint',
- 5: 'MultiLineString',
- 6: 'MultiPolygon',
- 7: 'GeometryCollection',
- 100: 'None',
- 101: 'LinearRing',
- 102: 'PointZ',
- 1 + wkb25bit: 'Point25D',
- 2 + wkb25bit: 'LineString25D',
- 3 + wkb25bit: 'Polygon25D',
- 4 + wkb25bit: 'MultiPoint25D',
- 5 + wkb25bit: 'MultiLineString25D',
- 6 + wkb25bit: 'MultiPolygon25D',
- 7 + wkb25bit: 'GeometryCollection25D',
+ 0: "Unknown",
+ 1: "Point",
+ 2: "LineString",
+ 3: "Polygon",
+ 4: "MultiPoint",
+ 5: "MultiLineString",
+ 6: "MultiPolygon",
+ 7: "GeometryCollection",
+ 100: "None",
+ 101: "LinearRing",
+ 102: "PointZ",
+ 1 + wkb25bit: "Point25D",
+ 2 + wkb25bit: "LineString25D",
+ 3 + wkb25bit: "Polygon25D",
+ 4 + wkb25bit: "MultiPoint25D",
+ 5 + wkb25bit: "MultiLineString25D",
+ 6 + wkb25bit: "MultiPolygon25D",
+ 7 + wkb25bit: "GeometryCollection25D",
}
# Reverse type dictionary, keyed by lowercase of the name.
_str_types = {v.lower(): k for k, v in _types.items()}
@@ -36,17 +36,17 @@ class OGRGeomType:
num = type_input.num
elif isinstance(type_input, str):
type_input = type_input.lower()
- if type_input == 'geometry':
- type_input = 'unknown'
+ if type_input == "geometry":
+ type_input = "unknown"
num = self._str_types.get(type_input)
if num is None:
raise GDALException('Invalid OGR String Type "%s"' % type_input)
elif isinstance(type_input, int):
if type_input not in self._types:
- raise GDALException('Invalid OGR Integer Type: %d' % type_input)
+ raise GDALException("Invalid OGR Integer Type: %d" % type_input)
num = type_input
else:
- raise TypeError('Invalid OGR input type given.')
+ raise TypeError("Invalid OGR input type given.")
# Setting the OGR geometry type number.
self.num = num
@@ -77,19 +77,19 @@ class OGRGeomType:
@property
def django(self):
"Return the Django GeometryField for this OGR Type."
- s = self.name.replace('25D', '')
- if s in ('LinearRing', 'None'):
+ s = self.name.replace("25D", "")
+ if s in ("LinearRing", "None"):
return None
- elif s == 'Unknown':
- s = 'Geometry'
- elif s == 'PointZ':
- s = 'Point'
- return s + 'Field'
+ elif s == "Unknown":
+ s = "Geometry"
+ elif s == "PointZ":
+ s = "Point"
+ return s + "Field"
def to_multi(self):
"""
Transform Point, LineString, Polygon, and their 25D equivalents
to their Multi... counterpart.
"""
- if self.name.startswith(('Point', 'LineString', 'Polygon')):
+ if self.name.startswith(("Point", "LineString", "Polygon")):
self.num += 3
diff --git a/django/contrib/gis/gdal/layer.py b/django/contrib/gis/gdal/layer.py
index 012f70bdb0..e8f97b7552 100644
--- a/django/contrib/gis/gdal/layer.py
+++ b/django/contrib/gis/gdal/layer.py
@@ -7,9 +7,9 @@ from django.contrib.gis.gdal.feature import Feature
from django.contrib.gis.gdal.field import OGRFieldTypes
from django.contrib.gis.gdal.geometries import OGRGeometry
from django.contrib.gis.gdal.geomtype import OGRGeomType
-from django.contrib.gis.gdal.prototypes import (
- ds as capi, geom as geom_api, srs as srs_api,
-)
+from django.contrib.gis.gdal.prototypes import ds as capi
+from django.contrib.gis.gdal.prototypes import geom as geom_api
+from django.contrib.gis.gdal.prototypes import srs as srs_api
from django.contrib.gis.gdal.srs import SpatialReference
from django.utils.encoding import force_bytes, force_str
@@ -29,12 +29,12 @@ class Layer(GDALBase):
collection of the `DataSource` while this Layer is still active.
"""
if not layer_ptr:
- raise GDALException('Cannot create Layer, invalid pointer given')
+ raise GDALException("Cannot create Layer, invalid pointer given")
self.ptr = layer_ptr
self._ds = ds
self._ldefn = capi.get_layer_defn(self._ptr)
# Does the Layer support random reading?
- self._random_read = self.test_capability(b'RandomRead')
+ self._random_read = self.test_capability(b"RandomRead")
def __getitem__(self, index):
"Get the Feature at the specified index."
@@ -43,14 +43,16 @@ class Layer(GDALBase):
# number of features because the beginning and ending feature IDs
# are not guaranteed to be 0 and len(layer)-1, respectively.
if index < 0:
- raise IndexError('Negative indices are not allowed on OGR Layers.')
+ raise IndexError("Negative indices are not allowed on OGR Layers.")
return self._make_feature(index)
elif isinstance(index, slice):
# A slice was given
start, stop, stride = index.indices(self.num_feat)
return [self._make_feature(fid) for fid in range(start, stop, stride)]
else:
- raise TypeError('Integers and slices may only be used when indexing OGR Layers.')
+ raise TypeError(
+ "Integers and slices may only be used when indexing OGR Layers."
+ )
def __iter__(self):
"Iterate over each Feature in the Layer."
@@ -87,7 +89,7 @@ class Layer(GDALBase):
if feat.fid == feat_id:
return feat
# Should have returned a Feature, raise an IndexError.
- raise IndexError('Invalid feature id: %s.' % feat_id)
+ raise IndexError("Invalid feature id: %s." % feat_id)
# #### Layer properties ####
@property
@@ -133,10 +135,14 @@ class Layer(GDALBase):
Return a list of string names corresponding to each of the Fields
available in this Layer.
"""
- return [force_str(
- capi.get_field_name(capi.get_field_defn(self._ldefn, i)),
- self._ds.encoding, strings_only=True,
- ) for i in range(self.num_fields)]
+ return [
+ force_str(
+ capi.get_field_name(capi.get_field_defn(self._ldefn, i)),
+ self._ds.encoding,
+ strings_only=True,
+ )
+ for i in range(self.num_fields)
+ ]
@property
def field_types(self):
@@ -145,20 +151,26 @@ class Layer(GDALBase):
return the list [OFTInteger, OFTReal, OFTString] for an OGR layer that
has an integer, a floating-point, and string fields.
"""
- return [OGRFieldTypes[capi.get_field_type(capi.get_field_defn(self._ldefn, i))]
- for i in range(self.num_fields)]
+ return [
+ OGRFieldTypes[capi.get_field_type(capi.get_field_defn(self._ldefn, i))]
+ for i in range(self.num_fields)
+ ]
@property
def field_widths(self):
"Return a list of the maximum field widths for the features."
- return [capi.get_field_width(capi.get_field_defn(self._ldefn, i))
- for i in range(self.num_fields)]
+ return [
+ capi.get_field_width(capi.get_field_defn(self._ldefn, i))
+ for i in range(self.num_fields)
+ ]
@property
def field_precisions(self):
"Return the field precisions for the features."
- return [capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
- for i in range(self.num_fields)]
+ return [
+ capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
+ for i in range(self.num_fields)
+ ]
def _get_spatial_filter(self):
try:
@@ -171,7 +183,7 @@ class Layer(GDALBase):
capi.set_spatial_filter(self.ptr, filter.ptr)
elif isinstance(filter, (tuple, list)):
if not len(filter) == 4:
- raise ValueError('Spatial filter list/tuple must have 4 elements.')
+ raise ValueError("Spatial filter list/tuple must have 4 elements.")
# Map c_double onto params -- if a bad type is passed in it
# will be caught here.
xmin, ymin, xmax, ymax = map(c_double, filter)
@@ -179,7 +191,9 @@ class Layer(GDALBase):
elif filter is None:
capi.set_spatial_filter(self.ptr, None)
else:
- raise TypeError('Spatial filter must be either an OGRGeometry instance, a 4-tuple, or None.')
+ raise TypeError(
+ "Spatial filter must be either an OGRGeometry instance, a 4-tuple, or None."
+ )
spatial_filter = property(_get_spatial_filter, _set_spatial_filter)
@@ -190,7 +204,7 @@ class Layer(GDALBase):
in the Layer.
"""
if field_name not in self.fields:
- raise GDALException('invalid field name: %s' % field_name)
+ raise GDALException("invalid field name: %s" % field_name)
return [feat.get(field_name) for feat in self]
def get_geoms(self, geos=False):
@@ -200,6 +214,7 @@ class Layer(GDALBase):
"""
if geos:
from django.contrib.gis.geos import GEOSGeometry
+
return [GEOSGeometry(feat.geom.wkb) for feat in self]
else:
return [feat.geom for feat in self]
diff --git a/django/contrib/gis/gdal/libgdal.py b/django/contrib/gis/gdal/libgdal.py
index 3ff82ef086..2cb8329451 100644
--- a/django/contrib/gis/gdal/libgdal.py
+++ b/django/contrib/gis/gdal/libgdal.py
@@ -7,29 +7,41 @@ from ctypes.util import find_library
from django.contrib.gis.gdal.error import GDALException
from django.core.exceptions import ImproperlyConfigured
-logger = logging.getLogger('django.contrib.gis')
+logger = logging.getLogger("django.contrib.gis")
# Custom library path set?
try:
from django.conf import settings
+
lib_path = settings.GDAL_LIBRARY_PATH
except (AttributeError, ImportError, ImproperlyConfigured, OSError):
lib_path = None
if lib_path:
lib_names = None
-elif os.name == 'nt':
+elif os.name == "nt":
# Windows NT shared libraries
lib_names = [
- 'gdal303', 'gdal302', 'gdal301', 'gdal300',
- 'gdal204', 'gdal203', 'gdal202',
+ "gdal303",
+ "gdal302",
+ "gdal301",
+ "gdal300",
+ "gdal204",
+ "gdal203",
+ "gdal202",
]
-elif os.name == 'posix':
+elif os.name == "posix":
# *NIX library names.
lib_names = [
- 'gdal', 'GDAL',
- 'gdal3.3.0', 'gdal3.2.0', 'gdal3.1.0', 'gdal3.0.0',
- 'gdal2.4.0', 'gdal2.3.0', 'gdal2.2.0',
+ "gdal",
+ "GDAL",
+ "gdal3.3.0",
+ "gdal3.2.0",
+ "gdal3.1.0",
+ "gdal3.0.0",
+ "gdal2.4.0",
+ "gdal2.3.0",
+ "gdal2.2.0",
]
else:
raise ImproperlyConfigured('GDAL is unsupported on OS "%s".' % os.name)
@@ -45,7 +57,7 @@ if lib_names:
if lib_path is None:
raise ImproperlyConfigured(
'Could not find the GDAL library (tried "%s"). Is GDAL installed? '
- 'If it is, try setting GDAL_LIBRARY_PATH in your settings.'
+ "If it is, try setting GDAL_LIBRARY_PATH in your settings."
% '", "'.join(lib_names)
)
@@ -56,8 +68,9 @@ lgdal = CDLL(lib_path)
# STDCALL, while others are not. Thus, the library will also need to
# be loaded up as WinDLL for said OSR functions that require the
# different calling convention.
-if os.name == 'nt':
+if os.name == "nt":
from ctypes import WinDLL
+
lwingdal = WinDLL(lib_path)
@@ -66,7 +79,7 @@ def std_call(func):
Return the correct STDCALL function for certain OSR routines on Win32
platforms.
"""
- if os.name == 'nt':
+ if os.name == "nt":
return lwingdal[func]
else:
return lgdal[func]
@@ -75,24 +88,24 @@ def std_call(func):
# #### Version-information functions. ####
# Return GDAL library version information with the given key.
-_version_info = std_call('GDALVersionInfo')
+_version_info = std_call("GDALVersionInfo")
_version_info.argtypes = [c_char_p]
_version_info.restype = c_char_p
def gdal_version():
"Return only the GDAL version number information."
- return _version_info(b'RELEASE_NAME')
+ return _version_info(b"RELEASE_NAME")
def gdal_full_version():
"Return the full GDAL version information."
- return _version_info(b'')
+ return _version_info(b"")
def gdal_version_info():
ver = gdal_version()
- m = re.match(br'^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<subminor>\d+))?', ver)
+ m = re.match(rb"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<subminor>\d+))?", ver)
if not m:
raise GDALException('Could not parse GDAL version string "%s"' % ver)
major, minor, subminor = m.groups()
@@ -106,7 +119,7 @@ CPLErrorHandler = CFUNCTYPE(None, c_int, c_int, c_char_p)
def err_handler(error_class, error_number, message):
- logger.error('GDAL_ERROR %d: %s', error_number, message)
+ logger.error("GDAL_ERROR %d: %s", error_number, message)
err_handler = CPLErrorHandler(err_handler)
@@ -119,5 +132,5 @@ def function(name, args, restype):
return func
-set_error_handler = function('CPLSetErrorHandler', [CPLErrorHandler], CPLErrorHandler)
+set_error_handler = function("CPLSetErrorHandler", [CPLErrorHandler], CPLErrorHandler)
set_error_handler(err_handler)
diff --git a/django/contrib/gis/gdal/prototypes/ds.py b/django/contrib/gis/gdal/prototypes/ds.py
index 0729ab3386..bc5250e2db 100644
--- a/django/contrib/gis/gdal/prototypes/ds.py
+++ b/django/contrib/gis/gdal/prototypes/ds.py
@@ -8,8 +8,15 @@ 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.prototypes.generation import (
- bool_output, const_string_output, double_output, geom_output, int64_output,
- int_output, srs_output, void_output, voidptr_output,
+ bool_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
@@ -18,9 +25,13 @@ c_int_p = POINTER(c_int) # shortcut type
register_all = void_output(lgdal.OGRRegisterAll, [], errcheck=False)
cleanup_all = void_output(lgdal.OGRCleanupAll, [], errcheck=False)
get_driver = voidptr_output(lgdal.OGRGetDriver, [c_int])
-get_driver_by_name = voidptr_output(lgdal.OGRGetDriverByName, [c_char_p], errcheck=False)
+get_driver_by_name = voidptr_output(
+ lgdal.OGRGetDriverByName, [c_char_p], errcheck=False
+)
get_driver_count = int_output(lgdal.OGRGetDriverCount, [])
-get_driver_name = const_string_output(lgdal.OGR_Dr_GetName, [c_void_p], decoding='ascii')
+get_driver_name = const_string_output(
+ lgdal.OGR_Dr_GetName, [c_void_p], decoding="ascii"
+)
# DataSource
open_ds = voidptr_output(lgdal.OGROpen, [c_char_p, c_int, POINTER(c_void_p)])
@@ -41,10 +52,13 @@ get_next_feature = voidptr_output(lgdal.OGR_L_GetNextFeature, [c_void_p])
reset_reading = void_output(lgdal.OGR_L_ResetReading, [c_void_p], errcheck=False)
test_capability = int_output(lgdal.OGR_L_TestCapability, [c_void_p, c_char_p])
get_spatial_filter = geom_output(lgdal.OGR_L_GetSpatialFilter, [c_void_p])
-set_spatial_filter = void_output(lgdal.OGR_L_SetSpatialFilter, [c_void_p, c_void_p], errcheck=False)
+set_spatial_filter = void_output(
+ lgdal.OGR_L_SetSpatialFilter, [c_void_p, c_void_p], errcheck=False
+)
set_spatial_filter_rect = void_output(
lgdal.OGR_L_SetSpatialFilterRect,
- [c_void_p, c_double, c_double, c_double, c_double], errcheck=False
+ [c_void_p, c_double, c_double, c_double, c_double],
+ errcheck=False,
)
# Feature Definition Routines
@@ -64,13 +78,17 @@ get_feat_field_defn = voidptr_output(lgdal.OGR_F_GetFieldDefnRef, [c_void_p, c_i
get_fid = int_output(lgdal.OGR_F_GetFID, [c_void_p])
get_field_as_datetime = int_output(
lgdal.OGR_F_GetFieldAsDateTime,
- [c_void_p, c_int, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p]
+ [c_void_p, c_int, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p],
)
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])
-get_field_as_integer64 = int64_output(lgdal.OGR_F_GetFieldAsInteger64, [c_void_p, c_int])
+get_field_as_integer64 = int64_output(
+ lgdal.OGR_F_GetFieldAsInteger64, [c_void_p, c_int]
+)
is_field_set = bool_output(lgdal.OGR_F_IsFieldSetAndNotNull, [c_void_p, c_int])
-get_field_as_string = const_string_output(lgdal.OGR_F_GetFieldAsString, [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])
# Field Routines
diff --git a/django/contrib/gis/gdal/prototypes/errcheck.py b/django/contrib/gis/gdal/prototypes/errcheck.py
index 405f2e7070..52bb7cb083 100644
--- a/django/contrib/gis/gdal/prototypes/errcheck.py
+++ b/django/contrib/gis/gdal/prototypes/errcheck.py
@@ -4,9 +4,7 @@
"""
from ctypes import c_void_p, string_at
-from django.contrib.gis.gdal.error import (
- GDALException, SRSException, check_err,
-)
+from django.contrib.gis.gdal.error import GDALException, SRSException, check_err
from django.contrib.gis.gdal.libgdal import lgdal
@@ -63,6 +61,7 @@ def check_string(result, func, cargs, offset=-1, str_result=False):
lgdal.VSIFree(ptr)
return s
+
# ### DataSource, Layer error-checking ###
@@ -80,7 +79,9 @@ def check_geom(result, func, cargs):
if isinstance(result, int):
result = c_void_p(result)
if not result:
- raise GDALException('Invalid geometry pointer returned from "%s".' % func.__name__)
+ raise GDALException(
+ 'Invalid geometry pointer returned from "%s".' % func.__name__
+ )
return result
@@ -96,7 +97,9 @@ def check_srs(result, func, cargs):
if isinstance(result, int):
result = c_void_p(result)
if not result:
- raise SRSException('Invalid spatial reference pointer returned from "%s".' % func.__name__)
+ raise SRSException(
+ 'Invalid spatial reference pointer returned from "%s".' % func.__name__
+ )
return result
diff --git a/django/contrib/gis/gdal/prototypes/generation.py b/django/contrib/gis/gdal/prototypes/generation.py
index 0b26585161..230e56f665 100644
--- a/django/contrib/gis/gdal/prototypes/generation.py
+++ b/django/contrib/gis/gdal/prototypes/generation.py
@@ -2,14 +2,19 @@
This module contains functions that generate ctypes prototypes for the
GDAL routines.
"""
-from ctypes import (
- POINTER, c_bool, c_char_p, c_double, c_int, c_int64, c_void_p,
-)
+from ctypes import POINTER, c_bool, c_char_p, c_double, c_int, c_int64, c_void_p
from functools import partial
from django.contrib.gis.gdal.prototypes.errcheck import (
- check_arg_errcode, check_const_string, check_errcode, check_geom,
- check_geom_offset, check_pointer, check_srs, check_str_arg, check_string,
+ check_arg_errcode,
+ check_const_string,
+ check_errcode,
+ check_geom,
+ check_geom_offset,
+ check_pointer,
+ check_srs,
+ check_str_arg,
+ check_string,
)
@@ -55,6 +60,7 @@ def geom_output(func, argtypes, offset=None):
def geomerrcheck(result, func, cargs):
return check_geom_offset(result, func, cargs, offset)
+
func.errcheck = geomerrcheck
return func
@@ -100,6 +106,7 @@ def const_string_output(func, argtypes, offset=None, decoding=None, cpl=False):
if res and decoding:
res = res.decode(decoding)
return res
+
func.errcheck = _check_const
return func
@@ -129,6 +136,7 @@ def string_output(func, argtypes, offset=-1, str_result=False, decoding=None):
if res and decoding:
res = res.decode(decoding)
return res
+
func.errcheck = _check_str
return func
diff --git a/django/contrib/gis/gdal/prototypes/geom.py b/django/contrib/gis/gdal/prototypes/geom.py
index f7745f552f..06c2a75f3a 100644
--- a/django/contrib/gis/gdal/prototypes/geom.py
+++ b/django/contrib/gis/gdal/prototypes/geom.py
@@ -4,8 +4,13 @@ from django.contrib.gis.gdal.envelope import OGREnvelope
from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.prototypes.errcheck import check_envelope
from django.contrib.gis.gdal.prototypes.generation import (
- const_string_output, double_output, geom_output, int_output, srs_output,
- string_output, void_output,
+ const_string_output,
+ double_output,
+ geom_output,
+ int_output,
+ srs_output,
+ string_output,
+ void_output,
)
@@ -34,8 +39,12 @@ def topology_func(f):
# GeoJSON routines.
from_json = geom_output(lgdal.OGR_G_CreateGeometryFromJson, [c_char_p])
-to_json = string_output(lgdal.OGR_G_ExportToJson, [c_void_p], str_result=True, decoding='ascii')
-to_kml = string_output(lgdal.OGR_G_ExportToKML, [c_void_p, c_char_p], str_result=True, decoding='ascii')
+to_json = string_output(
+ lgdal.OGR_G_ExportToJson, [c_void_p], str_result=True, decoding="ascii"
+)
+to_kml = string_output(
+ lgdal.OGR_G_ExportToKML, [c_void_p, c_char_p], str_result=True, decoding="ascii"
+)
# GetX, GetY, GetZ all return doubles.
getx = pnt_func(lgdal.OGR_G_GetX)
@@ -43,8 +52,14 @@ gety = pnt_func(lgdal.OGR_G_GetY)
getz = pnt_func(lgdal.OGR_G_GetZ)
# Geometry creation routines.
-from_wkb = geom_output(lgdal.OGR_G_CreateFromWkb, [c_char_p, c_void_p, POINTER(c_void_p), c_int], offset=-2)
-from_wkt = geom_output(lgdal.OGR_G_CreateFromWkt, [POINTER(c_char_p), c_void_p, POINTER(c_void_p)], offset=-1)
+from_wkb = geom_output(
+ lgdal.OGR_G_CreateFromWkb, [c_char_p, c_void_p, POINTER(c_void_p), c_int], offset=-2
+)
+from_wkt = geom_output(
+ lgdal.OGR_G_CreateFromWkt,
+ [POINTER(c_char_p), c_void_p, POINTER(c_void_p)],
+ offset=-1,
+)
from_gml = geom_output(lgdal.OGR_G_CreateFromGML, [c_char_p])
create_geom = geom_output(lgdal.OGR_G_CreateGeometry, [c_int])
clone_geom = geom_output(lgdal.OGR_G_Clone, [c_void_p])
@@ -64,13 +79,21 @@ import_wkt = void_output(lgdal.OGR_G_ImportFromWkt, [c_void_p, POINTER(c_char_p)
destroy_geom = void_output(lgdal.OGR_G_DestroyGeometry, [c_void_p], errcheck=False)
# Geometry export routines.
-to_wkb = void_output(lgdal.OGR_G_ExportToWkb, None, errcheck=True) # special handling for WKB.
-to_wkt = string_output(lgdal.OGR_G_ExportToWkt, [c_void_p, POINTER(c_char_p)], decoding='ascii')
-to_gml = string_output(lgdal.OGR_G_ExportToGML, [c_void_p], str_result=True, decoding='ascii')
+to_wkb = void_output(
+ lgdal.OGR_G_ExportToWkb, None, errcheck=True
+) # special handling for WKB.
+to_wkt = string_output(
+ lgdal.OGR_G_ExportToWkt, [c_void_p, POINTER(c_char_p)], decoding="ascii"
+)
+to_gml = string_output(
+ lgdal.OGR_G_ExportToGML, [c_void_p], str_result=True, decoding="ascii"
+)
get_wkbsize = int_output(lgdal.OGR_G_WkbSize, [c_void_p])
# Geometry spatial-reference related routines.
-assign_srs = void_output(lgdal.OGR_G_AssignSpatialReference, [c_void_p, c_void_p], errcheck=False)
+assign_srs = void_output(
+ lgdal.OGR_G_AssignSpatialReference, [c_void_p, c_void_p], errcheck=False
+)
get_geom_srs = srs_output(lgdal.OGR_G_GetSpatialReference, [c_void_p])
# Geometry properties
@@ -78,16 +101,23 @@ get_area = double_output(lgdal.OGR_G_GetArea, [c_void_p])
get_centroid = void_output(lgdal.OGR_G_Centroid, [c_void_p, c_void_p])
get_dims = int_output(lgdal.OGR_G_GetDimension, [c_void_p])
get_coord_dim = int_output(lgdal.OGR_G_GetCoordinateDimension, [c_void_p])
-set_coord_dim = void_output(lgdal.OGR_G_SetCoordinateDimension, [c_void_p, c_int], errcheck=False)
-is_empty = int_output(lgdal.OGR_G_IsEmpty, [c_void_p], errcheck=lambda result, func, cargs: bool(result))
+set_coord_dim = void_output(
+ lgdal.OGR_G_SetCoordinateDimension, [c_void_p, c_int], errcheck=False
+)
+is_empty = int_output(
+ lgdal.OGR_G_IsEmpty, [c_void_p], errcheck=lambda result, func, cargs: bool(result)
+)
get_geom_count = int_output(lgdal.OGR_G_GetGeometryCount, [c_void_p])
-get_geom_name = const_string_output(lgdal.OGR_G_GetGeometryName, [c_void_p], decoding='ascii')
+get_geom_name = const_string_output(
+ lgdal.OGR_G_GetGeometryName, [c_void_p], decoding="ascii"
+)
get_geom_type = int_output(lgdal.OGR_G_GetGeometryType, [c_void_p])
get_point_count = int_output(lgdal.OGR_G_GetPointCount, [c_void_p])
get_point = void_output(
lgdal.OGR_G_GetPoint,
- [c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double)], errcheck=False
+ [c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double)],
+ errcheck=False,
)
geom_close_rings = void_output(lgdal.OGR_G_CloseRings, [c_void_p], errcheck=False)
diff --git a/django/contrib/gis/gdal/prototypes/raster.py b/django/contrib/gis/gdal/prototypes/raster.py
index 3fc9446ce8..59b930cb02 100644
--- a/django/contrib/gis/gdal/prototypes/raster.py
+++ b/django/contrib/gis/gdal/prototypes/raster.py
@@ -7,8 +7,12 @@ from functools import partial
from django.contrib.gis.gdal.libgdal import std_call
from django.contrib.gis.gdal.prototypes.generation import (
- chararray_output, const_string_output, double_output, int_output,
- void_output, voidptr_output,
+ chararray_output,
+ const_string_output,
+ double_output,
+ int_output,
+ void_output,
+ voidptr_output,
)
# For more detail about c function names and definitions see
@@ -22,80 +26,152 @@ const_string_output = partial(const_string_output, cpl=True)
double_output = partial(double_output, cpl=True)
# Raster Driver Routines
-register_all = void_output(std_call('GDALAllRegister'), [], errcheck=False)
-get_driver = voidptr_output(std_call('GDALGetDriver'), [c_int])
-get_driver_by_name = voidptr_output(std_call('GDALGetDriverByName'), [c_char_p], errcheck=False)
-get_driver_count = int_output(std_call('GDALGetDriverCount'), [])
-get_driver_description = const_string_output(std_call('GDALGetDescription'), [c_void_p])
+register_all = void_output(std_call("GDALAllRegister"), [], errcheck=False)
+get_driver = voidptr_output(std_call("GDALGetDriver"), [c_int])
+get_driver_by_name = voidptr_output(
+ std_call("GDALGetDriverByName"), [c_char_p], errcheck=False
+)
+get_driver_count = int_output(std_call("GDALGetDriverCount"), [])
+get_driver_description = const_string_output(std_call("GDALGetDescription"), [c_void_p])
# 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], errcheck=False)
-flush_ds = int_output(std_call('GDALFlushCache'), [c_void_p])
+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], errcheck=False)
+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]
-)
-add_band_ds = void_output(std_call('GDALAddBand'), [c_void_p, c_int])
-get_ds_description = const_string_output(std_call('GDALGetDescription'), [c_void_p])
-get_ds_driver = voidptr_output(std_call('GDALGetDatasetDriver'), [c_void_p])
-get_ds_info = const_string_output(std_call('GDALInfo'), [c_void_p, c_void_p])
-get_ds_xsize = int_output(std_call('GDALGetRasterXSize'), [c_void_p])
-get_ds_ysize = int_output(std_call('GDALGetRasterYSize'), [c_void_p])
-get_ds_raster_count = int_output(std_call('GDALGetRasterCount'), [c_void_p])
-get_ds_raster_band = voidptr_output(std_call('GDALGetRasterBand'), [c_void_p, c_int])
-get_ds_projection_ref = const_string_output(std_call('GDALGetProjectionRef'), [c_void_p])
-set_ds_projection_ref = void_output(std_call('GDALSetProjection'), [c_void_p, c_char_p])
-get_ds_geotransform = void_output(std_call('GDALGetGeoTransform'), [c_void_p, POINTER(c_double * 6)], errcheck=False)
-set_ds_geotransform = void_output(std_call('GDALSetGeoTransform'), [c_void_p, POINTER(c_double * 6)])
+ std_call("GDALCreateCopy"),
+ [c_void_p, c_char_p, c_void_p, c_int, POINTER(c_char_p), c_void_p, c_void_p],
+)
+add_band_ds = void_output(std_call("GDALAddBand"), [c_void_p, c_int])
+get_ds_description = const_string_output(std_call("GDALGetDescription"), [c_void_p])
+get_ds_driver = voidptr_output(std_call("GDALGetDatasetDriver"), [c_void_p])
+get_ds_info = const_string_output(std_call("GDALInfo"), [c_void_p, c_void_p])
+get_ds_xsize = int_output(std_call("GDALGetRasterXSize"), [c_void_p])
+get_ds_ysize = int_output(std_call("GDALGetRasterYSize"), [c_void_p])
+get_ds_raster_count = int_output(std_call("GDALGetRasterCount"), [c_void_p])
+get_ds_raster_band = voidptr_output(std_call("GDALGetRasterBand"), [c_void_p, c_int])
+get_ds_projection_ref = const_string_output(
+ std_call("GDALGetProjectionRef"), [c_void_p]
+)
+set_ds_projection_ref = void_output(std_call("GDALSetProjection"), [c_void_p, c_char_p])
+get_ds_geotransform = void_output(
+ std_call("GDALGetGeoTransform"), [c_void_p, POINTER(c_double * 6)], errcheck=False
+)
+set_ds_geotransform = void_output(
+ std_call("GDALSetGeoTransform"), [c_void_p, POINTER(c_double * 6)]
+)
-get_ds_metadata = chararray_output(std_call('GDALGetMetadata'), [c_void_p, c_char_p], errcheck=False)
-set_ds_metadata = void_output(std_call('GDALSetMetadata'), [c_void_p, POINTER(c_char_p), c_char_p])
-get_ds_metadata_domain_list = chararray_output(std_call('GDALGetMetadataDomainList'), [c_void_p], errcheck=False)
-get_ds_metadata_item = const_string_output(std_call('GDALGetMetadataItem'), [c_void_p, c_char_p, c_char_p])
-set_ds_metadata_item = const_string_output(std_call('GDALSetMetadataItem'), [c_void_p, c_char_p, c_char_p, c_char_p])
-free_dsl = void_output(std_call('CSLDestroy'), [POINTER(c_char_p)], errcheck=False)
+get_ds_metadata = chararray_output(
+ std_call("GDALGetMetadata"), [c_void_p, c_char_p], errcheck=False
+)
+set_ds_metadata = void_output(
+ std_call("GDALSetMetadata"), [c_void_p, POINTER(c_char_p), c_char_p]
+)
+get_ds_metadata_domain_list = chararray_output(
+ std_call("GDALGetMetadataDomainList"), [c_void_p], errcheck=False
+)
+get_ds_metadata_item = const_string_output(
+ std_call("GDALGetMetadataItem"), [c_void_p, c_char_p, c_char_p]
+)
+set_ds_metadata_item = const_string_output(
+ std_call("GDALSetMetadataItem"), [c_void_p, c_char_p, c_char_p, c_char_p]
+)
+free_dsl = void_output(std_call("CSLDestroy"), [POINTER(c_char_p)], errcheck=False)
# Raster Band Routines
band_io = void_output(
- std_call('GDALRasterIO'),
- [c_void_p, c_int, c_int, c_int, c_int, c_int, c_void_p, c_int, c_int, c_int, c_int, c_int]
-)
-get_band_xsize = int_output(std_call('GDALGetRasterBandXSize'), [c_void_p])
-get_band_ysize = int_output(std_call('GDALGetRasterBandYSize'), [c_void_p])
-get_band_index = int_output(std_call('GDALGetBandNumber'), [c_void_p])
-get_band_description = const_string_output(std_call('GDALGetDescription'), [c_void_p])
-get_band_ds = voidptr_output(std_call('GDALGetBandDataset'), [c_void_p])
-get_band_datatype = int_output(std_call('GDALGetRasterDataType'), [c_void_p])
-get_band_color_interp = int_output(std_call('GDALGetRasterColorInterpretation'), [c_void_p])
-get_band_nodata_value = double_output(std_call('GDALGetRasterNoDataValue'), [c_void_p, POINTER(c_int)])
-set_band_nodata_value = void_output(std_call('GDALSetRasterNoDataValue'), [c_void_p, c_double])
-delete_band_nodata_value = void_output(std_call('GDALDeleteRasterNoDataValue'), [c_void_p])
+ std_call("GDALRasterIO"),
+ [
+ c_void_p,
+ c_int,
+ c_int,
+ c_int,
+ c_int,
+ c_int,
+ c_void_p,
+ c_int,
+ c_int,
+ c_int,
+ c_int,
+ c_int,
+ ],
+)
+get_band_xsize = int_output(std_call("GDALGetRasterBandXSize"), [c_void_p])
+get_band_ysize = int_output(std_call("GDALGetRasterBandYSize"), [c_void_p])
+get_band_index = int_output(std_call("GDALGetBandNumber"), [c_void_p])
+get_band_description = const_string_output(std_call("GDALGetDescription"), [c_void_p])
+get_band_ds = voidptr_output(std_call("GDALGetBandDataset"), [c_void_p])
+get_band_datatype = int_output(std_call("GDALGetRasterDataType"), [c_void_p])
+get_band_color_interp = int_output(
+ std_call("GDALGetRasterColorInterpretation"), [c_void_p]
+)
+get_band_nodata_value = double_output(
+ std_call("GDALGetRasterNoDataValue"), [c_void_p, POINTER(c_int)]
+)
+set_band_nodata_value = void_output(
+ std_call("GDALSetRasterNoDataValue"), [c_void_p, c_double]
+)
+delete_band_nodata_value = void_output(
+ std_call("GDALDeleteRasterNoDataValue"), [c_void_p]
+)
get_band_statistics = void_output(
- std_call('GDALGetRasterStatistics'),
+ std_call("GDALGetRasterStatistics"),
[
- c_void_p, c_int, c_int, POINTER(c_double), POINTER(c_double),
- POINTER(c_double), POINTER(c_double), c_void_p, c_void_p,
+ c_void_p,
+ c_int,
+ c_int,
+ POINTER(c_double),
+ POINTER(c_double),
+ POINTER(c_double),
+ POINTER(c_double),
+ c_void_p,
+ c_void_p,
],
)
compute_band_statistics = void_output(
- std_call('GDALComputeRasterStatistics'),
- [c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), c_void_p, c_void_p],
+ std_call("GDALComputeRasterStatistics"),
+ [
+ c_void_p,
+ c_int,
+ POINTER(c_double),
+ POINTER(c_double),
+ POINTER(c_double),
+ POINTER(c_double),
+ c_void_p,
+ c_void_p,
+ ],
)
# Reprojection routine
reproject_image = void_output(
- std_call('GDALReprojectImage'),
- [c_void_p, c_char_p, c_void_p, c_char_p, c_int, c_double, c_double, c_void_p, c_void_p, c_void_p]
+ std_call("GDALReprojectImage"),
+ [
+ c_void_p,
+ c_char_p,
+ c_void_p,
+ c_char_p,
+ c_int,
+ c_double,
+ c_double,
+ c_void_p,
+ c_void_p,
+ c_void_p,
+ ],
)
auto_create_warped_vrt = voidptr_output(
- std_call('GDALAutoCreateWarpedVRT'),
- [c_void_p, c_char_p, c_char_p, c_int, c_double, c_void_p]
+ std_call("GDALAutoCreateWarpedVRT"),
+ [c_void_p, c_char_p, c_char_p, c_int, c_double, c_void_p],
)
# Create VSI gdal raster files from in-memory buffers.
# https://gdal.org/api/cpl.html#cpl-vsi-h
-create_vsi_file_from_mem_buffer = voidptr_output(std_call('VSIFileFromMemBuffer'), [c_char_p, c_void_p, c_int, c_int])
-get_mem_buffer_from_vsi_file = voidptr_output(std_call('VSIGetMemFileBuffer'), [c_char_p, POINTER(c_int), c_bool])
-unlink_vsi_file = int_output(std_call('VSIUnlink'), [c_char_p])
+create_vsi_file_from_mem_buffer = voidptr_output(
+ std_call("VSIFileFromMemBuffer"), [c_char_p, c_void_p, c_int, c_int]
+)
+get_mem_buffer_from_vsi_file = voidptr_output(
+ std_call("VSIGetMemFileBuffer"), [c_char_p, POINTER(c_int), c_bool]
+)
+unlink_vsi_file = int_output(std_call("VSIUnlink"), [c_char_p])
diff --git a/django/contrib/gis/gdal/prototypes/srs.py b/django/contrib/gis/gdal/prototypes/srs.py
index c392b7bf2a..721eba8622 100644
--- a/django/contrib/gis/gdal/prototypes/srs.py
+++ b/django/contrib/gis/gdal/prototypes/srs.py
@@ -2,7 +2,11 @@ from ctypes import POINTER, c_char_p, c_int, c_void_p
from django.contrib.gis.gdal.libgdal import GDAL_VERSION, lgdal, std_call
from django.contrib.gis.gdal.prototypes.generation import (
- const_string_output, double_output, int_output, srs_output, string_output,
+ const_string_output,
+ double_output,
+ int_output,
+ srs_output,
+ string_output,
void_output,
)
@@ -25,14 +29,18 @@ def units_func(f):
# Creation & destruction.
-clone_srs = srs_output(std_call('OSRClone'), [c_void_p])
-new_srs = srs_output(std_call('OSRNewSpatialReference'), [c_char_p])
+clone_srs = srs_output(std_call("OSRClone"), [c_void_p])
+new_srs = srs_output(std_call("OSRNewSpatialReference"), [c_char_p])
release_srs = void_output(lgdal.OSRRelease, [c_void_p], errcheck=False)
-destroy_srs = void_output(std_call('OSRDestroySpatialReference'), [c_void_p], errcheck=False)
+destroy_srs = void_output(
+ std_call("OSRDestroySpatialReference"), [c_void_p], errcheck=False
+)
srs_validate = void_output(lgdal.OSRValidate, [c_void_p])
if GDAL_VERSION >= (3, 0):
- set_axis_strategy = void_output(lgdal.OSRSetAxisMappingStrategy, [c_void_p, c_int], errcheck=False)
+ set_axis_strategy = void_output(
+ lgdal.OSRSetAxisMappingStrategy, [c_void_p, c_int], errcheck=False
+ )
# Getting the semi_major, semi_minor, and flattening functions.
semi_major = srs_double(lgdal.OSRGetSemiMajor)
@@ -42,9 +50,9 @@ invflattening = srs_double(lgdal.OSRGetInvFlattening)
# WKT, PROJ, EPSG, XML importation routines.
from_wkt = void_output(lgdal.OSRImportFromWkt, [c_void_p, POINTER(c_char_p)])
from_proj = void_output(lgdal.OSRImportFromProj4, [c_void_p, c_char_p])
-from_epsg = void_output(std_call('OSRImportFromEPSG'), [c_void_p, c_int])
+from_epsg = void_output(std_call("OSRImportFromEPSG"), [c_void_p, c_int])
from_xml = void_output(lgdal.OSRImportFromXML, [c_void_p, c_char_p])
-from_user_input = void_output(std_call('OSRSetFromUserInput'), [c_void_p, c_char_p])
+from_user_input = void_output(std_call("OSRSetFromUserInput"), [c_void_p, c_char_p])
# Morphing to/from ESRI WKT.
morph_to_esri = void_output(lgdal.OSRMorphToESRI, [c_void_p])
@@ -58,19 +66,36 @@ linear_units = units_func(lgdal.OSRGetLinearUnits)
angular_units = units_func(lgdal.OSRGetAngularUnits)
# For exporting to WKT, PROJ, "Pretty" WKT, and XML.
-to_wkt = string_output(std_call('OSRExportToWkt'), [c_void_p, POINTER(c_char_p)], decoding='utf-8')
-to_proj = string_output(std_call('OSRExportToProj4'), [c_void_p, POINTER(c_char_p)], decoding='ascii')
+to_wkt = string_output(
+ std_call("OSRExportToWkt"), [c_void_p, POINTER(c_char_p)], decoding="utf-8"
+)
+to_proj = string_output(
+ std_call("OSRExportToProj4"), [c_void_p, POINTER(c_char_p)], decoding="ascii"
+)
to_pretty_wkt = string_output(
- std_call('OSRExportToPrettyWkt'),
- [c_void_p, POINTER(c_char_p), c_int], offset=-2, decoding='utf-8'
+ std_call("OSRExportToPrettyWkt"),
+ [c_void_p, POINTER(c_char_p), c_int],
+ offset=-2,
+ decoding="utf-8",
)
-to_xml = string_output(lgdal.OSRExportToXML, [c_void_p, POINTER(c_char_p), c_char_p], offset=-2, decoding='utf-8')
+to_xml = string_output(
+ lgdal.OSRExportToXML,
+ [c_void_p, POINTER(c_char_p), c_char_p],
+ offset=-2,
+ decoding="utf-8",
+)
# String attribute retrieval routines.
-get_attr_value = const_string_output(std_call('OSRGetAttrValue'), [c_void_p, c_char_p, c_int], decoding='utf-8')
-get_auth_name = const_string_output(lgdal.OSRGetAuthorityName, [c_void_p, c_char_p], decoding='ascii')
-get_auth_code = const_string_output(lgdal.OSRGetAuthorityCode, [c_void_p, c_char_p], decoding='ascii')
+get_attr_value = const_string_output(
+ std_call("OSRGetAttrValue"), [c_void_p, c_char_p, c_int], decoding="utf-8"
+)
+get_auth_name = const_string_output(
+ lgdal.OSRGetAuthorityName, [c_void_p, c_char_p], decoding="ascii"
+)
+get_auth_code = const_string_output(
+ lgdal.OSRGetAuthorityCode, [c_void_p, c_char_p], decoding="ascii"
+)
# SRS Properties
isgeographic = int_output(lgdal.OSRIsGeographic, [c_void_p])
@@ -78,5 +103,7 @@ islocal = int_output(lgdal.OSRIsLocal, [c_void_p])
isprojected = int_output(lgdal.OSRIsProjected, [c_void_p])
# Coordinate transformation
-new_ct = srs_output(std_call('OCTNewCoordinateTransformation'), [c_void_p, c_void_p])
-destroy_ct = void_output(std_call('OCTDestroyCoordinateTransformation'), [c_void_p], errcheck=False)
+new_ct = srs_output(std_call("OCTNewCoordinateTransformation"), [c_void_p, c_void_p])
+destroy_ct = void_output(
+ std_call("OCTDestroyCoordinateTransformation"), [c_void_p], errcheck=False
+)
diff --git a/django/contrib/gis/gdal/raster/band.py b/django/contrib/gis/gdal/raster/band.py
index 6739a52628..c3ec960643 100644
--- a/django/contrib/gis/gdal/raster/band.py
+++ b/django/contrib/gis/gdal/raster/band.py
@@ -7,7 +7,10 @@ from django.contrib.gis.shortcuts import numpy
from django.utils.encoding import force_str
from .const import (
- GDAL_COLOR_TYPES, GDAL_INTEGER_TYPES, GDAL_PIXEL_TYPES, GDAL_TO_CTYPES,
+ GDAL_COLOR_TYPES,
+ GDAL_INTEGER_TYPES,
+ GDAL_PIXEL_TYPES,
+ GDAL_TO_CTYPES,
)
@@ -15,6 +18,7 @@ class GDALBand(GDALRasterBase):
"""
Wrap a GDAL raster band, needs to be obtained from a GDALRaster object.
"""
+
def __init__(self, source, index):
self.source = source
self._ptr = capi.get_ds_raster_band(source._ptr, index)
@@ -79,8 +83,14 @@ class GDALBand(GDALRasterBase):
# Prepare array with arguments for capi function
smin, smax, smean, sstd = c_double(), c_double(), c_double(), c_double()
stats_args = [
- self._ptr, c_int(approximate), byref(smin), byref(smax),
- byref(smean), byref(sstd), c_void_p(), c_void_p(),
+ self._ptr,
+ c_int(approximate),
+ byref(smin),
+ byref(smax),
+ byref(smean),
+ byref(sstd),
+ c_void_p(),
+ c_void_p(),
]
if refresh or self._stats_refresh:
@@ -154,7 +164,7 @@ class GDALBand(GDALRasterBase):
if value is None:
capi.delete_band_nodata_value(self._ptr)
elif not isinstance(value, (int, float)):
- raise ValueError('Nodata value must be numeric or None.')
+ raise ValueError("Nodata value must be numeric or None.")
else:
capi.set_band_nodata_value(self._ptr, value)
self._flush()
@@ -188,10 +198,10 @@ class GDALBand(GDALRasterBase):
size = size or (self.width - offset[0], self.height - offset[1])
shape = shape or size
if any(x <= 0 for x in size):
- raise ValueError('Offset too big for this raster.')
+ raise ValueError("Offset too big for this raster.")
if size[0] > self.width or size[1] > self.height:
- raise ValueError('Size is larger than raster.')
+ raise ValueError("Size is larger than raster.")
# Create ctypes type array generator
ctypes_array = GDAL_TO_CTYPES[self.datatype()] * (shape[0] * shape[1])
@@ -206,15 +216,28 @@ class GDALBand(GDALRasterBase):
access_flag = 1
# Instantiate ctypes array holding the input data
- if isinstance(data, (bytes, memoryview)) or (numpy and isinstance(data, numpy.ndarray)):
+ if isinstance(data, (bytes, memoryview)) or (
+ numpy and isinstance(data, numpy.ndarray)
+ ):
data_array = ctypes_array.from_buffer_copy(data)
else:
data_array = ctypes_array(*data)
# Access band
- capi.band_io(self._ptr, access_flag, offset[0], offset[1],
- size[0], size[1], byref(data_array), shape[0],
- shape[1], self.datatype(), 0, 0)
+ capi.band_io(
+ self._ptr,
+ access_flag,
+ offset[0],
+ offset[1],
+ size[0],
+ size[1],
+ byref(data_array),
+ shape[0],
+ shape[1],
+ self.datatype(),
+ 0,
+ 0,
+ )
# Return data as numpy array if possible, otherwise as list
if data is None:
@@ -247,4 +270,4 @@ class BandList(list):
try:
return GDALBand(self.source, index + 1)
except GDALException:
- raise GDALException('Unable to get band index %d' % index)
+ raise GDALException("Unable to get band index %d" % index)
diff --git a/django/contrib/gis/gdal/raster/base.py b/django/contrib/gis/gdal/raster/base.py
index c5b438ee64..3d95c90dc7 100644
--- a/django/contrib/gis/gdal/raster/base.py
+++ b/django/contrib/gis/gdal/raster/base.py
@@ -6,6 +6,7 @@ class GDALRasterBase(GDALBase):
"""
Attributes that exist on both GDALRaster and GDALBand.
"""
+
@property
def metadata(self):
"""
@@ -15,7 +16,7 @@ class GDALRasterBase(GDALBase):
"""
# The initial metadata domain list contains the default domain.
# The default is returned if domain name is None.
- domain_list = ['DEFAULT']
+ domain_list = ["DEFAULT"]
# Get additional metadata domains from the raster.
meta_list = capi.get_ds_metadata_domain_list(self._ptr)
@@ -38,7 +39,7 @@ class GDALRasterBase(GDALBase):
# Get metadata for this domain.
data = capi.get_ds_metadata(
self._ptr,
- (None if domain == 'DEFAULT' else domain.encode()),
+ (None if domain == "DEFAULT" else domain.encode()),
)
if not data:
continue
@@ -48,12 +49,12 @@ class GDALRasterBase(GDALBase):
counter = 0
item = data[counter]
while item:
- key, val = item.decode().split('=')
+ key, val = item.decode().split("=")
domain_meta[key] = val
counter += 1
item = data[counter]
# The default domain values are returned if domain is None.
- result[domain or 'DEFAULT'] = domain_meta
+ result[domain or "DEFAULT"] = domain_meta
return result
@metadata.setter
@@ -65,11 +66,12 @@ class GDALRasterBase(GDALBase):
# Loop through domains.
for domain, metadata in value.items():
# Set the domain to None for the default, otherwise encode.
- domain = None if domain == 'DEFAULT' else domain.encode()
+ domain = None if domain == "DEFAULT" else domain.encode()
# Set each metadata entry separately.
for meta_name, meta_value in metadata.items():
capi.set_ds_metadata_item(
- self._ptr, meta_name.encode(),
+ self._ptr,
+ meta_name.encode(),
meta_value.encode() if meta_value else None,
domain,
)
diff --git a/django/contrib/gis/gdal/raster/const.py b/django/contrib/gis/gdal/raster/const.py
index c246a6a190..6d3761d9fb 100644
--- a/django/contrib/gis/gdal/raster/const.py
+++ b/django/contrib/gis/gdal/raster/const.py
@@ -1,24 +1,22 @@
"""
GDAL - Constant definitions
"""
-from ctypes import (
- c_double, c_float, c_int16, c_int32, c_ubyte, c_uint16, c_uint32,
-)
+from ctypes import c_double, c_float, c_int16, c_int32, c_ubyte, c_uint16, c_uint32
# See https://gdal.org/api/raster_c_api.html#_CPPv412GDALDataType
GDAL_PIXEL_TYPES = {
- 0: 'GDT_Unknown', # Unknown or unspecified type
- 1: 'GDT_Byte', # Eight bit unsigned integer
- 2: 'GDT_UInt16', # Sixteen bit unsigned integer
- 3: 'GDT_Int16', # Sixteen bit signed integer
- 4: 'GDT_UInt32', # Thirty-two bit unsigned integer
- 5: 'GDT_Int32', # Thirty-two bit signed integer
- 6: 'GDT_Float32', # Thirty-two bit floating point
- 7: 'GDT_Float64', # Sixty-four bit floating point
- 8: 'GDT_CInt16', # Complex Int16
- 9: 'GDT_CInt32', # Complex Int32
- 10: 'GDT_CFloat32', # Complex Float32
- 11: 'GDT_CFloat64', # Complex Float64
+ 0: "GDT_Unknown", # Unknown or unspecified type
+ 1: "GDT_Byte", # Eight bit unsigned integer
+ 2: "GDT_UInt16", # Sixteen bit unsigned integer
+ 3: "GDT_Int16", # Sixteen bit signed integer
+ 4: "GDT_UInt32", # Thirty-two bit unsigned integer
+ 5: "GDT_Int32", # Thirty-two bit signed integer
+ 6: "GDT_Float32", # Thirty-two bit floating point
+ 7: "GDT_Float64", # Sixty-four bit floating point
+ 8: "GDT_CInt16", # Complex Int16
+ 9: "GDT_CInt32", # Complex Int32
+ 10: "GDT_CFloat32", # Complex Float32
+ 11: "GDT_CFloat64", # Complex Float64
}
# A list of gdal datatypes that are integers.
@@ -29,47 +27,57 @@ GDAL_INTEGER_TYPES = [1, 2, 3, 4, 5]
# or to hold the space for data to be read into. The lookup below helps
# selecting the right ctypes object for a given gdal pixel type.
GDAL_TO_CTYPES = [
- None, c_ubyte, c_uint16, c_int16, c_uint32, c_int32,
- c_float, c_double, None, None, None, None
+ None,
+ c_ubyte,
+ c_uint16,
+ c_int16,
+ c_uint32,
+ c_int32,
+ c_float,
+ c_double,
+ None,
+ None,
+ None,
+ None,
]
# List of resampling algorithms that can be used to warp a GDALRaster.
GDAL_RESAMPLE_ALGORITHMS = {
- 'NearestNeighbour': 0,
- 'Bilinear': 1,
- 'Cubic': 2,
- 'CubicSpline': 3,
- 'Lanczos': 4,
- 'Average': 5,
- 'Mode': 6,
+ "NearestNeighbour": 0,
+ "Bilinear": 1,
+ "Cubic": 2,
+ "CubicSpline": 3,
+ "Lanczos": 4,
+ "Average": 5,
+ "Mode": 6,
}
# See https://gdal.org/api/raster_c_api.html#_CPPv415GDALColorInterp
GDAL_COLOR_TYPES = {
- 0: 'GCI_Undefined', # Undefined, default value, i.e. not known
- 1: 'GCI_GrayIndex', # Grayscale
- 2: 'GCI_PaletteIndex', # Paletted
- 3: 'GCI_RedBand', # Red band of RGBA image
- 4: 'GCI_GreenBand', # Green band of RGBA image
- 5: 'GCI_BlueBand', # Blue band of RGBA image
- 6: 'GCI_AlphaBand', # Alpha (0=transparent, 255=opaque)
- 7: 'GCI_HueBand', # Hue band of HLS image
- 8: 'GCI_SaturationBand', # Saturation band of HLS image
- 9: 'GCI_LightnessBand', # Lightness band of HLS image
- 10: 'GCI_CyanBand', # Cyan band of CMYK image
- 11: 'GCI_MagentaBand', # Magenta band of CMYK image
- 12: 'GCI_YellowBand', # Yellow band of CMYK image
- 13: 'GCI_BlackBand', # Black band of CMLY image
- 14: 'GCI_YCbCr_YBand', # Y Luminance
- 15: 'GCI_YCbCr_CbBand', # Cb Chroma
- 16: 'GCI_YCbCr_CrBand', # Cr Chroma, also GCI_Max
+ 0: "GCI_Undefined", # Undefined, default value, i.e. not known
+ 1: "GCI_GrayIndex", # Grayscale
+ 2: "GCI_PaletteIndex", # Paletted
+ 3: "GCI_RedBand", # Red band of RGBA image
+ 4: "GCI_GreenBand", # Green band of RGBA image
+ 5: "GCI_BlueBand", # Blue band of RGBA image
+ 6: "GCI_AlphaBand", # Alpha (0=transparent, 255=opaque)
+ 7: "GCI_HueBand", # Hue band of HLS image
+ 8: "GCI_SaturationBand", # Saturation band of HLS image
+ 9: "GCI_LightnessBand", # Lightness band of HLS image
+ 10: "GCI_CyanBand", # Cyan band of CMYK image
+ 11: "GCI_MagentaBand", # Magenta band of CMYK image
+ 12: "GCI_YellowBand", # Yellow band of CMYK image
+ 13: "GCI_BlackBand", # Black band of CMLY image
+ 14: "GCI_YCbCr_YBand", # Y Luminance
+ 15: "GCI_YCbCr_CbBand", # Cb Chroma
+ 16: "GCI_YCbCr_CrBand", # Cr Chroma, also GCI_Max
}
# GDAL virtual filesystems prefix.
-VSI_FILESYSTEM_PREFIX = '/vsi'
+VSI_FILESYSTEM_PREFIX = "/vsi"
# Fixed base path for buffer-based GDAL in-memory files.
-VSI_MEM_FILESYSTEM_BASE_PATH = '/vsimem/'
+VSI_MEM_FILESYSTEM_BASE_PATH = "/vsimem/"
# Should the memory file system take ownership of the buffer, freeing it when
# the file is deleted? (No, GDALRaster.__del__() will delete the buffer.)
diff --git a/django/contrib/gis/gdal/raster/source.py b/django/contrib/gis/gdal/raster/source.py
index 7c17b85925..ca7875752b 100644
--- a/django/contrib/gis/gdal/raster/source.py
+++ b/django/contrib/gis/gdal/raster/source.py
@@ -3,7 +3,14 @@ import os
import sys
import uuid
from ctypes import (
- addressof, byref, c_buffer, c_char_p, c_double, c_int, c_void_p, string_at,
+ addressof,
+ byref,
+ c_buffer,
+ c_char_p,
+ c_double,
+ c_int,
+ c_void_p,
+ string_at,
)
from django.contrib.gis.gdal.driver import Driver
@@ -12,8 +19,11 @@ from django.contrib.gis.gdal.prototypes import raster as capi
from django.contrib.gis.gdal.raster.band import BandList
from django.contrib.gis.gdal.raster.base import GDALRasterBase
from django.contrib.gis.gdal.raster.const import (
- GDAL_RESAMPLE_ALGORITHMS, VSI_DELETE_BUFFER_ON_READ, VSI_FILESYSTEM_PREFIX,
- VSI_MEM_FILESYSTEM_BASE_PATH, VSI_TAKE_BUFFER_OWNERSHIP,
+ GDAL_RESAMPLE_ALGORITHMS,
+ VSI_DELETE_BUFFER_ON_READ,
+ VSI_FILESYSTEM_PREFIX,
+ VSI_MEM_FILESYSTEM_BASE_PATH,
+ VSI_TAKE_BUFFER_OWNERSHIP,
)
from django.contrib.gis.gdal.srs import SpatialReference, SRSException
from django.contrib.gis.geometry import json_regex
@@ -23,9 +33,9 @@ from django.utils.functional import cached_property
class TransformPoint(list):
indices = {
- 'origin': (0, 3),
- 'scale': (1, 5),
- 'skew': (2, 4),
+ "origin": (0, 3),
+ "scale": (1, 5),
+ "skew": (2, 4),
}
def __init__(self, raster, prop):
@@ -60,6 +70,7 @@ class GDALRaster(GDALRasterBase):
"""
Wrap a raster GDAL Data Source object.
"""
+
destructor = capi.close_ds
def __init__(self, ds_input, write=False):
@@ -73,9 +84,8 @@ class GDALRaster(GDALRasterBase):
# If input is a valid file path, try setting file as source.
if isinstance(ds_input, str):
- if (
- not ds_input.startswith(VSI_FILESYSTEM_PREFIX) and
- not os.path.exists(ds_input)
+ if not ds_input.startswith(VSI_FILESYSTEM_PREFIX) and not os.path.exists(
+ ds_input
):
raise GDALException(
'Unable to read raster source input "%s".' % ds_input
@@ -84,7 +94,9 @@ class GDALRaster(GDALRasterBase):
# GDALOpen will auto-detect the data source type.
self._ptr = capi.open_ds(force_bytes(ds_input), self._write)
except GDALException as err:
- raise GDALException('Could not open the datasource at "{}" ({}).'.format(ds_input, err))
+ raise GDALException(
+ 'Could not open the datasource at "{}" ({}).'.format(ds_input, err)
+ )
elif isinstance(ds_input, bytes):
# Create a new raster in write mode.
self._write = 1
@@ -109,30 +121,36 @@ class GDALRaster(GDALRasterBase):
except GDALException:
# Remove the broken file from the VSI filesystem.
capi.unlink_vsi_file(force_bytes(vsi_path))
- raise GDALException('Failed creating VSI raster from the input buffer.')
+ raise GDALException("Failed creating VSI raster from the input buffer.")
elif isinstance(ds_input, dict):
# A new raster needs to be created in write mode
self._write = 1
# Create driver (in memory by default)
- driver = Driver(ds_input.get('driver', 'MEM'))
+ driver = Driver(ds_input.get("driver", "MEM"))
# For out of memory drivers, check filename argument
- if driver.name != 'MEM' and 'name' not in ds_input:
- raise GDALException('Specify name for creation of raster with driver "{}".'.format(driver.name))
+ if driver.name != "MEM" and "name" not in ds_input:
+ raise GDALException(
+ 'Specify name for creation of raster with driver "{}".'.format(
+ driver.name
+ )
+ )
# Check if width and height where specified
- if 'width' not in ds_input or 'height' not in ds_input:
- raise GDALException('Specify width and height attributes for JSON or dict input.')
+ if "width" not in ds_input or "height" not in ds_input:
+ raise GDALException(
+ "Specify width and height attributes for JSON or dict input."
+ )
# Check if srid was specified
- if 'srid' not in ds_input:
- raise GDALException('Specify srid for JSON or dict input.')
+ if "srid" not in ds_input:
+ raise GDALException("Specify srid for JSON or dict input.")
# Create null terminated gdal options array.
papsz_options = []
- for key, val in ds_input.get('papsz_options', {}).items():
- option = '{}={}'.format(key, val)
+ for key, val in ds_input.get("papsz_options", {}).items():
+ option = "{}={}".format(key, val)
papsz_options.append(option.upper().encode())
papsz_options.append(None)
@@ -142,51 +160,54 @@ class GDALRaster(GDALRasterBase):
# Create GDAL Raster
self._ptr = capi.create_ds(
driver._ptr,
- force_bytes(ds_input.get('name', '')),
- ds_input['width'],
- ds_input['height'],
- ds_input.get('nr_of_bands', len(ds_input.get('bands', []))),
- ds_input.get('datatype', 6),
+ force_bytes(ds_input.get("name", "")),
+ ds_input["width"],
+ ds_input["height"],
+ ds_input.get("nr_of_bands", len(ds_input.get("bands", []))),
+ ds_input.get("datatype", 6),
byref(papsz_options),
)
# Set band data if provided
- for i, band_input in enumerate(ds_input.get('bands', [])):
+ for i, band_input in enumerate(ds_input.get("bands", [])):
band = self.bands[i]
- if 'nodata_value' in band_input:
- band.nodata_value = band_input['nodata_value']
+ if "nodata_value" in band_input:
+ band.nodata_value = band_input["nodata_value"]
# Instantiate band filled with nodata values if only
# partial input data has been provided.
if band.nodata_value is not None and (
- 'data' not in band_input or
- 'size' in band_input or
- 'shape' in band_input):
+ "data" not in band_input
+ or "size" in band_input
+ or "shape" in band_input
+ ):
band.data(data=(band.nodata_value,), shape=(1, 1))
# Set band data values from input.
band.data(
- data=band_input.get('data'),
- size=band_input.get('size'),
- shape=band_input.get('shape'),
- offset=band_input.get('offset'),
+ data=band_input.get("data"),
+ size=band_input.get("size"),
+ shape=band_input.get("shape"),
+ offset=band_input.get("offset"),
)
# Set SRID
- self.srs = ds_input.get('srid')
+ self.srs = ds_input.get("srid")
# Set additional properties if provided
- if 'origin' in ds_input:
- self.origin.x, self.origin.y = ds_input['origin']
+ if "origin" in ds_input:
+ self.origin.x, self.origin.y = ds_input["origin"]
- if 'scale' in ds_input:
- self.scale.x, self.scale.y = ds_input['scale']
+ if "scale" in ds_input:
+ self.scale.x, self.scale.y = ds_input["scale"]
- if 'skew' in ds_input:
- self.skew.x, self.skew.y = ds_input['skew']
+ if "skew" in ds_input:
+ self.skew.x, self.skew.y = ds_input["skew"]
elif isinstance(ds_input, c_void_p):
# Instantiate the object using an existing pointer to a gdal raster.
self._ptr = ds_input
else:
- raise GDALException('Invalid data source input type: "{}".'.format(type(ds_input)))
+ raise GDALException(
+ 'Invalid data source input type: "{}".'.format(type(ds_input))
+ )
def __del__(self):
if self.is_vsi_based:
@@ -201,7 +222,7 @@ class GDALRaster(GDALRasterBase):
"""
Short-hand representation because WKB may be very large.
"""
- return '<Raster object at %s>' % hex(addressof(self._ptr))
+ return "<Raster object at %s>" % hex(addressof(self._ptr))
def _flush(self):
"""
@@ -212,14 +233,15 @@ class GDALRaster(GDALRasterBase):
"""
# Raise an Exception if the value is being changed in read mode.
if not self._write:
- raise GDALException('Raster needs to be opened in write mode to change values.')
+ raise GDALException(
+ "Raster needs to be opened in write mode to change values."
+ )
capi.flush_ds(self._ptr)
@property
def vsi_buffer(self):
if not (
- self.is_vsi_based and
- self.name.startswith(VSI_MEM_FILESYSTEM_BASE_PATH)
+ self.is_vsi_based and self.name.startswith(VSI_MEM_FILESYSTEM_BASE_PATH)
):
return None
# Prepare an integer that will contain the buffer length.
@@ -276,7 +298,7 @@ class GDALRaster(GDALRasterBase):
wkt = capi.get_ds_projection_ref(self._ptr)
if not wkt:
return None
- return SpatialReference(wkt, srs_type='wkt')
+ return SpatialReference(wkt, srs_type="wkt")
except SRSException:
return None
@@ -292,7 +314,7 @@ class GDALRaster(GDALRasterBase):
elif isinstance(value, (int, str)):
srs = SpatialReference(value)
else:
- raise ValueError('Could not create a SpatialReference from input.')
+ raise ValueError("Could not create a SpatialReference from input.")
capi.set_ds_projection_ref(self._ptr, srs.wkt.encode())
self._flush()
@@ -326,7 +348,7 @@ class GDALRaster(GDALRasterBase):
def geotransform(self, values):
"Set the geotransform for the data source."
if len(values) != 6 or not all(isinstance(x, (int, float)) for x in values):
- raise ValueError('Geotransform must consist of 6 numeric values.')
+ raise ValueError("Geotransform must consist of 6 numeric values.")
# Create ctypes double array with input and write data
values = (c_double * 6)(*values)
capi.set_ds_geotransform(self._ptr, byref(values))
@@ -337,21 +359,21 @@ class GDALRaster(GDALRasterBase):
"""
Coordinates of the raster origin.
"""
- return TransformPoint(self, 'origin')
+ return TransformPoint(self, "origin")
@property
def scale(self):
"""
Pixel scale in units of the raster projection.
"""
- return TransformPoint(self, 'scale')
+ return TransformPoint(self, "scale")
@property
def skew(self):
"""
Skew of pixels (rotation parameters).
"""
- return TransformPoint(self, 'skew')
+ return TransformPoint(self, "skew")
@property
def extent(self):
@@ -373,7 +395,7 @@ class GDALRaster(GDALRasterBase):
def bands(self):
return BandList(self)
- def warp(self, ds_input, resampling='NearestNeighbour', max_error=0.0):
+ def warp(self, ds_input, resampling="NearestNeighbour", max_error=0.0):
"""
Return a warped GDALRaster with the given input characteristics.
@@ -391,23 +413,23 @@ class GDALRaster(GDALRasterBase):
consult the GDAL_RESAMPLE_ALGORITHMS constant.
"""
# Get the parameters defining the geotransform, srid, and size of the raster
- ds_input.setdefault('width', self.width)
- ds_input.setdefault('height', self.height)
- ds_input.setdefault('srid', self.srs.srid)
- ds_input.setdefault('origin', self.origin)
- ds_input.setdefault('scale', self.scale)
- ds_input.setdefault('skew', self.skew)
+ ds_input.setdefault("width", self.width)
+ ds_input.setdefault("height", self.height)
+ ds_input.setdefault("srid", self.srs.srid)
+ ds_input.setdefault("origin", self.origin)
+ ds_input.setdefault("scale", self.scale)
+ ds_input.setdefault("skew", self.skew)
# Get the driver, name, and datatype of the target raster
- ds_input.setdefault('driver', self.driver.name)
+ ds_input.setdefault("driver", self.driver.name)
- if 'name' not in ds_input:
- ds_input['name'] = self.name + '_copy.' + self.driver.name
+ if "name" not in ds_input:
+ ds_input["name"] = self.name + "_copy." + self.driver.name
- if 'datatype' not in ds_input:
- ds_input['datatype'] = self.bands[0].datatype()
+ if "datatype" not in ds_input:
+ ds_input["datatype"] = self.bands[0].datatype()
# Instantiate raster bands filled with nodata values.
- ds_input['bands'] = [{'nodata_value': bnd.nodata_value} for bnd in self.bands]
+ ds_input["bands"] = [{"nodata_value": bnd.nodata_value} for bnd in self.bands]
# Create target raster
target = GDALRaster(ds_input, write=True)
@@ -417,10 +439,16 @@ class GDALRaster(GDALRasterBase):
# Reproject image
capi.reproject_image(
- self._ptr, self.srs.wkt.encode(),
- target._ptr, target.srs.wkt.encode(),
- algorithm, 0.0, max_error,
- c_void_p(), c_void_p(), c_void_p()
+ self._ptr,
+ self.srs.wkt.encode(),
+ target._ptr,
+ target.srs.wkt.encode(),
+ algorithm,
+ 0.0,
+ max_error,
+ c_void_p(),
+ c_void_p(),
+ c_void_p(),
)
# Make sure all data is written to file
@@ -432,8 +460,8 @@ class GDALRaster(GDALRasterBase):
"""Return a clone of this GDALRaster."""
if name:
clone_name = name
- elif self.driver.name != 'MEM':
- clone_name = self.name + '_copy.' + self.driver.name
+ elif self.driver.name != "MEM":
+ clone_name = self.name + "_copy." + self.driver.name
else:
clone_name = os.path.join(VSI_MEM_FILESYSTEM_BASE_PATH, str(uuid.uuid4()))
return GDALRaster(
@@ -449,8 +477,9 @@ class GDALRaster(GDALRasterBase):
write=self._write,
)
- def transform(self, srs, driver=None, name=None, resampling='NearestNeighbour',
- max_error=0.0):
+ def transform(
+ self, srs, driver=None, name=None, resampling="NearestNeighbour", max_error=0.0
+ ):
"""
Return a copy of this raster reprojected into the given spatial
reference system.
@@ -464,35 +493,39 @@ class GDALRaster(GDALRasterBase):
target_srs = SpatialReference(srs)
else:
raise TypeError(
- 'Transform only accepts SpatialReference, string, and integer '
- 'objects.'
+ "Transform only accepts SpatialReference, string, and integer "
+ "objects."
)
if target_srs.srid == self.srid and (not driver or driver == self.driver.name):
return self.clone(name)
# Create warped virtual dataset in the target reference system
target = capi.auto_create_warped_vrt(
- self._ptr, self.srs.wkt.encode(), target_srs.wkt.encode(),
- algorithm, max_error, c_void_p()
+ self._ptr,
+ self.srs.wkt.encode(),
+ target_srs.wkt.encode(),
+ algorithm,
+ max_error,
+ c_void_p(),
)
target = GDALRaster(target)
# Construct the target warp dictionary from the virtual raster
data = {
- 'srid': target_srs.srid,
- 'width': target.width,
- 'height': target.height,
- 'origin': [target.origin.x, target.origin.y],
- 'scale': [target.scale.x, target.scale.y],
- 'skew': [target.skew.x, target.skew.y],
+ "srid": target_srs.srid,
+ "width": target.width,
+ "height": target.height,
+ "origin": [target.origin.x, target.origin.y],
+ "scale": [target.scale.x, target.scale.y],
+ "skew": [target.skew.x, target.skew.y],
}
# Set the driver and filepath if provided
if driver:
- data['driver'] = driver
+ data["driver"] = driver
if name:
- data['name'] = name
+ data["name"] = name
# Warp the raster into new srid
return self.warp(data, resampling=resampling, max_error=max_error)
diff --git a/django/contrib/gis/gdal/srs.py b/django/contrib/gis/gdal/srs.py
index 5df8b54ab2..41477d55db 100644
--- a/django/contrib/gis/gdal/srs.py
+++ b/django/contrib/gis/gdal/srs.py
@@ -47,9 +47,10 @@ class SpatialReference(GDALBase):
the SpatialReference object "provide[s] services to represent coordinate
systems (projections and datums) and to transform between them."
"""
+
destructor = capi.release_srs
- def __init__(self, srs_input='', srs_type='user', axis_order=None):
+ def __init__(self, srs_input="", srs_type="user", axis_order=None):
"""
Create a GDAL OSR Spatial Reference object from the given input.
The input may be string of OGC Well Known Text (WKT), an integer
@@ -58,56 +59,58 @@ class SpatialReference(GDALBase):
"""
if not isinstance(axis_order, (type(None), AxisOrder)):
raise ValueError(
- 'SpatialReference.axis_order must be an AxisOrder instance.'
+ "SpatialReference.axis_order must be an AxisOrder instance."
)
self.axis_order = axis_order or AxisOrder.TRADITIONAL
- if srs_type == 'wkt':
- self.ptr = capi.new_srs(c_char_p(b''))
+ if srs_type == "wkt":
+ self.ptr = capi.new_srs(c_char_p(b""))
self.import_wkt(srs_input)
if self.axis_order == AxisOrder.TRADITIONAL and GDAL_VERSION >= (3, 0):
capi.set_axis_strategy(self.ptr, self.axis_order)
elif self.axis_order != AxisOrder.TRADITIONAL and GDAL_VERSION < (3, 0):
- raise ValueError('%s is not supported in GDAL < 3.0.' % self.axis_order)
+ raise ValueError("%s is not supported in GDAL < 3.0." % self.axis_order)
return
elif isinstance(srs_input, str):
try:
# If SRID is a string, e.g., '4326', then make acceptable
# as user input.
srid = int(srs_input)
- srs_input = 'EPSG:%d' % srid
+ srs_input = "EPSG:%d" % srid
except ValueError:
pass
elif isinstance(srs_input, int):
# EPSG integer code was input.
- srs_type = 'epsg'
+ srs_type = "epsg"
elif isinstance(srs_input, self.ptr_type):
srs = srs_input
- srs_type = 'ogr'
+ srs_type = "ogr"
else:
raise TypeError('Invalid SRS type "%s"' % srs_type)
- if srs_type == 'ogr':
+ if srs_type == "ogr":
# Input is already an SRS pointer.
srs = srs_input
else:
# Creating a new SRS pointer, using the string buffer.
- buf = c_char_p(b'')
+ buf = c_char_p(b"")
srs = capi.new_srs(buf)
# If the pointer is NULL, throw an exception.
if not srs:
- raise SRSException('Could not create spatial reference from: %s' % srs_input)
+ raise SRSException(
+ "Could not create spatial reference from: %s" % srs_input
+ )
else:
self.ptr = srs
if self.axis_order == AxisOrder.TRADITIONAL and GDAL_VERSION >= (3, 0):
capi.set_axis_strategy(self.ptr, self.axis_order)
elif self.axis_order != AxisOrder.TRADITIONAL and GDAL_VERSION < (3, 0):
- raise ValueError('%s is not supported in GDAL < 3.0.' % self.axis_order)
+ raise ValueError("%s is not supported in GDAL < 3.0." % self.axis_order)
# Importing from either the user input string or an integer SRID.
- if srs_type == 'user':
+ if srs_type == "user":
self.import_user_input(srs_input)
- elif srs_type == 'epsg':
+ elif srs_type == "epsg":
self.import_epsg(srs_input)
def __getitem__(self, target):
@@ -188,11 +191,11 @@ class SpatialReference(GDALBase):
def name(self):
"Return the name of this Spatial Reference."
if self.projected:
- return self.attr_value('PROJCS')
+ return self.attr_value("PROJCS")
elif self.geographic:
- return self.attr_value('GEOGCS')
+ return self.attr_value("GEOGCS")
elif self.local:
- return self.attr_value('LOCAL_CS')
+ return self.attr_value("LOCAL_CS")
else:
return None
@@ -200,7 +203,7 @@ class SpatialReference(GDALBase):
def srid(self):
"Return the SRID of top-level authority, or None if undefined."
try:
- return int(self.attr_value('AUTHORITY', 1))
+ return int(self.attr_value("AUTHORITY", 1))
except (TypeError, ValueError):
return None
@@ -333,7 +336,7 @@ class SpatialReference(GDALBase):
return self.proj
@property
- def xml(self, dialect=''):
+ def xml(self, dialect=""):
"Return the XML representation of this Spatial Reference."
return capi.to_xml(self.ptr, byref(c_char_p()), force_bytes(dialect))
@@ -344,8 +347,10 @@ class CoordTransform(GDALBase):
def __init__(self, source, target):
"Initialize on a source and target SpatialReference objects."
- if not isinstance(source, SpatialReference) or not isinstance(target, SpatialReference):
- raise TypeError('source and target must be of type SpatialReference')
+ if not isinstance(source, SpatialReference) or not isinstance(
+ target, SpatialReference
+ ):
+ raise TypeError("source and target must be of type SpatialReference")
self.ptr = capi.new_ct(source._ptr, target._ptr)
self._srs1_name = source.name
self._srs2_name = target.name
diff --git a/django/contrib/gis/geoip2/__init__.py b/django/contrib/gis/geoip2/__init__.py
index 191706b01e..71b71f68db 100644
--- a/django/contrib/gis/geoip2/__init__.py
+++ b/django/contrib/gis/geoip2/__init__.py
@@ -11,7 +11,7 @@ downloaded from MaxMind at https://dev.maxmind.com/geoip/geoip2/geolite2/.
Grab GeoLite2-Country.mmdb.gz and GeoLite2-City.mmdb.gz, and unzip them in the
directory corresponding to settings.GEOIP_PATH.
"""
-__all__ = ['HAS_GEOIP2']
+__all__ = ["HAS_GEOIP2"]
try:
import geoip2 # NOQA
@@ -19,5 +19,6 @@ except ImportError:
HAS_GEOIP2 = False
else:
from .base import GeoIP2, GeoIP2Exception
+
HAS_GEOIP2 = True
- __all__ += ['GeoIP2', 'GeoIP2Exception']
+ __all__ += ["GeoIP2", "GeoIP2Exception"]
diff --git a/django/contrib/gis/geoip2/base.py b/django/contrib/gis/geoip2/base.py
index bcd8f1e2d8..e74984fe45 100644
--- a/django/contrib/gis/geoip2/base.py
+++ b/django/contrib/gis/geoip2/base.py
@@ -12,9 +12,9 @@ from .resources import City, Country
# Creating the settings dictionary with any settings, if needed.
GEOIP_SETTINGS = {
- 'GEOIP_PATH': getattr(settings, 'GEOIP_PATH', None),
- 'GEOIP_CITY': getattr(settings, 'GEOIP_CITY', 'GeoLite2-City.mmdb'),
- 'GEOIP_COUNTRY': getattr(settings, 'GEOIP_COUNTRY', 'GeoLite2-Country.mmdb'),
+ "GEOIP_PATH": getattr(settings, "GEOIP_PATH", None),
+ "GEOIP_CITY": getattr(settings, "GEOIP_CITY", "GeoLite2-City.mmdb"),
+ "GEOIP_COUNTRY": getattr(settings, "GEOIP_COUNTRY", "GeoLite2-Country.mmdb"),
}
@@ -34,11 +34,13 @@ class GeoIP2:
MODE_FILE = 4
# Load database into memory. Pure Python.
MODE_MEMORY = 8
- cache_options = frozenset((MODE_AUTO, MODE_MMAP_EXT, MODE_MMAP, MODE_FILE, MODE_MEMORY))
+ cache_options = frozenset(
+ (MODE_AUTO, MODE_MMAP_EXT, MODE_MMAP, MODE_FILE, MODE_MEMORY)
+ )
# Paths to the city & country binary databases.
- _city_file = ''
- _country_file = ''
+ _city_file = ""
+ _country_file = ""
# Initially, pointers to GeoIP file references are NULL.
_city = None
@@ -69,29 +71,31 @@ class GeoIP2:
"""
# Checking the given cache option.
if cache not in self.cache_options:
- raise GeoIP2Exception('Invalid GeoIP caching option: %s' % cache)
+ raise GeoIP2Exception("Invalid GeoIP caching option: %s" % cache)
# Getting the GeoIP data path.
- path = path or GEOIP_SETTINGS['GEOIP_PATH']
+ path = path or GEOIP_SETTINGS["GEOIP_PATH"]
if not path:
- raise GeoIP2Exception('GeoIP path must be provided via parameter or the GEOIP_PATH setting.')
+ raise GeoIP2Exception(
+ "GeoIP path must be provided via parameter or the GEOIP_PATH setting."
+ )
path = to_path(path)
if path.is_dir():
# Constructing the GeoIP database filenames using the settings
# dictionary. If the database files for the GeoLite country
# and/or city datasets exist, then try to open them.
- country_db = path / (country or GEOIP_SETTINGS['GEOIP_COUNTRY'])
+ country_db = path / (country or GEOIP_SETTINGS["GEOIP_COUNTRY"])
if country_db.is_file():
self._country = geoip2.database.Reader(str(country_db), mode=cache)
self._country_file = country_db
- city_db = path / (city or GEOIP_SETTINGS['GEOIP_CITY'])
+ city_db = path / (city or GEOIP_SETTINGS["GEOIP_CITY"])
if city_db.is_file():
self._city = geoip2.database.Reader(str(city_db), mode=cache)
self._city_file = city_db
if not self._reader:
- raise GeoIP2Exception('Could not load a database from %s.' % path)
+ raise GeoIP2Exception("Could not load a database from %s." % path)
elif path.is_file():
# Otherwise, some detective work will be needed to figure out
# whether the given database path is for the GeoIP country or city
@@ -99,18 +103,20 @@ class GeoIP2:
reader = geoip2.database.Reader(str(path), mode=cache)
db_type = reader.metadata().database_type
- if db_type.endswith('City'):
+ if db_type.endswith("City"):
# GeoLite City database detected.
self._city = reader
self._city_file = path
- elif db_type.endswith('Country'):
+ elif db_type.endswith("Country"):
# GeoIP Country database detected.
self._country = reader
self._country_file = path
else:
- raise GeoIP2Exception('Unable to recognize database edition: %s' % db_type)
+ raise GeoIP2Exception(
+ "Unable to recognize database edition: %s" % db_type
+ )
else:
- raise GeoIP2Exception('GeoIP path must be a valid file or directory.')
+ raise GeoIP2Exception("GeoIP path must be a valid file or directory.")
@property
def _reader(self):
@@ -130,25 +136,33 @@ class GeoIP2:
def __repr__(self):
meta = self._reader.metadata()
- version = '[v%s.%s]' % (meta.binary_format_major_version, meta.binary_format_minor_version)
- return '<%(cls)s %(version)s _country_file="%(country)s", _city_file="%(city)s">' % {
- 'cls': self.__class__.__name__,
- 'version': version,
- 'country': self._country_file,
- 'city': self._city_file,
- }
+ version = "[v%s.%s]" % (
+ meta.binary_format_major_version,
+ meta.binary_format_minor_version,
+ )
+ return (
+ '<%(cls)s %(version)s _country_file="%(country)s", _city_file="%(city)s">'
+ % {
+ "cls": self.__class__.__name__,
+ "version": version,
+ "country": self._country_file,
+ "city": self._city_file,
+ }
+ )
def _check_query(self, query, city=False, city_or_country=False):
"Check the query and database availability."
# Making sure a string was passed in for the query.
if not isinstance(query, str):
- raise TypeError('GeoIP query must be a string, not type %s' % type(query).__name__)
+ raise TypeError(
+ "GeoIP query must be a string, not type %s" % type(query).__name__
+ )
# Extra checks for the existence of country and city databases.
if city_or_country and not (self._country or self._city):
- raise GeoIP2Exception('Invalid GeoIP country and city data files.')
+ raise GeoIP2Exception("Invalid GeoIP country and city data files.")
elif city and not self._city:
- raise GeoIP2Exception('Invalid GeoIP city data file: %s' % self._city_file)
+ raise GeoIP2Exception("Invalid GeoIP city data file: %s" % self._city_file)
# Return the query string back to the caller. GeoIP2 only takes IP addresses.
try:
@@ -169,11 +183,11 @@ class GeoIP2:
def country_code(self, query):
"Return the country code for the given IP Address or FQDN."
- return self.country(query)['country_code']
+ return self.country(query)["country_code"]
def country_name(self, query):
"Return the country name for the given IP Address or FQDN."
- return self.country(query)['country_name']
+ return self.country(query)["country_name"]
def country(self, query):
"""
@@ -186,7 +200,7 @@ class GeoIP2:
return Country(self._country_or_city(enc_query))
# #### Coordinate retrieval routines ####
- def coords(self, query, ordering=('longitude', 'latitude')):
+ def coords(self, query, ordering=("longitude", "latitude")):
cdict = self.city(query)
if cdict is None:
return None
@@ -199,7 +213,7 @@ class GeoIP2:
def lat_lon(self, query):
"Return a tuple of the (latitude, longitude) for the given query."
- return self.coords(query, ('latitude', 'longitude'))
+ return self.coords(query, ("latitude", "longitude"))
def geos(self, query):
"Return a GEOS Point object for the given query."
@@ -214,7 +228,10 @@ class GeoIP2:
def info(self):
"Return information about the GeoIP library and databases in use."
meta = self._reader.metadata()
- return 'GeoIP Library:\n\t%s.%s\n' % (meta.binary_format_major_version, meta.binary_format_minor_version)
+ return "GeoIP Library:\n\t%s.%s\n" % (
+ meta.binary_format_major_version,
+ meta.binary_format_minor_version,
+ )
@classmethod
def open(cls, full_path, cache):
diff --git a/django/contrib/gis/geoip2/resources.py b/django/contrib/gis/geoip2/resources.py
index 08923b0998..74f4228697 100644
--- a/django/contrib/gis/geoip2/resources.py
+++ b/django/contrib/gis/geoip2/resources.py
@@ -1,22 +1,22 @@
def City(response):
return {
- 'city': response.city.name,
- 'continent_code': response.continent.code,
- 'continent_name': response.continent.name,
- 'country_code': response.country.iso_code,
- 'country_name': response.country.name,
- 'dma_code': response.location.metro_code,
- 'is_in_european_union': response.country.is_in_european_union,
- 'latitude': response.location.latitude,
- 'longitude': response.location.longitude,
- 'postal_code': response.postal.code,
- 'region': response.subdivisions[0].iso_code if response.subdivisions else None,
- 'time_zone': response.location.time_zone,
+ "city": response.city.name,
+ "continent_code": response.continent.code,
+ "continent_name": response.continent.name,
+ "country_code": response.country.iso_code,
+ "country_name": response.country.name,
+ "dma_code": response.location.metro_code,
+ "is_in_european_union": response.country.is_in_european_union,
+ "latitude": response.location.latitude,
+ "longitude": response.location.longitude,
+ "postal_code": response.postal.code,
+ "region": response.subdivisions[0].iso_code if response.subdivisions else None,
+ "time_zone": response.location.time_zone,
}
def Country(response):
return {
- 'country_code': response.country.iso_code,
- 'country_name': response.country.name,
+ "country_code": response.country.iso_code,
+ "country_name": response.country.name,
}
diff --git a/django/contrib/gis/geometry.py b/django/contrib/gis/geometry.py
index f7a70618fa..0b289cf355 100644
--- a/django/contrib/gis/geometry.py
+++ b/django/contrib/gis/geometry.py
@@ -5,13 +5,13 @@ from django.utils.regex_helper import _lazy_re_compile
# Regular expression for recognizing HEXEWKB and WKT. A prophylactic measure
# to prevent potentially malicious input from reaching the underlying C
# library. Not a substitute for good web security programming practices.
-hex_regex = _lazy_re_compile(r'^[0-9A-F]+$', re.I)
+hex_regex = _lazy_re_compile(r"^[0-9A-F]+$", re.I)
wkt_regex = _lazy_re_compile(
- r'^(SRID=(?P<srid>\-?[0-9]+);)?'
- r'(?P<wkt>'
- r'(?P<type>POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|'
- r'MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)'
- r'[ACEGIMLONPSRUTYZ0-9,\.\-\+\(\) ]+)$',
- re.I
+ r"^(SRID=(?P<srid>\-?[0-9]+);)?"
+ r"(?P<wkt>"
+ r"(?P<type>POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|"
+ r"MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)"
+ r"[ACEGIMLONPSRUTYZ0-9,\.\-\+\(\) ]+)$",
+ re.I,
)
-json_regex = _lazy_re_compile(r'^(\s+)?\{.*}(\s+)?$', re.DOTALL)
+json_regex = _lazy_re_compile(r"^(\s+)?\{.*}(\s+)?$", re.DOTALL)
diff --git a/django/contrib/gis/geos/__init__.py b/django/contrib/gis/geos/__init__.py
index 65e7e54817..27de1ca8e6 100644
--- a/django/contrib/gis/geos/__init__.py
+++ b/django/contrib/gis/geos/__init__.py
@@ -3,7 +3,10 @@ The GeoDjango GEOS module. Please consult the GeoDjango documentation
for more details: https://docs.djangoproject.com/en/dev/ref/contrib/gis/geos/
"""
from .collections import ( # NOQA
- GeometryCollection, MultiLineString, MultiPoint, MultiPolygon,
+ GeometryCollection,
+ MultiLineString,
+ MultiPoint,
+ MultiPolygon,
)
from .error import GEOSException # NOQA
from .factory import fromfile, fromstr # NOQA
diff --git a/django/contrib/gis/geos/collections.py b/django/contrib/gis/geos/collections.py
index 3c1f0c858e..abfec8af3d 100644
--- a/django/contrib/gis/geos/collections.py
+++ b/django/contrib/gis/geos/collections.py
@@ -46,11 +46,14 @@ class GeometryCollection(GEOSGeometry):
# ### Methods for compatibility with ListMixin ###
def _create_collection(self, length, items):
# Creating the geometry pointer array.
- geoms = (GEOM_PTR * length)(*[
- # this is a little sloppy, but makes life easier
- # allow GEOSGeometry types (python wrappers) or pointer types
- capi.geom_clone(getattr(g, 'ptr', g)) for g in items
- ])
+ geoms = (GEOM_PTR * length)(
+ *[
+ # this is a little sloppy, but makes life easier
+ # allow GEOSGeometry types (python wrappers) or pointer types
+ capi.geom_clone(getattr(g, "ptr", g))
+ for g in items
+ ]
+ )
return capi.create_collection(self._typeid, geoms, length)
def _get_single_internal(self, index):
@@ -59,7 +62,9 @@ class GeometryCollection(GEOSGeometry):
def _get_single_external(self, index):
"Return the Geometry from this Collection at the given index (0-based)."
# Checking the index and returning the corresponding GEOS geometry.
- return GEOSGeometry(capi.geom_clone(self._get_single_internal(index)), srid=self.srid)
+ return GEOSGeometry(
+ capi.geom_clone(self._get_single_internal(index)), srid=self.srid
+ )
def _set_list(self, length, items):
"Create a new collection, and destroy the contents of the previous pointer."
@@ -76,12 +81,13 @@ class GeometryCollection(GEOSGeometry):
@property
def kml(self):
"Return the KML for this Geometry Collection."
- return '<MultiGeometry>%s</MultiGeometry>' % ''.join(g.kml for g in self)
+ return "<MultiGeometry>%s</MultiGeometry>" % "".join(g.kml for g in self)
@property
def tuple(self):
"Return a tuple of all the coordinates in this Geometry Collection"
return tuple(g.tuple for g in self)
+
coords = tuple
@@ -103,4 +109,12 @@ class MultiPolygon(GeometryCollection):
# Setting the allowed types here since GeometryCollection is defined before
# its subclasses.
-GeometryCollection._allowed = (Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon)
+GeometryCollection._allowed = (
+ Point,
+ LineString,
+ LinearRing,
+ Polygon,
+ MultiPoint,
+ MultiLineString,
+ MultiPolygon,
+)
diff --git a/django/contrib/gis/geos/coordseq.py b/django/contrib/gis/geos/coordseq.py
index d6a7c6cdc7..07a3b7d213 100644
--- a/django/contrib/gis/geos/coordseq.py
+++ b/django/contrib/gis/geos/coordseq.py
@@ -20,7 +20,7 @@ class GEOSCoordSeq(GEOSBase):
def __init__(self, ptr, z=False):
"Initialize from a GEOS pointer."
if not isinstance(ptr, CS_PTR):
- raise TypeError('Coordinate sequence should initialize with a CS_PTR.')
+ raise TypeError("Coordinate sequence should initialize with a CS_PTR.")
self._ptr = ptr
self._z = z
@@ -50,7 +50,9 @@ class GEOSCoordSeq(GEOSBase):
elif numpy and isinstance(value, numpy.ndarray):
pass
else:
- raise TypeError('Must set coordinate with a sequence (list, tuple, or numpy array).')
+ raise TypeError(
+ "Must set coordinate with a sequence (list, tuple, or numpy array)."
+ )
# Checking the dims of the input
if self.dims == 3 and self._z:
n_args = 3
@@ -59,7 +61,7 @@ class GEOSCoordSeq(GEOSBase):
n_args = 2
point_setter = self._set_point_2d
if len(value) != n_args:
- raise TypeError('Dimension of value does not match.')
+ raise TypeError("Dimension of value does not match.")
self._checkindex(index)
point_setter(index, value)
@@ -67,7 +69,7 @@ class GEOSCoordSeq(GEOSBase):
def _checkindex(self, index):
"Check the given index."
if not (0 <= index < self.size):
- raise IndexError('invalid GEOS Geometry index: %s' % index)
+ raise IndexError("invalid GEOS Geometry index: %s" % index)
def _checkdim(self, dim):
"Check the given dimension."
@@ -180,11 +182,13 @@ class GEOSCoordSeq(GEOSBase):
# Getting the substitution string depending on whether the coordinates have
# a Z dimension.
if self.hasz:
- substr = '%s,%s,%s '
+ substr = "%s,%s,%s "
else:
- substr = '%s,%s,0 '
- return '<coordinates>%s</coordinates>' % \
- ''.join(substr % self[i] for i in range(len(self))).strip()
+ substr = "%s,%s,0 "
+ return (
+ "<coordinates>%s</coordinates>"
+ % "".join(substr % self[i] for i in range(len(self))).strip()
+ )
@property
def tuple(self):
diff --git a/django/contrib/gis/geos/factory.py b/django/contrib/gis/geos/factory.py
index 46ed1f0c51..2c1c24741b 100644
--- a/django/contrib/gis/geos/factory.py
+++ b/django/contrib/gis/geos/factory.py
@@ -8,7 +8,7 @@ def fromfile(file_h):
"""
# If given a file name, get a real handle.
if isinstance(file_h, str):
- with open(file_h, 'rb') as file_h:
+ with open(file_h, "rb") as file_h:
buf = file_h.read()
else:
buf = file_h.read()
diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py
index 36f6895224..9d22425fab 100644
--- a/django/contrib/gis/geos/geometry.py
+++ b/django/contrib/gis/geos/geometry.py
@@ -14,9 +14,7 @@ from django.contrib.gis.geos.error import GEOSException
from django.contrib.gis.geos.libgeos import GEOM_PTR, geos_version_tuple
from django.contrib.gis.geos.mutable_list import ListMixin
from django.contrib.gis.geos.prepared import PreparedGeometry
-from django.contrib.gis.geos.prototypes.io import (
- ewkb_w, wkb_r, wkb_w, wkt_r, wkt_w,
-)
+from django.contrib.gis.geos.prototypes.io import ewkb_w, wkb_r, wkb_w, wkt_r, wkt_w
from django.utils.deconstruct import deconstructible
from django.utils.encoding import force_bytes, force_str
@@ -38,12 +36,15 @@ class GEOSGeometryBase(GEOSBase):
if GEOSGeometryBase._GEOS_CLASSES is None:
# Inner imports avoid import conflicts with GEOSGeometry.
from .collections import (
- GeometryCollection, MultiLineString, MultiPoint,
+ GeometryCollection,
+ MultiLineString,
+ MultiPoint,
MultiPolygon,
)
from .linestring import LinearRing, LineString
from .point import Point
from .polygon import Polygon
+
GEOSGeometryBase._GEOS_CLASSES = {
0: Point,
1: LineString,
@@ -62,7 +63,9 @@ class GEOSGeometryBase(GEOSBase):
"Perform post-initialization setup."
# Setting the coordinate sequence for the geometry (will be None on
# geometries that do not have coordinate sequences)
- self._cs = GEOSCoordSeq(capi.get_cs(self.ptr), self.hasz) if self.has_cs else None
+ self._cs = (
+ GEOSCoordSeq(capi.get_cs(self.ptr), self.hasz) if self.has_cs else None
+ )
def __copy__(self):
"""
@@ -85,7 +88,7 @@ class GEOSGeometryBase(GEOSBase):
def __repr__(self):
"Short-hand representation because WKT may be very large."
- return '<%s object at %s>' % (self.geom_type, hex(addressof(self.ptr)))
+ return "<%s object at %s>" % (self.geom_type, hex(addressof(self.ptr)))
# Pickling support
def _to_pickle_wkb(self):
@@ -104,7 +107,7 @@ class GEOSGeometryBase(GEOSBase):
wkb, srid = state
ptr = self._from_pickle_wkb(wkb)
if not ptr:
- raise GEOSException('Invalid Geometry loaded from pickled state.')
+ raise GEOSException("Invalid Geometry loaded from pickled state.")
self.ptr = ptr
self._post_init()
self.srid = srid
@@ -117,17 +120,17 @@ class GEOSGeometryBase(GEOSBase):
def from_ewkt(ewkt):
ewkt = force_bytes(ewkt)
srid = None
- parts = ewkt.split(b';', 1)
+ parts = ewkt.split(b";", 1)
if len(parts) == 2:
srid_part, wkt = parts
- match = re.match(br'SRID=(?P<srid>\-?\d+)', srid_part)
+ match = re.match(rb"SRID=(?P<srid>\-?\d+)", srid_part)
if not match:
- raise ValueError('EWKT has invalid SRID part.')
- srid = int(match['srid'])
+ raise ValueError("EWKT has invalid SRID part.")
+ srid = int(match["srid"])
else:
wkt = ewkt
if not wkt:
- raise ValueError('Expected WKT but got an empty string.')
+ raise ValueError("Expected WKT but got an empty string.")
return GEOSGeometry(GEOSGeometry._from_wkt(wkt), srid=srid)
@staticmethod
@@ -149,7 +152,11 @@ class GEOSGeometryBase(GEOSBase):
other = GEOSGeometry.from_ewkt(other)
except (ValueError, GEOSException):
return False
- return isinstance(other, GEOSGeometry) and self.srid == other.srid and self.equals_exact(other)
+ return (
+ isinstance(other, GEOSGeometry)
+ and self.srid == other.srid
+ and self.equals_exact(other)
+ )
def __hash__(self):
return hash((self.srid, self.wkt))
@@ -225,7 +232,7 @@ class GEOSGeometryBase(GEOSBase):
without losing any of the input vertices.
"""
if geos_version_tuple() < (3, 8):
- raise GEOSException('GEOSGeometry.make_valid() requires GEOS >= 3.8.0.')
+ raise GEOSException("GEOSGeometry.make_valid() requires GEOS >= 3.8.0.")
return GEOSGeometry(capi.geos_makevalid(self.ptr), srid=self.srid)
# #### Unary predicates ####
@@ -323,7 +330,7 @@ class GEOSGeometryBase(GEOSBase):
two Geometries match the elements in pattern.
"""
if not isinstance(pattern, str) or len(pattern) > 9:
- raise GEOSException('invalid intersection matrix pattern')
+ raise GEOSException("invalid intersection matrix pattern")
return capi.geos_relatepattern(self.ptr, other.ptr, force_bytes(pattern))
def touches(self, other):
@@ -362,7 +369,7 @@ class GEOSGeometryBase(GEOSBase):
Return the EWKT (SRID + WKT) of the Geometry.
"""
srid = self.srid
- return 'SRID=%s;%s' % (srid, self.wkt) if srid else self.wkt
+ return "SRID=%s;%s" % (srid, self.wkt) if srid else self.wkt
@property
def wkt(self):
@@ -395,6 +402,7 @@ class GEOSGeometryBase(GEOSBase):
Return GeoJSON representation of this Geometry.
"""
return self.ogr.json
+
geojson = json
@property
@@ -419,7 +427,7 @@ class GEOSGeometryBase(GEOSBase):
def kml(self):
"Return the KML representation of this Geometry."
gtype = self.geom_type
- return '<%s>%s</%s>' % (gtype, self.coord_seq.kml, gtype)
+ return "<%s>%s</%s>" % (gtype, self.coord_seq.kml, gtype)
@property
def prepared(self):
@@ -493,7 +501,7 @@ class GEOSGeometryBase(GEOSBase):
self._post_init()
self.srid = g.srid
else:
- raise GEOSException('Transformed WKB was invalid.')
+ raise GEOSException("Transformed WKB was invalid.")
# #### Topology Routines ####
def _topology(self, gptr):
@@ -515,7 +523,9 @@ class GEOSGeometryBase(GEOSBase):
"""
return self._topology(capi.geos_buffer(self.ptr, width, quadsegs))
- def buffer_with_style(self, width, quadsegs=8, end_cap_style=1, join_style=1, mitre_limit=5.0):
+ def buffer_with_style(
+ self, width, quadsegs=8, end_cap_style=1, join_style=1, mitre_limit=5.0
+ ):
"""
Same as buffer() but allows customizing the style of the buffer.
@@ -524,7 +534,9 @@ class GEOSGeometryBase(GEOSBase):
Mitre ratio limit only affects mitered join style.
"""
return self._topology(
- capi.geos_bufferwithstyle(self.ptr, width, quadsegs, end_cap_style, join_style, mitre_limit),
+ capi.geos_bufferwithstyle(
+ self.ptr, width, quadsegs, end_cap_style, join_style, mitre_limit
+ ),
)
@property
@@ -615,7 +627,7 @@ class GEOSGeometryBase(GEOSBase):
the Geometry.
"""
if not isinstance(other, GEOSGeometry):
- raise TypeError('distance() works only on other GEOS Geometries.')
+ raise TypeError("distance() works only on other GEOS Geometries.")
return capi.geos_distance(self.ptr, other.ptr, byref(c_double()))
@property
@@ -625,6 +637,7 @@ class GEOSGeometryBase(GEOSBase):
(xmin, ymin, xmax, ymax).
"""
from .point import Point
+
env = self.envelope
if isinstance(env, Point):
xmin, ymin = env.tuple
@@ -651,6 +664,7 @@ class LinearGeometryMixin:
"""
Used for LineString and MultiLineString.
"""
+
def interpolate(self, distance):
return self._topology(capi.geos_interpolate(self.ptr, distance))
@@ -659,14 +673,16 @@ class LinearGeometryMixin:
def project(self, point):
from .point import Point
+
if not isinstance(point, Point):
- raise TypeError('locate_point argument must be a Point')
+ raise TypeError("locate_point argument must be a Point")
return capi.geos_project(self.ptr, point.ptr)
def project_normalized(self, point):
from .point import Point
+
if not isinstance(point, Point):
- raise TypeError('locate_point argument must be a Point')
+ raise TypeError("locate_point argument must be a Point")
return capi.geos_project_normalized(self.ptr, point.ptr)
@property
@@ -710,9 +726,9 @@ class GEOSGeometry(GEOSGeometryBase, ListMixin):
wkt_m = wkt_regex.match(geo_input)
if wkt_m:
# Handle WKT input.
- if wkt_m['srid']:
- input_srid = int(wkt_m['srid'])
- g = self._from_wkt(force_bytes(wkt_m['wkt']))
+ if wkt_m["srid"]:
+ input_srid = int(wkt_m["srid"])
+ g = self._from_wkt(force_bytes(wkt_m["wkt"]))
elif hex_regex.match(geo_input):
# Handle HEXEWKB input.
g = wkb_r().read(force_bytes(geo_input))
@@ -722,7 +738,7 @@ class GEOSGeometry(GEOSGeometryBase, ListMixin):
g = ogr._geos_ptr()
input_srid = ogr.srid
else:
- raise ValueError('String input unrecognized as WKT EWKT, and HEXEWKB.')
+ raise ValueError("String input unrecognized as WKT EWKT, and HEXEWKB.")
elif isinstance(geo_input, GEOM_PTR):
# When the input is a pointer to a geometry (GEOM_PTR).
g = geo_input
@@ -732,14 +748,14 @@ class GEOSGeometry(GEOSGeometryBase, ListMixin):
elif isinstance(geo_input, GEOSGeometry):
g = capi.geom_clone(geo_input.ptr)
else:
- raise TypeError('Improper geometry input type: %s' % type(geo_input))
+ raise TypeError("Improper geometry input type: %s" % type(geo_input))
if not g:
- raise GEOSException('Could not initialize GEOS Geometry with given input.')
+ raise GEOSException("Could not initialize GEOS Geometry with given input.")
input_srid = input_srid or capi.geos_get_srid(g) or None
if input_srid and srid and input_srid != srid:
- raise ValueError('Input geometry already has SRID: %d.' % input_srid)
+ raise ValueError("Input geometry already has SRID: %d." % input_srid)
super().__init__(g, None)
# Set the SRID, if given.
diff --git a/django/contrib/gis/geos/io.py b/django/contrib/gis/geos/io.py
index 15027ff68f..d7898065f0 100644
--- a/django/contrib/gis/geos/io.py
+++ b/django/contrib/gis/geos/io.py
@@ -5,10 +5,13 @@ reader and writer classes.
"""
from django.contrib.gis.geos.geometry import GEOSGeometry
from django.contrib.gis.geos.prototypes.io import (
- WKBWriter, WKTWriter, _WKBReader, _WKTReader,
+ WKBWriter,
+ WKTWriter,
+ _WKBReader,
+ _WKTReader,
)
-__all__ = ['WKBWriter', 'WKTWriter', 'WKBReader', 'WKTReader']
+__all__ = ["WKBWriter", "WKTWriter", "WKBReader", "WKTReader"]
# Public classes for (WKB|WKT)Reader, which return GEOSGeometry
diff --git a/django/contrib/gis/geos/libgeos.py b/django/contrib/gis/geos/libgeos.py
index aa19b3a706..1121b4f715 100644
--- a/django/contrib/gis/geos/libgeos.py
+++ b/django/contrib/gis/geos/libgeos.py
@@ -15,13 +15,14 @@ from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import SimpleLazyObject, cached_property
from django.utils.version import get_version_tuple
-logger = logging.getLogger('django.contrib.gis')
+logger = logging.getLogger("django.contrib.gis")
def load_geos():
# Custom library path set?
try:
from django.conf import settings
+
lib_path = settings.GEOS_LIBRARY_PATH
except (AttributeError, ImportError, ImproperlyConfigured, OSError):
lib_path = None
@@ -29,12 +30,12 @@ def load_geos():
# Setting the appropriate names for the GEOS-C library.
if lib_path:
lib_names = None
- elif os.name == 'nt':
+ elif os.name == "nt":
# Windows NT libraries
- lib_names = ['geos_c', 'libgeos_c-1']
- elif os.name == 'posix':
+ lib_names = ["geos_c", "libgeos_c-1"]
+ elif os.name == "posix":
# *NIX libraries
- lib_names = ['geos_c', 'GEOS']
+ lib_names = ["geos_c", "GEOS"]
else:
raise ImportError('Unsupported OS "%s"' % os.name)
@@ -51,8 +52,7 @@ def load_geos():
if lib_path is None:
raise ImportError(
'Could not find the GEOS library (tried "%s"). '
- 'Try setting GEOS_LIBRARY_PATH in your settings.' %
- '", "'.join(lib_names)
+ "Try setting GEOS_LIBRARY_PATH in your settings." % '", "'.join(lib_names)
)
# Getting the GEOS C library. The C interface (CDLL) is used for
# both *NIX and Windows.
@@ -82,7 +82,7 @@ def notice_h(fmt, lst):
warn_msg = fmt % lst
except TypeError:
warn_msg = fmt
- logger.warning('GEOS_NOTICE: %s\n', warn_msg)
+ logger.warning("GEOS_NOTICE: %s\n", warn_msg)
notice_h = NOTICEFUNC(notice_h)
@@ -96,7 +96,7 @@ def error_h(fmt, lst):
err_msg = fmt % lst
except TypeError:
err_msg = fmt
- logger.error('GEOS_ERROR: %s\n', err_msg)
+ logger.error("GEOS_ERROR: %s\n", err_msg)
error_h = ERRORFUNC(error_h)
@@ -135,6 +135,7 @@ class GEOSFuncFactory:
"""
Lazy loading of GEOS functions.
"""
+
argtypes = None
restype = None
errcheck = None
@@ -154,6 +155,7 @@ class GEOSFuncFactory:
@cached_property
def func(self):
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
+
func = GEOSFunc(self.func_name)
func.argtypes = self.argtypes or []
func.restype = self.restype
diff --git a/django/contrib/gis/geos/linestring.py b/django/contrib/gis/geos/linestring.py
index a85ecfff8c..78a265cebf 100644
--- a/django/contrib/gis/geos/linestring.py
+++ b/django/contrib/gis/geos/linestring.py
@@ -29,11 +29,15 @@ class LineString(LinearGeometryMixin, GEOSGeometry):
else:
coords = args
- if not (isinstance(coords, (tuple, list)) or numpy and isinstance(coords, numpy.ndarray)):
- raise TypeError('Invalid initialization input for LineStrings.')
+ if not (
+ isinstance(coords, (tuple, list))
+ or numpy
+ and isinstance(coords, numpy.ndarray)
+ ):
+ raise TypeError("Invalid initialization input for LineStrings.")
# If SRID was passed in with the keyword arguments
- srid = kwargs.get('srid')
+ srid = kwargs.get("srid")
ncoords = len(coords)
if not ncoords:
@@ -42,7 +46,8 @@ class LineString(LinearGeometryMixin, GEOSGeometry):
if ncoords < self._minlength:
raise ValueError(
- '%s requires at least %d points, got %s.' % (
+ "%s requires at least %d points, got %s."
+ % (
self.__class__.__name__,
self._minlength,
ncoords,
@@ -53,7 +58,7 @@ class LineString(LinearGeometryMixin, GEOSGeometry):
if numpy_coords:
shape = coords.shape # Using numpy's shape.
if len(shape) != 2:
- raise TypeError('Too many dimensions.')
+ raise TypeError("Too many dimensions.")
self._checkdim(shape[1])
ndim = shape[1]
else:
@@ -63,13 +68,15 @@ class LineString(LinearGeometryMixin, GEOSGeometry):
# Incrementing through each of the coordinates and verifying
for coord in coords:
if not isinstance(coord, (tuple, list, Point)):
- raise TypeError('Each coordinate should be a sequence (list or tuple)')
+ raise TypeError(
+ "Each coordinate should be a sequence (list or tuple)"
+ )
if ndim is None:
ndim = len(coord)
self._checkdim(ndim)
elif len(coord) != ndim:
- raise TypeError('Dimension mismatch.')
+ raise TypeError("Dimension mismatch.")
# Creating a coordinate sequence object because it is easier to
# set the points using its methods.
@@ -122,20 +129,21 @@ class LineString(LinearGeometryMixin, GEOSGeometry):
self._post_init()
else:
# can this happen?
- raise GEOSException('Geometry resulting from slice deletion was invalid.')
+ raise GEOSException("Geometry resulting from slice deletion was invalid.")
def _set_single(self, index, value):
self._cs[index] = value
def _checkdim(self, dim):
if dim not in (2, 3):
- raise TypeError('Dimension mismatch.')
+ raise TypeError("Dimension mismatch.")
# #### Sequence Properties ####
@property
def tuple(self):
"Return a tuple version of the geometry from the coordinate sequence."
return self._cs.tuple
+
coords = tuple
def _listarr(self, func):
@@ -181,7 +189,5 @@ class LinearRing(LineString):
@property
def is_counterclockwise(self):
if self.empty:
- raise ValueError(
- 'Orientation of an empty LinearRing cannot be determined.'
- )
+ raise ValueError("Orientation of an empty LinearRing cannot be determined.")
return self._cs.is_counterclockwise
diff --git a/django/contrib/gis/geos/mutable_list.py b/django/contrib/gis/geos/mutable_list.py
index b04a2128af..36131fe9ce 100644
--- a/django/contrib/gis/geos/mutable_list.py
+++ b/django/contrib/gis/geos/mutable_list.py
@@ -60,10 +60,10 @@ class ListMixin:
# ### Python initialization and special list interface methods ###
def __init__(self, *args, **kwargs):
- if not hasattr(self, '_get_single_internal'):
+ if not hasattr(self, "_get_single_internal"):
self._get_single_internal = self._get_single_external
- if not hasattr(self, '_set_single'):
+ if not hasattr(self, "_set_single"):
self._set_single = self._set_single_rebuild
self._assign_extended_slice = self._assign_extended_slice_rebuild
@@ -72,7 +72,9 @@ class ListMixin:
def __getitem__(self, index):
"Get the item(s) at the specified index/slice."
if isinstance(index, slice):
- return [self._get_single_external(i) for i in range(*index.indices(len(self)))]
+ return [
+ self._get_single_external(i) for i in range(*index.indices(len(self)))
+ ]
else:
index = self._checkindex(index)
return self._get_single_external(index)
@@ -91,9 +93,9 @@ class ListMixin:
indexRange = range(*index.indices(origLen))
newLen = origLen - len(indexRange)
- newItems = (self._get_single_internal(i)
- for i in range(origLen)
- if i not in indexRange)
+ newItems = (
+ self._get_single_internal(i) for i in range(origLen) if i not in indexRange
+ )
self._rebuild(newLen, newItems)
@@ -108,28 +110,28 @@ class ListMixin:
# ### Special methods for arithmetic operations ###
def __add__(self, other):
- 'add another list-like object'
+ "add another list-like object"
return self.__class__([*self, *other])
def __radd__(self, other):
- 'add to another list-like object'
+ "add to another list-like object"
return other.__class__([*other, *self])
def __iadd__(self, other):
- 'add another list-like object to self'
+ "add another list-like object to self"
self.extend(other)
return self
def __mul__(self, n):
- 'multiply'
+ "multiply"
return self.__class__(list(self) * n)
def __rmul__(self, n):
- 'multiply'
+ "multiply"
return self.__class__(list(self) * n)
def __imul__(self, n):
- 'multiply'
+ "multiply"
if n <= 0:
del self[:]
else:
@@ -179,16 +181,16 @@ class ListMixin:
for i in range(0, len(self)):
if self[i] == val:
return i
- raise ValueError('%s not found in object' % val)
+ raise ValueError("%s not found in object" % val)
# ## Mutating ##
def append(self, val):
"Standard list append method"
- self[len(self):] = [val]
+ self[len(self) :] = [val]
def extend(self, vals):
"Standard list extend method"
- self[len(self):] = vals
+ self[len(self) :] = vals
def insert(self, index, val):
"Standard list insert method"
@@ -217,9 +219,9 @@ class ListMixin:
# ### Private routines ###
def _rebuild(self, newLen, newItems):
if newLen and newLen < self._minlength:
- raise ValueError('Must have at least %d items' % self._minlength)
+ raise ValueError("Must have at least %d items" % self._minlength)
if self._maxlength is not None and newLen > self._maxlength:
- raise ValueError('Cannot have more than %d items' % self._maxlength)
+ raise ValueError("Cannot have more than %d items" % self._maxlength)
self._set_list(newLen, newItems)
@@ -232,19 +234,19 @@ class ListMixin:
return index
if -length <= index < 0:
return index + length
- raise IndexError('invalid index: %s' % index)
+ raise IndexError("invalid index: %s" % index)
def _check_allowed(self, items):
- if hasattr(self, '_allowed'):
+ if hasattr(self, "_allowed"):
if False in [isinstance(val, self._allowed) for val in items]:
- raise TypeError('Invalid type encountered in the arguments.')
+ raise TypeError("Invalid type encountered in the arguments.")
def _set_slice(self, index, values):
"Assign values to a slice of the object"
try:
valueList = list(values)
except TypeError:
- raise TypeError('can only assign an iterable to a slice')
+ raise TypeError("can only assign an iterable to a slice")
self._check_allowed(valueList)
@@ -259,13 +261,14 @@ class ListMixin:
self._assign_extended_slice(start, stop, step, valueList)
def _assign_extended_slice_rebuild(self, start, stop, step, valueList):
- 'Assign an extended slice by rebuilding entire list'
+ "Assign an extended slice by rebuilding entire list"
indexList = range(start, stop, step)
# extended slice, only allow assigning slice of same size
if len(valueList) != len(indexList):
- raise ValueError('attempt to assign sequence of size %d '
- 'to extended slice of size %d'
- % (len(valueList), len(indexList)))
+ raise ValueError(
+ "attempt to assign sequence of size %d "
+ "to extended slice of size %d" % (len(valueList), len(indexList))
+ )
# we're not changing the length of the sequence
newLen = len(self)
@@ -281,19 +284,20 @@ class ListMixin:
self._rebuild(newLen, newItems())
def _assign_extended_slice(self, start, stop, step, valueList):
- 'Assign an extended slice by re-assigning individual items'
+ "Assign an extended slice by re-assigning individual items"
indexList = range(start, stop, step)
# extended slice, only allow assigning slice of same size
if len(valueList) != len(indexList):
- raise ValueError('attempt to assign sequence of size %d '
- 'to extended slice of size %d'
- % (len(valueList), len(indexList)))
+ raise ValueError(
+ "attempt to assign sequence of size %d "
+ "to extended slice of size %d" % (len(valueList), len(indexList))
+ )
for i, val in zip(indexList, valueList):
self._set_single(i, val)
def _assign_simple_slice(self, start, stop, valueList):
- 'Assign a simple slice; Can assign slice of any length'
+ "Assign a simple slice; Can assign slice of any length"
origLen = len(self)
stop = max(start, stop)
newLen = origLen - stop + start + len(valueList)
diff --git a/django/contrib/gis/geos/point.py b/django/contrib/gis/geos/point.py
index 00fdd96a27..06b2668621 100644
--- a/django/contrib/gis/geos/point.py
+++ b/django/contrib/gis/geos/point.py
@@ -32,7 +32,7 @@ class Point(GEOSGeometry):
else:
coords = [x, y]
else:
- raise TypeError('Invalid parameters given for Point initialization.')
+ raise TypeError("Invalid parameters given for Point initialization.")
point = self._create_point(len(coords), coords)
@@ -47,7 +47,9 @@ class Point(GEOSGeometry):
return self._create_empty() if wkb is None else super()._from_pickle_wkb(wkb)
def _ogr_ptr(self):
- return gdal.geometries.Point._create_empty() if self.empty else super()._ogr_ptr()
+ return (
+ gdal.geometries.Point._create_empty() if self.empty else super()._ogr_ptr()
+ )
@classmethod
def _create_empty(cls):
@@ -62,7 +64,7 @@ class Point(GEOSGeometry):
return capi.create_point(None)
if ndim < 2 or ndim > 3:
- raise TypeError('Invalid point dimension: %s' % ndim)
+ raise TypeError("Invalid point dimension: %s" % ndim)
cs = capi.create_cs(c_uint(1), c_uint(ndim))
i = iter(coords)
@@ -84,7 +86,7 @@ class Point(GEOSGeometry):
self._post_init()
else:
# can this happen?
- raise GEOSException('Geometry resulting from slice deletion was invalid.')
+ raise GEOSException("Geometry resulting from slice deletion was invalid.")
def _set_single(self, index, value):
self._cs.setOrdinate(index, 0, value)
@@ -142,7 +144,7 @@ class Point(GEOSGeometry):
def z(self, value):
"Set the Z component of the Point."
if not self.hasz:
- raise GEOSException('Cannot set Z on 2D Point.')
+ raise GEOSException("Cannot set Z on 2D Point.")
self._cs.setOrdinate(2, 0, value)
# ### Tuple setting and retrieval routines. ###
diff --git a/django/contrib/gis/geos/polygon.py b/django/contrib/gis/geos/polygon.py
index d75106a9a8..452e72fcb6 100644
--- a/django/contrib/gis/geos/polygon.py
+++ b/django/contrib/gis/geos/polygon.py
@@ -59,8 +59,10 @@ class Polygon(GEOSGeometry):
x0, y0, x1, y1 = bbox
for z in bbox:
if not isinstance(z, (float, int)):
- return GEOSGeometry('POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' %
- (x0, y0, x0, y1, x1, y1, x1, y0, x0, y0))
+ return GEOSGeometry(
+ "POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))"
+ % (x0, y0, x0, y1, x1, y1, x1, y0, x0, y0)
+ )
return Polygon(((x0, y0), (x0, y1), (x1, y1), (x1, y0), (x0, y0)))
# ### These routines are needed for list-like operation w/ListMixin ###
@@ -95,8 +97,13 @@ class Polygon(GEOSGeometry):
else:
return capi.geom_clone(g.ptr)
- def _construct_ring(self, param, msg=(
- 'Parameter must be a sequence of LinearRings or objects that can initialize to LinearRings')):
+ def _construct_ring(
+ self,
+ param,
+ msg=(
+ "Parameter must be a sequence of LinearRings or objects that can initialize to LinearRings"
+ ),
+ ):
"Try to construct a ring from the given parameter."
if isinstance(param, LinearRing):
return param
@@ -135,7 +142,9 @@ class Polygon(GEOSGeometry):
return capi.get_intring(self.ptr, index - 1)
def _get_single_external(self, index):
- return GEOSGeometry(capi.geom_clone(self._get_single_internal(index)), srid=self.srid)
+ return GEOSGeometry(
+ capi.geom_clone(self._get_single_internal(index)), srid=self.srid
+ )
_set_single = GEOSGeometry._set_single_rebuild
_assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild
@@ -163,13 +172,17 @@ class Polygon(GEOSGeometry):
def tuple(self):
"Get the tuple for each ring in this Polygon."
return tuple(self[i].tuple for i in range(len(self)))
+
coords = tuple
@property
def kml(self):
"Return the KML representation of this Polygon."
- inner_kml = ''.join(
+ inner_kml = "".join(
"<innerBoundaryIs>%s</innerBoundaryIs>" % self[i + 1].kml
for i in range(self.num_interior_rings)
)
- return "<Polygon><outerBoundaryIs>%s</outerBoundaryIs>%s</Polygon>" % (self[0].kml, inner_kml)
+ return "<Polygon><outerBoundaryIs>%s</outerBoundaryIs>%s</Polygon>" % (
+ self[0].kml,
+ inner_kml,
+ )
diff --git a/django/contrib/gis/geos/prepared.py b/django/contrib/gis/geos/prepared.py
index 789432f81a..9c77d8a533 100644
--- a/django/contrib/gis/geos/prepared.py
+++ b/django/contrib/gis/geos/prepared.py
@@ -8,6 +8,7 @@ class PreparedGeometry(GEOSBase):
At the moment this includes the contains covers, and intersects
operations.
"""
+
ptr_type = capi.PREPGEOM_PTR
destructor = capi.prepared_destroy
@@ -17,6 +18,7 @@ class PreparedGeometry(GEOSBase):
# See #21662
self._base_geom = geom
from .geometry import GEOSGeometry
+
if not isinstance(geom, GEOSGeometry):
raise TypeError
self.ptr = capi.geos_prepare(geom.ptr)
diff --git a/django/contrib/gis/geos/prototypes/__init__.py b/django/contrib/gis/geos/prototypes/__init__.py
index a79533fa14..8fa98f98e7 100644
--- a/django/contrib/gis/geos/prototypes/__init__.py
+++ b/django/contrib/gis/geos/prototypes/__init__.py
@@ -5,22 +5,62 @@
"""
from django.contrib.gis.geos.prototypes.coordseq import ( # NOQA
- create_cs, cs_clone, cs_getdims, cs_getordinate, cs_getsize, cs_getx,
- cs_gety, cs_getz, cs_is_ccw, cs_setordinate, cs_setx, cs_sety, cs_setz,
+ create_cs,
+ cs_clone,
+ cs_getdims,
+ cs_getordinate,
+ cs_getsize,
+ cs_getx,
+ cs_gety,
+ cs_getz,
+ cs_is_ccw,
+ cs_setordinate,
+ cs_setx,
+ cs_sety,
+ cs_setz,
get_cs,
)
from django.contrib.gis.geos.prototypes.geom import ( # NOQA
- create_collection, create_empty_polygon, create_linearring,
- create_linestring, create_point, create_polygon, destroy_geom, geom_clone,
- geos_get_srid, geos_makevalid, geos_normalize, geos_set_srid, geos_type,
- geos_typeid, get_dims, get_extring, get_geomn, get_intring, get_nrings,
- get_num_coords, get_num_geoms,
+ create_collection,
+ create_empty_polygon,
+ create_linearring,
+ create_linestring,
+ create_point,
+ create_polygon,
+ destroy_geom,
+ geom_clone,
+ geos_get_srid,
+ geos_makevalid,
+ geos_normalize,
+ geos_set_srid,
+ geos_type,
+ geos_typeid,
+ get_dims,
+ get_extring,
+ get_geomn,
+ get_intring,
+ get_nrings,
+ get_num_coords,
+ get_num_geoms,
)
from django.contrib.gis.geos.prototypes.misc import * # NOQA
from django.contrib.gis.geos.prototypes.predicates import ( # NOQA
- geos_contains, geos_covers, geos_crosses, geos_disjoint, geos_equals,
- geos_equalsexact, geos_hasz, geos_intersects, geos_isclosed, geos_isempty,
- geos_isring, geos_issimple, geos_isvalid, geos_overlaps,
- geos_relatepattern, geos_touches, geos_within,
+ geos_contains,
+ geos_covers,
+ geos_crosses,
+ geos_disjoint,
+ geos_equals,
+ geos_equalsexact,
+ geos_hasz,
+ geos_intersects,
+ geos_isclosed,
+ geos_isempty,
+ geos_isring,
+ geos_issimple,
+ geos_isvalid,
+ geos_overlaps,
+ geos_relatepattern,
+ geos_touches,
+ geos_within,
)
from django.contrib.gis.geos.prototypes.topology import * # NOQA
diff --git a/django/contrib/gis/geos/prototypes/coordseq.py b/django/contrib/gis/geos/prototypes/coordseq.py
index aab5d3e75e..ed05de99f4 100644
--- a/django/contrib/gis/geos/prototypes/coordseq.py
+++ b/django/contrib/gis/geos/prototypes/coordseq.py
@@ -1,16 +1,14 @@
from ctypes import POINTER, c_byte, c_double, c_int, c_uint
from django.contrib.gis.geos.libgeos import CS_PTR, GEOM_PTR, GEOSFuncFactory
-from django.contrib.gis.geos.prototypes.errcheck import (
- GEOSException, last_arg_byref,
-)
+from django.contrib.gis.geos.prototypes.errcheck import GEOSException, last_arg_byref
# ## Error-checking routines specific to coordinate sequences. ##
def check_cs_op(result, func, cargs):
"Check the status code of a coordinate sequence operation."
if result == 0:
- raise GEOSException('Could not set value on coordinate sequence')
+ raise GEOSException("Could not set value on coordinate sequence")
else:
return result
@@ -49,7 +47,9 @@ class CsOperation(GEOSFuncFactory):
else:
argtypes = [CS_PTR, c_uint, dbl_param]
- super().__init__(*args, **{**kwargs, 'errcheck': errcheck, 'argtypes': argtypes})
+ super().__init__(
+ *args, **{**kwargs, "errcheck": errcheck, "argtypes": argtypes}
+ )
class CsOutput(GEOSFuncFactory):
@@ -59,7 +59,7 @@ class CsOutput(GEOSFuncFactory):
def errcheck(result, func, cargs):
if not result:
raise GEOSException(
- 'Error encountered checking Coordinate Sequence returned from GEOS '
+ "Error encountered checking Coordinate Sequence returned from GEOS "
'C function "%s".' % func.__name__
)
return result
@@ -68,26 +68,28 @@ class CsOutput(GEOSFuncFactory):
# ## Coordinate Sequence ctypes prototypes ##
# Coordinate Sequence constructors & cloning.
-cs_clone = CsOutput('GEOSCoordSeq_clone', argtypes=[CS_PTR])
-create_cs = CsOutput('GEOSCoordSeq_create', argtypes=[c_uint, c_uint])
-get_cs = CsOutput('GEOSGeom_getCoordSeq', argtypes=[GEOM_PTR])
+cs_clone = CsOutput("GEOSCoordSeq_clone", argtypes=[CS_PTR])
+create_cs = CsOutput("GEOSCoordSeq_create", argtypes=[c_uint, c_uint])
+get_cs = CsOutput("GEOSGeom_getCoordSeq", argtypes=[GEOM_PTR])
# Getting, setting ordinate
-cs_getordinate = CsOperation('GEOSCoordSeq_getOrdinate', ordinate=True, get=True)
-cs_setordinate = CsOperation('GEOSCoordSeq_setOrdinate', ordinate=True)
+cs_getordinate = CsOperation("GEOSCoordSeq_getOrdinate", ordinate=True, get=True)
+cs_setordinate = CsOperation("GEOSCoordSeq_setOrdinate", ordinate=True)
# For getting, x, y, z
-cs_getx = CsOperation('GEOSCoordSeq_getX', get=True)
-cs_gety = CsOperation('GEOSCoordSeq_getY', get=True)
-cs_getz = CsOperation('GEOSCoordSeq_getZ', get=True)
+cs_getx = CsOperation("GEOSCoordSeq_getX", get=True)
+cs_gety = CsOperation("GEOSCoordSeq_getY", get=True)
+cs_getz = CsOperation("GEOSCoordSeq_getZ", get=True)
# For setting, x, y, z
-cs_setx = CsOperation('GEOSCoordSeq_setX')
-cs_sety = CsOperation('GEOSCoordSeq_setY')
-cs_setz = CsOperation('GEOSCoordSeq_setZ')
+cs_setx = CsOperation("GEOSCoordSeq_setX")
+cs_sety = CsOperation("GEOSCoordSeq_setY")
+cs_setz = CsOperation("GEOSCoordSeq_setZ")
# These routines return size & dimensions.
-cs_getsize = CsInt('GEOSCoordSeq_getSize')
-cs_getdims = CsInt('GEOSCoordSeq_getDimensions')
+cs_getsize = CsInt("GEOSCoordSeq_getSize")
+cs_getdims = CsInt("GEOSCoordSeq_getDimensions")
-cs_is_ccw = GEOSFuncFactory('GEOSCoordSeq_isCCW', restype=c_int, argtypes=[CS_PTR, POINTER(c_byte)])
+cs_is_ccw = GEOSFuncFactory(
+ "GEOSCoordSeq_isCCW", restype=c_int, argtypes=[CS_PTR, POINTER(c_byte)]
+)
diff --git a/django/contrib/gis/geos/prototypes/errcheck.py b/django/contrib/gis/geos/prototypes/errcheck.py
index 7d5f8422e0..a527f513a7 100644
--- a/django/contrib/gis/geos/prototypes/errcheck.py
+++ b/django/contrib/gis/geos/prototypes/errcheck.py
@@ -8,7 +8,7 @@ from django.contrib.gis.geos.libgeos import GEOSFuncFactory
# Getting the `free` routine used to free the memory allocated for
# string pointers returned by GEOS.
-free = GEOSFuncFactory('GEOSFree')
+free = GEOSFuncFactory("GEOSFree")
free.argtypes = [c_void_p]
@@ -29,14 +29,19 @@ def check_dbl(result, func, cargs):
def check_geom(result, func, cargs):
"Error checking on routines that return Geometries."
if not result:
- raise GEOSException('Error encountered checking Geometry returned from GEOS C function "%s".' % func.__name__)
+ raise GEOSException(
+ 'Error encountered checking Geometry returned from GEOS C function "%s".'
+ % func.__name__
+ )
return result
def check_minus_one(result, func, cargs):
"Error checking on routines that should not return -1."
if result == -1:
- raise GEOSException('Error encountered in GEOS C function "%s".' % func.__name__)
+ raise GEOSException(
+ 'Error encountered in GEOS C function "%s".' % func.__name__
+ )
else:
return result
@@ -48,7 +53,9 @@ def check_predicate(result, func, cargs):
elif result == 0:
return False
else:
- raise GEOSException('Error encountered on GEOS C predicate function "%s".' % func.__name__)
+ raise GEOSException(
+ 'Error encountered on GEOS C predicate function "%s".' % func.__name__
+ )
def check_sized_string(result, func, cargs):
@@ -58,7 +65,9 @@ def check_sized_string(result, func, cargs):
This frees the memory allocated by GEOS at the result pointer.
"""
if not result:
- raise GEOSException('Invalid string pointer returned by GEOS C function "%s"' % func.__name__)
+ raise GEOSException(
+ 'Invalid string pointer returned by GEOS C function "%s"' % func.__name__
+ )
# A c_size_t object is passed in by reference for the second
# argument on these routines, and its needed to determine the
# correct size.
@@ -75,7 +84,10 @@ def check_string(result, func, cargs):
This frees the memory allocated by GEOS at the result pointer.
"""
if not result:
- raise GEOSException('Error encountered checking string return value in GEOS C function "%s".' % func.__name__)
+ raise GEOSException(
+ 'Error encountered checking string return value in GEOS C function "%s".'
+ % func.__name__
+ )
# Getting the string value at the pointer address.
s = string_at(result)
# Freeing the memory allocated within GEOS
diff --git a/django/contrib/gis/geos/prototypes/geom.py b/django/contrib/gis/geos/prototypes/geom.py
index bddf7b55b2..a456acd0c1 100644
--- a/django/contrib/gis/geos/prototypes/geom.py
+++ b/django/contrib/gis/geos/prototypes/geom.py
@@ -2,7 +2,9 @@ from ctypes import POINTER, c_char_p, c_int, c_ubyte, c_uint
from django.contrib.gis.geos.libgeos import CS_PTR, GEOM_PTR, GEOSFuncFactory
from django.contrib.gis.geos.prototypes.errcheck import (
- check_geom, check_minus_one, check_string,
+ check_geom,
+ check_minus_one,
+ check_string,
)
# This is the return type used by binary output (WKB, HEX) routines.
@@ -44,44 +46,46 @@ class StringFromGeom(GEOSFuncFactory):
# ### ctypes prototypes ###
# The GEOS geometry type, typeid, num_coordinates and number of geometries
-geos_makevalid = GeomOutput('GEOSMakeValid', argtypes=[GEOM_PTR])
-geos_normalize = IntFromGeom('GEOSNormalize')
-geos_type = StringFromGeom('GEOSGeomType')
-geos_typeid = IntFromGeom('GEOSGeomTypeId')
-get_dims = GEOSFuncFactory('GEOSGeom_getDimensions', argtypes=[GEOM_PTR], restype=c_int)
-get_num_coords = IntFromGeom('GEOSGetNumCoordinates')
-get_num_geoms = IntFromGeom('GEOSGetNumGeometries')
+geos_makevalid = GeomOutput("GEOSMakeValid", argtypes=[GEOM_PTR])
+geos_normalize = IntFromGeom("GEOSNormalize")
+geos_type = StringFromGeom("GEOSGeomType")
+geos_typeid = IntFromGeom("GEOSGeomTypeId")
+get_dims = GEOSFuncFactory("GEOSGeom_getDimensions", argtypes=[GEOM_PTR], restype=c_int)
+get_num_coords = IntFromGeom("GEOSGetNumCoordinates")
+get_num_geoms = IntFromGeom("GEOSGetNumGeometries")
# Geometry creation factories
-create_point = GeomOutput('GEOSGeom_createPoint', argtypes=[CS_PTR])
-create_linestring = GeomOutput('GEOSGeom_createLineString', argtypes=[CS_PTR])
-create_linearring = GeomOutput('GEOSGeom_createLinearRing', argtypes=[CS_PTR])
+create_point = GeomOutput("GEOSGeom_createPoint", argtypes=[CS_PTR])
+create_linestring = GeomOutput("GEOSGeom_createLineString", argtypes=[CS_PTR])
+create_linearring = GeomOutput("GEOSGeom_createLinearRing", argtypes=[CS_PTR])
# Polygon and collection creation routines need argument types defined
# for compatibility with some platforms, e.g. macOS ARM64. With argtypes
# defined, arrays are automatically cast and byref() calls are not needed.
create_polygon = GeomOutput(
- 'GEOSGeom_createPolygon', argtypes=[GEOM_PTR, POINTER(GEOM_PTR), c_uint],
+ "GEOSGeom_createPolygon",
+ argtypes=[GEOM_PTR, POINTER(GEOM_PTR), c_uint],
)
-create_empty_polygon = GeomOutput('GEOSGeom_createEmptyPolygon', argtypes=[])
+create_empty_polygon = GeomOutput("GEOSGeom_createEmptyPolygon", argtypes=[])
create_collection = GeomOutput(
- 'GEOSGeom_createCollection', argtypes=[c_int, POINTER(GEOM_PTR), c_uint],
+ "GEOSGeom_createCollection",
+ argtypes=[c_int, POINTER(GEOM_PTR), c_uint],
)
# Ring routines
-get_extring = GeomOutput('GEOSGetExteriorRing', argtypes=[GEOM_PTR])
-get_intring = GeomOutput('GEOSGetInteriorRingN', argtypes=[GEOM_PTR, c_int])
-get_nrings = IntFromGeom('GEOSGetNumInteriorRings')
+get_extring = GeomOutput("GEOSGetExteriorRing", argtypes=[GEOM_PTR])
+get_intring = GeomOutput("GEOSGetInteriorRingN", argtypes=[GEOM_PTR, c_int])
+get_nrings = IntFromGeom("GEOSGetNumInteriorRings")
# Collection Routines
-get_geomn = GeomOutput('GEOSGetGeometryN', argtypes=[GEOM_PTR, c_int])
+get_geomn = GeomOutput("GEOSGetGeometryN", argtypes=[GEOM_PTR, c_int])
# Cloning
-geom_clone = GEOSFuncFactory('GEOSGeom_clone', argtypes=[GEOM_PTR], restype=GEOM_PTR)
+geom_clone = GEOSFuncFactory("GEOSGeom_clone", argtypes=[GEOM_PTR], restype=GEOM_PTR)
# Destruction routine.
-destroy_geom = GEOSFuncFactory('GEOSGeom_destroy', argtypes=[GEOM_PTR])
+destroy_geom = GEOSFuncFactory("GEOSGeom_destroy", argtypes=[GEOM_PTR])
# SRID routines
-geos_get_srid = GEOSFuncFactory('GEOSGetSRID', argtypes=[GEOM_PTR], restype=c_int)
-geos_set_srid = GEOSFuncFactory('GEOSSetSRID', argtypes=[GEOM_PTR, c_int])
+geos_get_srid = GEOSFuncFactory("GEOSGetSRID", argtypes=[GEOM_PTR], restype=c_int)
+geos_set_srid = GEOSFuncFactory("GEOSSetSRID", argtypes=[GEOM_PTR, c_int])
diff --git a/django/contrib/gis/geos/prototypes/io.py b/django/contrib/gis/geos/prototypes/io.py
index 4a1180ad7a..555d0e3a25 100644
--- a/django/contrib/gis/geos/prototypes/io.py
+++ b/django/contrib/gis/geos/prototypes/io.py
@@ -3,10 +3,14 @@ from ctypes import POINTER, Structure, byref, c_byte, c_char_p, c_int, c_size_t
from django.contrib.gis.geos.base import GEOSBase
from django.contrib.gis.geos.libgeos import (
- GEOM_PTR, GEOSFuncFactory, geos_version_tuple,
+ GEOM_PTR,
+ GEOSFuncFactory,
+ geos_version_tuple,
)
from django.contrib.gis.geos.prototypes.errcheck import (
- check_geom, check_sized_string, check_string,
+ check_geom,
+ check_sized_string,
+ check_string,
)
from django.contrib.gis.geos.prototypes.geom import c_uchar_p, geos_char_p
from django.utils.encoding import force_bytes
@@ -35,33 +39,43 @@ WKB_READ_PTR = POINTER(WKBReader_st)
WKB_WRITE_PTR = POINTER(WKBReader_st)
# WKTReader routines
-wkt_reader_create = GEOSFuncFactory('GEOSWKTReader_create', restype=WKT_READ_PTR)
-wkt_reader_destroy = GEOSFuncFactory('GEOSWKTReader_destroy', argtypes=[WKT_READ_PTR])
+wkt_reader_create = GEOSFuncFactory("GEOSWKTReader_create", restype=WKT_READ_PTR)
+wkt_reader_destroy = GEOSFuncFactory("GEOSWKTReader_destroy", argtypes=[WKT_READ_PTR])
wkt_reader_read = GEOSFuncFactory(
- 'GEOSWKTReader_read', argtypes=[WKT_READ_PTR, c_char_p], restype=GEOM_PTR, errcheck=check_geom
+ "GEOSWKTReader_read",
+ argtypes=[WKT_READ_PTR, c_char_p],
+ restype=GEOM_PTR,
+ errcheck=check_geom,
)
# WKTWriter routines
-wkt_writer_create = GEOSFuncFactory('GEOSWKTWriter_create', restype=WKT_WRITE_PTR)
-wkt_writer_destroy = GEOSFuncFactory('GEOSWKTWriter_destroy', argtypes=[WKT_WRITE_PTR])
+wkt_writer_create = GEOSFuncFactory("GEOSWKTWriter_create", restype=WKT_WRITE_PTR)
+wkt_writer_destroy = GEOSFuncFactory("GEOSWKTWriter_destroy", argtypes=[WKT_WRITE_PTR])
wkt_writer_write = GEOSFuncFactory(
- 'GEOSWKTWriter_write', argtypes=[WKT_WRITE_PTR, GEOM_PTR], restype=geos_char_p, errcheck=check_string
+ "GEOSWKTWriter_write",
+ argtypes=[WKT_WRITE_PTR, GEOM_PTR],
+ restype=geos_char_p,
+ errcheck=check_string,
)
wkt_writer_get_outdim = GEOSFuncFactory(
- 'GEOSWKTWriter_getOutputDimension', argtypes=[WKT_WRITE_PTR], restype=c_int
+ "GEOSWKTWriter_getOutputDimension", argtypes=[WKT_WRITE_PTR], restype=c_int
)
wkt_writer_set_outdim = GEOSFuncFactory(
- 'GEOSWKTWriter_setOutputDimension', argtypes=[WKT_WRITE_PTR, c_int]
+ "GEOSWKTWriter_setOutputDimension", argtypes=[WKT_WRITE_PTR, c_int]
)
-wkt_writer_set_trim = GEOSFuncFactory('GEOSWKTWriter_setTrim', argtypes=[WKT_WRITE_PTR, c_byte])
-wkt_writer_set_precision = GEOSFuncFactory('GEOSWKTWriter_setRoundingPrecision', argtypes=[WKT_WRITE_PTR, c_int])
+wkt_writer_set_trim = GEOSFuncFactory(
+ "GEOSWKTWriter_setTrim", argtypes=[WKT_WRITE_PTR, c_byte]
+)
+wkt_writer_set_precision = GEOSFuncFactory(
+ "GEOSWKTWriter_setRoundingPrecision", argtypes=[WKT_WRITE_PTR, c_int]
+)
# WKBReader routines
-wkb_reader_create = GEOSFuncFactory('GEOSWKBReader_create', restype=WKB_READ_PTR)
-wkb_reader_destroy = GEOSFuncFactory('GEOSWKBReader_destroy', argtypes=[WKB_READ_PTR])
+wkb_reader_create = GEOSFuncFactory("GEOSWKBReader_create", restype=WKB_READ_PTR)
+wkb_reader_destroy = GEOSFuncFactory("GEOSWKBReader_destroy", argtypes=[WKB_READ_PTR])
class WKBReadFunc(GEOSFuncFactory):
@@ -75,12 +89,12 @@ class WKBReadFunc(GEOSFuncFactory):
errcheck = staticmethod(check_geom)
-wkb_reader_read = WKBReadFunc('GEOSWKBReader_read')
-wkb_reader_read_hex = WKBReadFunc('GEOSWKBReader_readHEX')
+wkb_reader_read = WKBReadFunc("GEOSWKBReader_read")
+wkb_reader_read_hex = WKBReadFunc("GEOSWKBReader_readHEX")
# WKBWriter routines
-wkb_writer_create = GEOSFuncFactory('GEOSWKBWriter_create', restype=WKB_WRITE_PTR)
-wkb_writer_destroy = GEOSFuncFactory('GEOSWKBWriter_destroy', argtypes=[WKB_WRITE_PTR])
+wkb_writer_create = GEOSFuncFactory("GEOSWKBWriter_create", restype=WKB_WRITE_PTR)
+wkb_writer_destroy = GEOSFuncFactory("GEOSWKBWriter_destroy", argtypes=[WKB_WRITE_PTR])
# WKB Writing prototypes.
@@ -90,8 +104,8 @@ class WKBWriteFunc(GEOSFuncFactory):
errcheck = staticmethod(check_sized_string)
-wkb_writer_write = WKBWriteFunc('GEOSWKBWriter_write')
-wkb_writer_write_hex = WKBWriteFunc('GEOSWKBWriter_writeHEX')
+wkb_writer_write = WKBWriteFunc("GEOSWKBWriter_write")
+wkb_writer_write_hex = WKBWriteFunc("GEOSWKBWriter_writeHEX")
# WKBWriter property getter/setter prototypes.
@@ -104,17 +118,22 @@ class WKBWriterSet(GEOSFuncFactory):
argtypes = [WKB_WRITE_PTR, c_int]
-wkb_writer_get_byteorder = WKBWriterGet('GEOSWKBWriter_getByteOrder')
-wkb_writer_set_byteorder = WKBWriterSet('GEOSWKBWriter_setByteOrder')
-wkb_writer_get_outdim = WKBWriterGet('GEOSWKBWriter_getOutputDimension')
-wkb_writer_set_outdim = WKBWriterSet('GEOSWKBWriter_setOutputDimension')
-wkb_writer_get_include_srid = WKBWriterGet('GEOSWKBWriter_getIncludeSRID', restype=c_byte)
-wkb_writer_set_include_srid = WKBWriterSet('GEOSWKBWriter_setIncludeSRID', argtypes=[WKB_WRITE_PTR, c_byte])
+wkb_writer_get_byteorder = WKBWriterGet("GEOSWKBWriter_getByteOrder")
+wkb_writer_set_byteorder = WKBWriterSet("GEOSWKBWriter_setByteOrder")
+wkb_writer_get_outdim = WKBWriterGet("GEOSWKBWriter_getOutputDimension")
+wkb_writer_set_outdim = WKBWriterSet("GEOSWKBWriter_setOutputDimension")
+wkb_writer_get_include_srid = WKBWriterGet(
+ "GEOSWKBWriter_getIncludeSRID", restype=c_byte
+)
+wkb_writer_set_include_srid = WKBWriterSet(
+ "GEOSWKBWriter_setIncludeSRID", argtypes=[WKB_WRITE_PTR, c_byte]
+)
# ### Base I/O Class ###
class IOBase(GEOSBase):
"Base class for GEOS I/O objects."
+
def __init__(self):
# Getting the pointer with the constructor.
self.ptr = self._constructor()
@@ -122,6 +141,7 @@ class IOBase(GEOSBase):
# __del__ is too late (import error).
self.destructor.func
+
# ### Base WKB/WKT Reading and Writing objects ###
@@ -183,7 +203,7 @@ class WKTWriter(IOBase):
@outdim.setter
def outdim(self, new_dim):
if new_dim not in (2, 3):
- raise ValueError('WKT output dimension must be 2 or 3')
+ raise ValueError("WKT output dimension must be 2 or 3")
wkt_writer_set_outdim(self.ptr, new_dim)
@property
@@ -203,7 +223,9 @@ class WKTWriter(IOBase):
@precision.setter
def precision(self, precision):
if (not isinstance(precision, int) or precision < 0) and precision is not None:
- raise AttributeError('WKT output rounding precision must be non-negative integer or None.')
+ raise AttributeError(
+ "WKT output rounding precision must be non-negative integer or None."
+ )
if precision != self._precision:
self._precision = precision
wkt_writer_set_precision(self.ptr, -1 if precision is None else precision)
@@ -221,34 +243,37 @@ class WKBWriter(IOBase):
def _handle_empty_point(self, geom):
from django.contrib.gis.geos import Point
+
if isinstance(geom, Point) and geom.empty:
if self.srid:
# PostGIS uses POINT(NaN NaN) for WKB representation of empty
# points. Use it for EWKB as it's a PostGIS specific format.
# https://trac.osgeo.org/postgis/ticket/3181
- geom = Point(float('NaN'), float('NaN'), srid=geom.srid)
+ geom = Point(float("NaN"), float("NaN"), srid=geom.srid)
else:
- raise ValueError('Empty point is not representable in WKB.')
+ raise ValueError("Empty point is not representable in WKB.")
return geom
def write(self, geom):
"Return the WKB representation of the given geometry."
from django.contrib.gis.geos import Polygon
+
geom = self._handle_empty_point(geom)
wkb = wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t()))
if self.geos_version < (3, 6, 1) and isinstance(geom, Polygon) and geom.empty:
# Fix GEOS output for empty polygon.
# See https://trac.osgeo.org/geos/ticket/680.
- wkb = wkb[:-8] + b'\0' * 4
+ wkb = wkb[:-8] + b"\0" * 4
return memoryview(wkb)
def write_hex(self, geom):
"Return the HEXEWKB representation of the given geometry."
from django.contrib.gis.geos.polygon import Polygon
+
geom = self._handle_empty_point(geom)
wkb = wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
if self.geos_version < (3, 6, 1) and isinstance(geom, Polygon) and geom.empty:
- wkb = wkb[:-16] + b'0' * 8
+ wkb = wkb[:-16] + b"0" * 8
return wkb
# ### WKBWriter Properties ###
@@ -259,7 +284,9 @@ class WKBWriter(IOBase):
def _set_byteorder(self, order):
if order not in (0, 1):
- raise ValueError('Byte order parameter must be 0 (Big Endian) or 1 (Little Endian).')
+ raise ValueError(
+ "Byte order parameter must be 0 (Big Endian) or 1 (Little Endian)."
+ )
wkb_writer_set_byteorder(self.ptr, order)
byteorder = property(_get_byteorder, _set_byteorder)
@@ -272,7 +299,7 @@ class WKBWriter(IOBase):
@outdim.setter
def outdim(self, new_dim):
if new_dim not in (2, 3):
- raise ValueError('WKB output dimension must be 2 or 3')
+ raise ValueError("WKB output dimension must be 2 or 3")
wkb_writer_set_outdim(self.ptr, new_dim)
# Property for getting/setting the include srid flag.
diff --git a/django/contrib/gis/geos/prototypes/misc.py b/django/contrib/gis/geos/prototypes/misc.py
index 016c8328cb..fccd0ecc9e 100644
--- a/django/contrib/gis/geos/prototypes/misc.py
+++ b/django/contrib/gis/geos/prototypes/misc.py
@@ -8,7 +8,7 @@ from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOSFuncFactory
from django.contrib.gis.geos.prototypes.errcheck import check_dbl, check_string
from django.contrib.gis.geos.prototypes.geom import geos_char_p
-__all__ = ['geos_area', 'geos_distance', 'geos_length', 'geos_isvalidreason']
+__all__ = ["geos_area", "geos_distance", "geos_length", "geos_isvalidreason"]
class DblFromGeom(GEOSFuncFactory):
@@ -16,6 +16,7 @@ class DblFromGeom(GEOSFuncFactory):
Argument is a Geometry, return type is double that is passed
in by reference as the last argument.
"""
+
restype = c_int # Status code returned
errcheck = staticmethod(check_dbl)
@@ -23,9 +24,11 @@ class DblFromGeom(GEOSFuncFactory):
# ### ctypes prototypes ###
# Area, distance, and length prototypes.
-geos_area = DblFromGeom('GEOSArea', argtypes=[GEOM_PTR, POINTER(c_double)])
-geos_distance = DblFromGeom('GEOSDistance', argtypes=[GEOM_PTR, GEOM_PTR, POINTER(c_double)])
-geos_length = DblFromGeom('GEOSLength', argtypes=[GEOM_PTR, POINTER(c_double)])
+geos_area = DblFromGeom("GEOSArea", argtypes=[GEOM_PTR, POINTER(c_double)])
+geos_distance = DblFromGeom(
+ "GEOSDistance", argtypes=[GEOM_PTR, GEOM_PTR, POINTER(c_double)]
+)
+geos_length = DblFromGeom("GEOSLength", argtypes=[GEOM_PTR, POINTER(c_double)])
geos_isvalidreason = GEOSFuncFactory(
- 'GEOSisValidReason', restype=geos_char_p, errcheck=check_string, argtypes=[GEOM_PTR]
+ "GEOSisValidReason", restype=geos_char_p, errcheck=check_string, argtypes=[GEOM_PTR]
)
diff --git a/django/contrib/gis/geos/prototypes/predicates.py b/django/contrib/gis/geos/prototypes/predicates.py
index d4681c1689..d2e113a734 100644
--- a/django/contrib/gis/geos/prototypes/predicates.py
+++ b/django/contrib/gis/geos/prototypes/predicates.py
@@ -22,22 +22,26 @@ class BinaryPredicate(UnaryPredicate):
# ## Unary Predicates ##
-geos_hasz = UnaryPredicate('GEOSHasZ')
-geos_isclosed = UnaryPredicate('GEOSisClosed')
-geos_isempty = UnaryPredicate('GEOSisEmpty')
-geos_isring = UnaryPredicate('GEOSisRing')
-geos_issimple = UnaryPredicate('GEOSisSimple')
-geos_isvalid = UnaryPredicate('GEOSisValid')
+geos_hasz = UnaryPredicate("GEOSHasZ")
+geos_isclosed = UnaryPredicate("GEOSisClosed")
+geos_isempty = UnaryPredicate("GEOSisEmpty")
+geos_isring = UnaryPredicate("GEOSisRing")
+geos_issimple = UnaryPredicate("GEOSisSimple")
+geos_isvalid = UnaryPredicate("GEOSisValid")
# ## Binary Predicates ##
-geos_contains = BinaryPredicate('GEOSContains')
-geos_covers = BinaryPredicate('GEOSCovers')
-geos_crosses = BinaryPredicate('GEOSCrosses')
-geos_disjoint = BinaryPredicate('GEOSDisjoint')
-geos_equals = BinaryPredicate('GEOSEquals')
-geos_equalsexact = BinaryPredicate('GEOSEqualsExact', argtypes=[GEOM_PTR, GEOM_PTR, c_double])
-geos_intersects = BinaryPredicate('GEOSIntersects')
-geos_overlaps = BinaryPredicate('GEOSOverlaps')
-geos_relatepattern = BinaryPredicate('GEOSRelatePattern', argtypes=[GEOM_PTR, GEOM_PTR, c_char_p])
-geos_touches = BinaryPredicate('GEOSTouches')
-geos_within = BinaryPredicate('GEOSWithin')
+geos_contains = BinaryPredicate("GEOSContains")
+geos_covers = BinaryPredicate("GEOSCovers")
+geos_crosses = BinaryPredicate("GEOSCrosses")
+geos_disjoint = BinaryPredicate("GEOSDisjoint")
+geos_equals = BinaryPredicate("GEOSEquals")
+geos_equalsexact = BinaryPredicate(
+ "GEOSEqualsExact", argtypes=[GEOM_PTR, GEOM_PTR, c_double]
+)
+geos_intersects = BinaryPredicate("GEOSIntersects")
+geos_overlaps = BinaryPredicate("GEOSOverlaps")
+geos_relatepattern = BinaryPredicate(
+ "GEOSRelatePattern", argtypes=[GEOM_PTR, GEOM_PTR, c_char_p]
+)
+geos_touches = BinaryPredicate("GEOSTouches")
+geos_within = BinaryPredicate("GEOSWithin")
diff --git a/django/contrib/gis/geos/prototypes/prepared.py b/django/contrib/gis/geos/prototypes/prepared.py
index 52c31563d8..4fdfab30ed 100644
--- a/django/contrib/gis/geos/prototypes/prepared.py
+++ b/django/contrib/gis/geos/prototypes/prepared.py
@@ -1,13 +1,11 @@
from ctypes import c_byte
-from django.contrib.gis.geos.libgeos import (
- GEOM_PTR, PREPGEOM_PTR, GEOSFuncFactory,
-)
+from django.contrib.gis.geos.libgeos import GEOM_PTR, PREPGEOM_PTR, GEOSFuncFactory
from django.contrib.gis.geos.prototypes.errcheck import check_predicate
# Prepared geometry constructor and destructors.
-geos_prepare = GEOSFuncFactory('GEOSPrepare', argtypes=[GEOM_PTR], restype=PREPGEOM_PTR)
-prepared_destroy = GEOSFuncFactory('GEOSPreparedGeom_destroy', argtypes=[PREPGEOM_PTR])
+geos_prepare = GEOSFuncFactory("GEOSPrepare", argtypes=[GEOM_PTR], restype=PREPGEOM_PTR)
+prepared_destroy = GEOSFuncFactory("GEOSPreparedGeom_destroy", argtypes=[PREPGEOM_PTR])
# Prepared geometry binary predicate support.
@@ -17,12 +15,12 @@ class PreparedPredicate(GEOSFuncFactory):
errcheck = staticmethod(check_predicate)
-prepared_contains = PreparedPredicate('GEOSPreparedContains')
-prepared_contains_properly = PreparedPredicate('GEOSPreparedContainsProperly')
-prepared_covers = PreparedPredicate('GEOSPreparedCovers')
-prepared_crosses = PreparedPredicate('GEOSPreparedCrosses')
-prepared_disjoint = PreparedPredicate('GEOSPreparedDisjoint')
-prepared_intersects = PreparedPredicate('GEOSPreparedIntersects')
-prepared_overlaps = PreparedPredicate('GEOSPreparedOverlaps')
-prepared_touches = PreparedPredicate('GEOSPreparedTouches')
-prepared_within = PreparedPredicate('GEOSPreparedWithin')
+prepared_contains = PreparedPredicate("GEOSPreparedContains")
+prepared_contains_properly = PreparedPredicate("GEOSPreparedContainsProperly")
+prepared_covers = PreparedPredicate("GEOSPreparedCovers")
+prepared_crosses = PreparedPredicate("GEOSPreparedCrosses")
+prepared_disjoint = PreparedPredicate("GEOSPreparedDisjoint")
+prepared_intersects = PreparedPredicate("GEOSPreparedIntersects")
+prepared_overlaps = PreparedPredicate("GEOSPreparedOverlaps")
+prepared_touches = PreparedPredicate("GEOSPreparedTouches")
+prepared_within = PreparedPredicate("GEOSPreparedWithin")
diff --git a/django/contrib/gis/geos/prototypes/threadsafe.py b/django/contrib/gis/geos/prototypes/threadsafe.py
index 500f6a6019..d4f7ffb8ac 100644
--- a/django/contrib/gis/geos/prototypes/threadsafe.py
+++ b/django/contrib/gis/geos/prototypes/threadsafe.py
@@ -1,13 +1,12 @@
import threading
from django.contrib.gis.geos.base import GEOSBase
-from django.contrib.gis.geos.libgeos import (
- CONTEXT_PTR, error_h, lgeos, notice_h,
-)
+from django.contrib.gis.geos.libgeos import CONTEXT_PTR, error_h, lgeos, notice_h
class GEOSContextHandle(GEOSBase):
"""Represent a GEOS context handle."""
+
ptr_type = CONTEXT_PTR
destructor = lgeos.finishGEOS_r
@@ -31,10 +30,11 @@ class GEOSFunc:
Serve as a wrapper for GEOS C Functions. Use thread-safe function
variants when available.
"""
+
def __init__(self, func_name):
# GEOS thread-safe function signatures end with '_r' and take an
# additional context handle parameter.
- self.cfunc = getattr(lgeos, func_name + '_r')
+ self.cfunc = getattr(lgeos, func_name + "_r")
# Create a reference to thread_context so it's not garbage-collected
# before an attempt to call this object.
self.thread_context = thread_context
diff --git a/django/contrib/gis/geos/prototypes/topology.py b/django/contrib/gis/geos/prototypes/topology.py
index 9ca0dce695..e61eae964a 100644
--- a/django/contrib/gis/geos/prototypes/topology.py
+++ b/django/contrib/gis/geos/prototypes/topology.py
@@ -6,7 +6,9 @@ from ctypes import c_double, c_int
from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOSFuncFactory
from django.contrib.gis.geos.prototypes.errcheck import (
- check_geom, check_minus_one, check_string,
+ check_geom,
+ check_minus_one,
+ check_string,
)
from django.contrib.gis.geos.prototypes.geom import geos_char_p
@@ -19,35 +21,52 @@ class Topology(GEOSFuncFactory):
# Topology Routines
-geos_boundary = Topology('GEOSBoundary')
-geos_buffer = Topology('GEOSBuffer', argtypes=[GEOM_PTR, c_double, c_int])
-geos_bufferwithstyle = Topology('GEOSBufferWithStyle', argtypes=[GEOM_PTR, c_double, c_int, c_int, c_int, c_double])
-geos_centroid = Topology('GEOSGetCentroid')
-geos_convexhull = Topology('GEOSConvexHull')
-geos_difference = Topology('GEOSDifference', argtypes=[GEOM_PTR, GEOM_PTR])
-geos_envelope = Topology('GEOSEnvelope')
-geos_intersection = Topology('GEOSIntersection', argtypes=[GEOM_PTR, GEOM_PTR])
-geos_linemerge = Topology('GEOSLineMerge')
-geos_pointonsurface = Topology('GEOSPointOnSurface')
-geos_preservesimplify = Topology('GEOSTopologyPreserveSimplify', argtypes=[GEOM_PTR, c_double])
-geos_simplify = Topology('GEOSSimplify', argtypes=[GEOM_PTR, c_double])
-geos_symdifference = Topology('GEOSSymDifference', argtypes=[GEOM_PTR, GEOM_PTR])
-geos_union = Topology('GEOSUnion', argtypes=[GEOM_PTR, GEOM_PTR])
-
-geos_unary_union = GEOSFuncFactory('GEOSUnaryUnion', argtypes=[GEOM_PTR], restype=GEOM_PTR)
+geos_boundary = Topology("GEOSBoundary")
+geos_buffer = Topology("GEOSBuffer", argtypes=[GEOM_PTR, c_double, c_int])
+geos_bufferwithstyle = Topology(
+ "GEOSBufferWithStyle", argtypes=[GEOM_PTR, c_double, c_int, c_int, c_int, c_double]
+)
+geos_centroid = Topology("GEOSGetCentroid")
+geos_convexhull = Topology("GEOSConvexHull")
+geos_difference = Topology("GEOSDifference", argtypes=[GEOM_PTR, GEOM_PTR])
+geos_envelope = Topology("GEOSEnvelope")
+geos_intersection = Topology("GEOSIntersection", argtypes=[GEOM_PTR, GEOM_PTR])
+geos_linemerge = Topology("GEOSLineMerge")
+geos_pointonsurface = Topology("GEOSPointOnSurface")
+geos_preservesimplify = Topology(
+ "GEOSTopologyPreserveSimplify", argtypes=[GEOM_PTR, c_double]
+)
+geos_simplify = Topology("GEOSSimplify", argtypes=[GEOM_PTR, c_double])
+geos_symdifference = Topology("GEOSSymDifference", argtypes=[GEOM_PTR, GEOM_PTR])
+geos_union = Topology("GEOSUnion", argtypes=[GEOM_PTR, GEOM_PTR])
+
+geos_unary_union = GEOSFuncFactory(
+ "GEOSUnaryUnion", argtypes=[GEOM_PTR], restype=GEOM_PTR
+)
# GEOSRelate returns a string, not a geometry.
geos_relate = GEOSFuncFactory(
- 'GEOSRelate', argtypes=[GEOM_PTR, GEOM_PTR], restype=geos_char_p, errcheck=check_string
+ "GEOSRelate",
+ argtypes=[GEOM_PTR, GEOM_PTR],
+ restype=geos_char_p,
+ errcheck=check_string,
)
# Linear referencing routines
geos_project = GEOSFuncFactory(
- 'GEOSProject', argtypes=[GEOM_PTR, GEOM_PTR], restype=c_double, errcheck=check_minus_one
+ "GEOSProject",
+ argtypes=[GEOM_PTR, GEOM_PTR],
+ restype=c_double,
+ errcheck=check_minus_one,
)
-geos_interpolate = Topology('GEOSInterpolate', argtypes=[GEOM_PTR, c_double])
+geos_interpolate = Topology("GEOSInterpolate", argtypes=[GEOM_PTR, c_double])
geos_project_normalized = GEOSFuncFactory(
- 'GEOSProjectNormalized', argtypes=[GEOM_PTR, GEOM_PTR], restype=c_double, errcheck=check_minus_one
+ "GEOSProjectNormalized",
+ argtypes=[GEOM_PTR, GEOM_PTR],
+ restype=c_double,
+ errcheck=check_minus_one,
+)
+geos_interpolate_normalized = Topology(
+ "GEOSInterpolateNormalized", argtypes=[GEOM_PTR, c_double]
)
-geos_interpolate_normalized = Topology('GEOSInterpolateNormalized', argtypes=[GEOM_PTR, c_double])
diff --git a/django/contrib/gis/management/commands/inspectdb.py b/django/contrib/gis/management/commands/inspectdb.py
index 8c6f62932a..1bcc1a0793 100644
--- a/django/contrib/gis/management/commands/inspectdb.py
+++ b/django/contrib/gis/management/commands/inspectdb.py
@@ -1,16 +1,18 @@
-from django.core.management.commands.inspectdb import (
- Command as InspectDBCommand,
-)
+from django.core.management.commands.inspectdb import Command as InspectDBCommand
class Command(InspectDBCommand):
- db_module = 'django.contrib.gis.db'
+ db_module = "django.contrib.gis.db"
def get_field_type(self, connection, table_name, row):
- field_type, field_params, field_notes = super().get_field_type(connection, table_name, row)
- if field_type == 'GeometryField':
+ field_type, field_params, field_notes = super().get_field_type(
+ connection, table_name, row
+ )
+ if field_type == "GeometryField":
# Getting a more specific field type and any additional parameters
# from the `get_geometry_type` routine for the spatial backend.
- field_type, geo_params = connection.introspection.get_geometry_type(table_name, row)
+ field_type, geo_params = connection.introspection.get_geometry_type(
+ table_name, row
+ )
field_params.update(geo_params)
return field_type, field_params, field_notes
diff --git a/django/contrib/gis/management/commands/ogrinspect.py b/django/contrib/gis/management/commands/ogrinspect.py
index 12c1db392f..133cec3e60 100644
--- a/django/contrib/gis/management/commands/ogrinspect.py
+++ b/django/contrib/gis/management/commands/ogrinspect.py
@@ -10,6 +10,7 @@ class LayerOptionAction(argparse.Action):
Custom argparse action for the `ogrinspect` `layer_key` keyword option
which may be an integer or a string.
"""
+
def __call__(self, parser, namespace, value, option_string=None):
try:
setattr(namespace, self.dest, int(value))
@@ -23,80 +24,92 @@ class ListOptionAction(argparse.Action):
a string list. If the string is 'True'/'true' then the option
value will be a boolean instead.
"""
+
def __call__(self, parser, namespace, value, option_string=None):
- if value.lower() == 'true':
+ if value.lower() == "true":
setattr(namespace, self.dest, True)
else:
- setattr(namespace, self.dest, value.split(','))
+ setattr(namespace, self.dest, value.split(","))
class Command(BaseCommand):
help = (
- 'Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n'
- 'a GeoDjango model with the given model name. For example:\n'
- ' ./manage.py ogrinspect zipcode.shp Zipcode'
+ "Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n"
+ "a GeoDjango model with the given model name. For example:\n"
+ " ./manage.py ogrinspect zipcode.shp Zipcode"
)
requires_system_checks = []
def add_arguments(self, parser):
- parser.add_argument('data_source', help='Path to the data source.')
- parser.add_argument('model_name', help='Name of the model to create.')
+ parser.add_argument("data_source", help="Path to the data source.")
+ parser.add_argument("model_name", help="Name of the model to create.")
parser.add_argument(
- '--blank',
- action=ListOptionAction, default=False,
- help='Use a comma separated list of OGR field names to add '
- 'the `blank=True` option to the field definition. Set to `true` '
- 'to apply to all applicable fields.',
+ "--blank",
+ action=ListOptionAction,
+ default=False,
+ help="Use a comma separated list of OGR field names to add "
+ "the `blank=True` option to the field definition. Set to `true` "
+ "to apply to all applicable fields.",
)
parser.add_argument(
- '--decimal',
- action=ListOptionAction, default=False,
- help='Use a comma separated list of OGR float fields to '
- 'generate `DecimalField` instead of the default '
- '`FloatField`. Set to `true` to apply to all OGR float fields.',
+ "--decimal",
+ action=ListOptionAction,
+ default=False,
+ help="Use a comma separated list of OGR float fields to "
+ "generate `DecimalField` instead of the default "
+ "`FloatField`. Set to `true` to apply to all OGR float fields.",
)
parser.add_argument(
- '--geom-name', default='geom',
- help='Specifies the model name for the Geometry Field (defaults to `geom`)'
+ "--geom-name",
+ default="geom",
+ help="Specifies the model name for the Geometry Field (defaults to `geom`)",
)
parser.add_argument(
- '--layer', dest='layer_key',
- action=LayerOptionAction, default=0,
- help='The key for specifying which layer in the OGR data '
- 'source to use. Defaults to 0 (the first layer). May be '
- 'an integer or a string identifier for the layer.',
+ "--layer",
+ dest="layer_key",
+ action=LayerOptionAction,
+ default=0,
+ help="The key for specifying which layer in the OGR data "
+ "source to use. Defaults to 0 (the first layer). May be "
+ "an integer or a string identifier for the layer.",
)
parser.add_argument(
- '--multi-geom', action='store_true',
- help='Treat the geometry in the data source as a geometry collection.',
+ "--multi-geom",
+ action="store_true",
+ help="Treat the geometry in the data source as a geometry collection.",
)
parser.add_argument(
- '--name-field',
- help='Specifies a field name to return for the __str__() method.',
+ "--name-field",
+ help="Specifies a field name to return for the __str__() method.",
)
parser.add_argument(
- '--no-imports', action='store_false', dest='imports',
- help='Do not include `from django.contrib.gis.db import models` statement.',
+ "--no-imports",
+ action="store_false",
+ dest="imports",
+ help="Do not include `from django.contrib.gis.db import models` statement.",
)
parser.add_argument(
- '--null', action=ListOptionAction, default=False,
- help='Use a comma separated list of OGR field names to add '
- 'the `null=True` option to the field definition. Set to `true` '
- 'to apply to all applicable fields.',
+ "--null",
+ action=ListOptionAction,
+ default=False,
+ help="Use a comma separated list of OGR field names to add "
+ "the `null=True` option to the field definition. Set to `true` "
+ "to apply to all applicable fields.",
)
parser.add_argument(
- '--srid',
- help='The SRID to use for the Geometry Field. If it can be '
- 'determined, the SRID of the data source is used.',
+ "--srid",
+ help="The SRID to use for the Geometry Field. If it can be "
+ "determined, the SRID of the data source is used.",
)
parser.add_argument(
- '--mapping', action='store_true',
- help='Generate mapping dictionary for use with `LayerMapping`.',
+ "--mapping",
+ action="store_true",
+ help="Generate mapping dictionary for use with `LayerMapping`.",
)
def handle(self, *args, **options):
- data_source, model_name = options.pop('data_source'), options.pop('model_name')
+ data_source, model_name = options.pop("data_source"), options.pop("model_name")
# Getting the OGR DataSource from the string parameter.
try:
@@ -109,26 +122,43 @@ class Command(BaseCommand):
from django.contrib.gis.utils.ogrinspect import _ogrinspect, mapping
# Filter options to params accepted by `_ogrinspect`
- ogr_options = {k: v for k, v in options.items()
- if k in get_func_args(_ogrinspect) and v is not None}
+ ogr_options = {
+ k: v
+ for k, v in options.items()
+ if k in get_func_args(_ogrinspect) and v is not None
+ }
output = [s for s in _ogrinspect(ds, model_name, **ogr_options)]
- if options['mapping']:
+ if options["mapping"]:
# Constructing the keyword arguments for `mapping`, and
# calling it on the data source.
kwargs = {
- 'geom_name': options['geom_name'],
- 'layer_key': options['layer_key'],
- 'multi_geom': options['multi_geom'],
+ "geom_name": options["geom_name"],
+ "layer_key": options["layer_key"],
+ "multi_geom": options["multi_geom"],
}
mapping_dict = mapping(ds, **kwargs)
# This extra legwork is so that the dictionary definition comes
# out in the same order as the fields in the model definition.
rev_mapping = {v: k for k, v in mapping_dict.items()}
- output.extend(['', '', '# Auto-generated `LayerMapping` dictionary for %s model' % model_name,
- '%s_mapping = {' % model_name.lower()])
- output.extend(" '%s': '%s'," % (
- rev_mapping[ogr_fld], ogr_fld) for ogr_fld in ds[options['layer_key']].fields
+ output.extend(
+ [
+ "",
+ "",
+ "# Auto-generated `LayerMapping` dictionary for %s model"
+ % model_name,
+ "%s_mapping = {" % model_name.lower(),
+ ]
+ )
+ output.extend(
+ " '%s': '%s'," % (rev_mapping[ogr_fld], ogr_fld)
+ for ogr_fld in ds[options["layer_key"]].fields
+ )
+ output.extend(
+ [
+ " '%s': '%s',"
+ % (options["geom_name"], mapping_dict[options["geom_name"]]),
+ "}",
+ ]
)
- output.extend([" '%s': '%s'," % (options['geom_name'], mapping_dict[options['geom_name']]), '}'])
- return '\n'.join(output)
+ return "\n".join(output)
diff --git a/django/contrib/gis/measure.py b/django/contrib/gis/measure.py
index 7e571f14dd..640f0e0068 100644
--- a/django/contrib/gis/measure.py
+++ b/django/contrib/gis/measure.py
@@ -38,7 +38,7 @@ and Geoff Biggs' PhD work on dimensioned units for robotics.
from decimal import Decimal
from functools import total_ordering
-__all__ = ['A', 'Area', 'D', 'Distance']
+__all__ = ["A", "Area", "D", "Distance"]
NUMERIC_TYPES = (int, float, Decimal)
AREA_PREFIX = "sq_"
@@ -73,13 +73,17 @@ class MeasureBase:
if name in self.UNITS:
return self.standard / self.UNITS[name]
else:
- raise AttributeError('Unknown unit type: %s' % name)
+ raise AttributeError("Unknown unit type: %s" % name)
def __repr__(self):
- return '%s(%s=%s)' % (pretty_name(self), self._default_unit, getattr(self, self._default_unit))
+ return "%s(%s=%s)" % (
+ pretty_name(self),
+ self._default_unit,
+ getattr(self, self._default_unit),
+ )
def __str__(self):
- return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
+ return "%s %s" % (getattr(self, self._default_unit), self._default_unit)
# **** Comparison methods ****
@@ -104,49 +108,65 @@ class MeasureBase:
if isinstance(other, self.__class__):
return self.__class__(
default_unit=self._default_unit,
- **{self.STANDARD_UNIT: (self.standard + other.standard)}
+ **{self.STANDARD_UNIT: (self.standard + other.standard)},
)
else:
- raise TypeError('%(class)s must be added with %(class)s' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be added with %(class)s" % {"class": pretty_name(self)}
+ )
def __iadd__(self, other):
if isinstance(other, self.__class__):
self.standard += other.standard
return self
else:
- raise TypeError('%(class)s must be added with %(class)s' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be added with %(class)s" % {"class": pretty_name(self)}
+ )
def __sub__(self, other):
if isinstance(other, self.__class__):
return self.__class__(
default_unit=self._default_unit,
- **{self.STANDARD_UNIT: (self.standard - other.standard)}
+ **{self.STANDARD_UNIT: (self.standard - other.standard)},
)
else:
- raise TypeError('%(class)s must be subtracted from %(class)s' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be subtracted from %(class)s"
+ % {"class": pretty_name(self)}
+ )
def __isub__(self, other):
if isinstance(other, self.__class__):
self.standard -= other.standard
return self
else:
- raise TypeError('%(class)s must be subtracted from %(class)s' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be subtracted from %(class)s"
+ % {"class": pretty_name(self)}
+ )
def __mul__(self, other):
if isinstance(other, NUMERIC_TYPES):
return self.__class__(
default_unit=self._default_unit,
- **{self.STANDARD_UNIT: (self.standard * other)}
+ **{self.STANDARD_UNIT: (self.standard * other)},
)
else:
- raise TypeError('%(class)s must be multiplied with number' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be multiplied with number"
+ % {"class": pretty_name(self)}
+ )
def __imul__(self, other):
if isinstance(other, NUMERIC_TYPES):
self.standard *= float(other)
return self
else:
- raise TypeError('%(class)s must be multiplied with number' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be multiplied with number"
+ % {"class": pretty_name(self)}
+ )
def __rmul__(self, other):
return self * other
@@ -157,17 +177,22 @@ class MeasureBase:
if isinstance(other, NUMERIC_TYPES):
return self.__class__(
default_unit=self._default_unit,
- **{self.STANDARD_UNIT: (self.standard / other)}
+ **{self.STANDARD_UNIT: (self.standard / other)},
)
else:
- raise TypeError('%(class)s must be divided with number or %(class)s' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be divided with number or %(class)s"
+ % {"class": pretty_name(self)}
+ )
def __itruediv__(self, other):
if isinstance(other, NUMERIC_TYPES):
self.standard /= float(other)
return self
else:
- raise TypeError('%(class)s must be divided with number' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be divided with number" % {"class": pretty_name(self)}
+ )
def __bool__(self):
return bool(self.standard)
@@ -199,7 +224,7 @@ class MeasureBase:
val += self.UNITS[u] * value
default_unit = u
else:
- raise AttributeError('Unknown unit type: %s' % unit)
+ raise AttributeError("Unknown unit type: %s" % unit)
return val, default_unit
@classmethod
@@ -217,85 +242,87 @@ class MeasureBase:
elif lower in cls.LALIAS:
return cls.LALIAS[lower]
else:
- raise Exception('Could not find a unit keyword associated with "%s"' % unit_str)
+ raise Exception(
+ 'Could not find a unit keyword associated with "%s"' % unit_str
+ )
class Distance(MeasureBase):
STANDARD_UNIT = "m"
UNITS = {
- 'chain': 20.1168,
- 'chain_benoit': 20.116782,
- 'chain_sears': 20.1167645,
- 'british_chain_benoit': 20.1167824944,
- 'british_chain_sears': 20.1167651216,
- 'british_chain_sears_truncated': 20.116756,
- 'cm': 0.01,
- 'british_ft': 0.304799471539,
- 'british_yd': 0.914398414616,
- 'clarke_ft': 0.3047972654,
- 'clarke_link': 0.201166195164,
- 'fathom': 1.8288,
- 'ft': 0.3048,
- 'furlong': 201.168,
- 'german_m': 1.0000135965,
- 'gold_coast_ft': 0.304799710181508,
- 'indian_yd': 0.914398530744,
- 'inch': 0.0254,
- 'km': 1000.0,
- 'link': 0.201168,
- 'link_benoit': 0.20116782,
- 'link_sears': 0.20116765,
- 'm': 1.0,
- 'mi': 1609.344,
- 'mm': 0.001,
- 'nm': 1852.0,
- 'nm_uk': 1853.184,
- 'rod': 5.0292,
- 'sears_yd': 0.91439841,
- 'survey_ft': 0.304800609601,
- 'um': 0.000001,
- 'yd': 0.9144,
+ "chain": 20.1168,
+ "chain_benoit": 20.116782,
+ "chain_sears": 20.1167645,
+ "british_chain_benoit": 20.1167824944,
+ "british_chain_sears": 20.1167651216,
+ "british_chain_sears_truncated": 20.116756,
+ "cm": 0.01,
+ "british_ft": 0.304799471539,
+ "british_yd": 0.914398414616,
+ "clarke_ft": 0.3047972654,
+ "clarke_link": 0.201166195164,
+ "fathom": 1.8288,
+ "ft": 0.3048,
+ "furlong": 201.168,
+ "german_m": 1.0000135965,
+ "gold_coast_ft": 0.304799710181508,
+ "indian_yd": 0.914398530744,
+ "inch": 0.0254,
+ "km": 1000.0,
+ "link": 0.201168,
+ "link_benoit": 0.20116782,
+ "link_sears": 0.20116765,
+ "m": 1.0,
+ "mi": 1609.344,
+ "mm": 0.001,
+ "nm": 1852.0,
+ "nm_uk": 1853.184,
+ "rod": 5.0292,
+ "sears_yd": 0.91439841,
+ "survey_ft": 0.304800609601,
+ "um": 0.000001,
+ "yd": 0.9144,
}
# Unit aliases for `UNIT` terms encountered in Spatial Reference WKT.
ALIAS = {
- 'centimeter': 'cm',
- 'foot': 'ft',
- 'inches': 'inch',
- 'kilometer': 'km',
- 'kilometre': 'km',
- 'meter': 'm',
- 'metre': 'm',
- 'micrometer': 'um',
- 'micrometre': 'um',
- 'millimeter': 'mm',
- 'millimetre': 'mm',
- 'mile': 'mi',
- 'yard': 'yd',
- 'British chain (Benoit 1895 B)': 'british_chain_benoit',
- 'British chain (Sears 1922)': 'british_chain_sears',
- 'British chain (Sears 1922 truncated)': 'british_chain_sears_truncated',
- 'British foot (Sears 1922)': 'british_ft',
- 'British foot': 'british_ft',
- 'British yard (Sears 1922)': 'british_yd',
- 'British yard': 'british_yd',
- "Clarke's Foot": 'clarke_ft',
- "Clarke's link": 'clarke_link',
- 'Chain (Benoit)': 'chain_benoit',
- 'Chain (Sears)': 'chain_sears',
- 'Foot (International)': 'ft',
- 'Furrow Long': 'furlong',
- 'German legal metre': 'german_m',
- 'Gold Coast foot': 'gold_coast_ft',
- 'Indian yard': 'indian_yd',
- 'Link (Benoit)': 'link_benoit',
- 'Link (Sears)': 'link_sears',
- 'Nautical Mile': 'nm',
- 'Nautical Mile (UK)': 'nm_uk',
- 'US survey foot': 'survey_ft',
- 'U.S. Foot': 'survey_ft',
- 'Yard (Indian)': 'indian_yd',
- 'Yard (Sears)': 'sears_yd'
+ "centimeter": "cm",
+ "foot": "ft",
+ "inches": "inch",
+ "kilometer": "km",
+ "kilometre": "km",
+ "meter": "m",
+ "metre": "m",
+ "micrometer": "um",
+ "micrometre": "um",
+ "millimeter": "mm",
+ "millimetre": "mm",
+ "mile": "mi",
+ "yard": "yd",
+ "British chain (Benoit 1895 B)": "british_chain_benoit",
+ "British chain (Sears 1922)": "british_chain_sears",
+ "British chain (Sears 1922 truncated)": "british_chain_sears_truncated",
+ "British foot (Sears 1922)": "british_ft",
+ "British foot": "british_ft",
+ "British yard (Sears 1922)": "british_yd",
+ "British yard": "british_yd",
+ "Clarke's Foot": "clarke_ft",
+ "Clarke's link": "clarke_link",
+ "Chain (Benoit)": "chain_benoit",
+ "Chain (Sears)": "chain_sears",
+ "Foot (International)": "ft",
+ "Furrow Long": "furlong",
+ "German legal metre": "german_m",
+ "Gold Coast foot": "gold_coast_ft",
+ "Indian yard": "indian_yd",
+ "Link (Benoit)": "link_benoit",
+ "Link (Sears)": "link_sears",
+ "Nautical Mile": "nm",
+ "Nautical Mile (UK)": "nm_uk",
+ "US survey foot": "survey_ft",
+ "U.S. Foot": "survey_ft",
+ "Yard (Indian)": "indian_yd",
+ "Yard (Sears)": "sears_yd",
}
LALIAS = {k.lower(): v for k, v in ALIAS.items()}
@@ -303,34 +330,39 @@ class Distance(MeasureBase):
if isinstance(other, self.__class__):
return Area(
default_unit=AREA_PREFIX + self._default_unit,
- **{AREA_PREFIX + self.STANDARD_UNIT: (self.standard * other.standard)}
+ **{AREA_PREFIX + self.STANDARD_UNIT: (self.standard * other.standard)},
)
elif isinstance(other, NUMERIC_TYPES):
return self.__class__(
default_unit=self._default_unit,
- **{self.STANDARD_UNIT: (self.standard * other)}
+ **{self.STANDARD_UNIT: (self.standard * other)},
)
else:
- raise TypeError('%(distance)s must be multiplied with number or %(distance)s' % {
- "distance": pretty_name(self.__class__),
- })
+ raise TypeError(
+ "%(distance)s must be multiplied with number or %(distance)s"
+ % {
+ "distance": pretty_name(self.__class__),
+ }
+ )
class Area(MeasureBase):
STANDARD_UNIT = AREA_PREFIX + Distance.STANDARD_UNIT
# Getting the square units values and the alias dictionary.
- UNITS = {'%s%s' % (AREA_PREFIX, k): v ** 2 for k, v in Distance.UNITS.items()}
- ALIAS = {k: '%s%s' % (AREA_PREFIX, v) for k, v in Distance.ALIAS.items()}
+ UNITS = {"%s%s" % (AREA_PREFIX, k): v**2 for k, v in Distance.UNITS.items()}
+ ALIAS = {k: "%s%s" % (AREA_PREFIX, v) for k, v in Distance.ALIAS.items()}
LALIAS = {k.lower(): v for k, v in ALIAS.items()}
def __truediv__(self, other):
if isinstance(other, NUMERIC_TYPES):
return self.__class__(
default_unit=self._default_unit,
- **{self.STANDARD_UNIT: (self.standard / other)}
+ **{self.STANDARD_UNIT: (self.standard / other)},
)
else:
- raise TypeError('%(class)s must be divided by a number' % {"class": pretty_name(self)})
+ raise TypeError(
+ "%(class)s must be divided by a number" % {"class": pretty_name(self)}
+ )
# Shortcuts
diff --git a/django/contrib/gis/ptr.py b/django/contrib/gis/ptr.py
index a5a117a19a..6754701613 100644
--- a/django/contrib/gis/ptr.py
+++ b/django/contrib/gis/ptr.py
@@ -6,6 +6,7 @@ class CPointerBase:
Base class for objects that have a pointer access property
that controls access to the underlying C pointer.
"""
+
_ptr = None # Initially the pointer is NULL.
ptr_type = c_void_p
destructor = None
@@ -17,14 +18,16 @@ class CPointerBase:
# aren't passed to routines -- that's very bad.
if self._ptr:
return self._ptr
- raise self.null_ptr_exception_class('NULL %s pointer encountered.' % self.__class__.__name__)
+ raise self.null_ptr_exception_class(
+ "NULL %s pointer encountered." % self.__class__.__name__
+ )
@ptr.setter
def ptr(self, ptr):
# Only allow the pointer to be set with pointers of the compatible
# type or None (NULL).
if not (ptr is None or isinstance(ptr, self.ptr_type)):
- raise TypeError('Incompatible pointer type: %s.' % type(ptr))
+ raise TypeError("Incompatible pointer type: %s." % type(ptr))
self._ptr = ptr
def __del__(self):
diff --git a/django/contrib/gis/serializers/geojson.py b/django/contrib/gis/serializers/geojson.py
index 0e4f744774..f90d3544e7 100644
--- a/django/contrib/gis/serializers/geojson.py
+++ b/django/contrib/gis/serializers/geojson.py
@@ -9,12 +9,16 @@ class Serializer(JSONSerializer):
"""
Convert a queryset to GeoJSON, http://geojson.org/
"""
+
def _init_options(self):
super()._init_options()
- self.geometry_field = self.json_kwargs.pop('geometry_field', None)
- self.srid = self.json_kwargs.pop('srid', 4326)
- if (self.selected_fields is not None and self.geometry_field is not None and
- self.geometry_field not in self.selected_fields):
+ self.geometry_field = self.json_kwargs.pop("geometry_field", None)
+ self.srid = self.json_kwargs.pop("srid", 4326)
+ if (
+ self.selected_fields is not None
+ and self.geometry_field is not None
+ and self.geometry_field not in self.selected_fields
+ ):
self.selected_fields = [*self.selected_fields, self.geometry_field]
def start_serialization(self):
@@ -22,10 +26,11 @@ class Serializer(JSONSerializer):
self._cts = {} # cache of CoordTransform's
self.stream.write(
'{"type": "FeatureCollection", "crs": {"type": "name", "properties": {"name": "EPSG:%d"}},'
- ' "features": [' % self.srid)
+ ' "features": [' % self.srid
+ )
def end_serialization(self):
- self.stream.write(']}')
+ self.stream.write("]}")
def start_object(self, obj):
super().start_object(obj)
@@ -33,7 +38,7 @@ class Serializer(JSONSerializer):
if self.geometry_field is None:
# Find the first declared geometry field
for field in obj._meta.fields:
- if hasattr(field, 'geom_type'):
+ if hasattr(field, "geom_type"):
self.geometry_field = field.name
break
@@ -42,15 +47,18 @@ class Serializer(JSONSerializer):
"type": "Feature",
"properties": self._current,
}
- if ((self.selected_fields is None or 'pk' in self.selected_fields) and
- 'pk' not in data["properties"]):
+ if (
+ self.selected_fields is None or "pk" in self.selected_fields
+ ) and "pk" not in data["properties"]:
data["properties"]["pk"] = obj._meta.pk.value_to_string(obj)
if self._geometry:
if self._geometry.srid != self.srid:
# If needed, transform the geometry in the srid of the global geojson srid
if self._geometry.srid not in self._cts:
srs = SpatialReference(self.srid)
- self._cts[self._geometry.srid] = CoordTransform(self._geometry.srs, srs)
+ self._cts[self._geometry.srid] = CoordTransform(
+ self._geometry.srs, srs
+ )
self._geometry.transform(self._cts[self._geometry.srid])
data["geometry"] = json.loads(self._geometry.geojson)
else:
diff --git a/django/contrib/gis/shortcuts.py b/django/contrib/gis/shortcuts.py
index aa68140b62..33ff2acb06 100644
--- a/django/contrib/gis/shortcuts.py
+++ b/django/contrib/gis/shortcuts.py
@@ -15,8 +15,8 @@ except ImportError:
def compress_kml(kml):
"Return compressed KMZ from the given KML string."
kmz = BytesIO()
- with zipfile.ZipFile(kmz, 'a', zipfile.ZIP_DEFLATED) as zf:
- zf.writestr('doc.kml', kml.encode(settings.DEFAULT_CHARSET))
+ with zipfile.ZipFile(kmz, "a", zipfile.ZIP_DEFLATED) as zf:
+ zf.writestr("doc.kml", kml.encode(settings.DEFAULT_CHARSET))
kmz.seek(0)
return kmz.read()
@@ -25,7 +25,7 @@ def render_to_kml(*args, **kwargs):
"Render the response as KML (using the correct MIME type)."
return HttpResponse(
loader.render_to_string(*args, **kwargs),
- content_type='application/vnd.google-earth.kml+xml',
+ content_type="application/vnd.google-earth.kml+xml",
)
@@ -36,5 +36,5 @@ def render_to_kmz(*args, **kwargs):
"""
return HttpResponse(
compress_kml(loader.render_to_string(*args, **kwargs)),
- content_type='application/vnd.google-earth.kmz',
+ content_type="application/vnd.google-earth.kmz",
)
diff --git a/django/contrib/gis/sitemaps/__init__.py b/django/contrib/gis/sitemaps/__init__.py
index 7337e65a9c..3654bfc80b 100644
--- a/django/contrib/gis/sitemaps/__init__.py
+++ b/django/contrib/gis/sitemaps/__init__.py
@@ -1,4 +1,4 @@
# Geo-enabled Sitemap classes.
from django.contrib.gis.sitemaps.kml import KMLSitemap, KMZSitemap
-__all__ = ['KMLSitemap', 'KMZSitemap']
+__all__ = ["KMLSitemap", "KMZSitemap"]
diff --git a/django/contrib/gis/sitemaps/kml.py b/django/contrib/gis/sitemaps/kml.py
index 103dc20408..5ec089d6f5 100644
--- a/django/contrib/gis/sitemaps/kml.py
+++ b/django/contrib/gis/sitemaps/kml.py
@@ -9,7 +9,8 @@ class KMLSitemap(Sitemap):
"""
A minimal hook to produce KML sitemaps.
"""
- geo_format = 'kml'
+
+ geo_format = "kml"
def __init__(self, locations=None):
# If no locations specified, then we try to build for
@@ -31,15 +32,21 @@ class KMLSitemap(Sitemap):
if isinstance(source, models.base.ModelBase):
for field in source._meta.fields:
if isinstance(field, GeometryField):
- kml_sources.append((source._meta.app_label,
- source._meta.model_name,
- field.name))
+ kml_sources.append(
+ (
+ source._meta.app_label,
+ source._meta.model_name,
+ field.name,
+ )
+ )
elif isinstance(source, (list, tuple)):
if len(source) != 3:
- raise ValueError('Must specify a 3-tuple of (app_label, module_name, field_name).')
+ raise ValueError(
+ "Must specify a 3-tuple of (app_label, module_name, field_name)."
+ )
kml_sources.append(source)
else:
- raise TypeError('KML Sources must be a model or a 3-tuple.')
+ raise TypeError("KML Sources must be a model or a 3-tuple.")
return kml_sources
def get_urls(self, page=1, site=None, protocol=None):
@@ -49,7 +56,7 @@ class KMLSitemap(Sitemap):
"""
urls = Sitemap.get_urls(self, page=page, site=site, protocol=protocol)
for url in urls:
- url['geo_format'] = self.geo_format
+ url["geo_format"] = self.geo_format
return urls
def items(self):
@@ -57,14 +64,14 @@ class KMLSitemap(Sitemap):
def location(self, obj):
return reverse(
- 'django.contrib.gis.sitemaps.views.%s' % self.geo_format,
+ "django.contrib.gis.sitemaps.views.%s" % self.geo_format,
kwargs={
- 'label': obj[0],
- 'model': obj[1],
- 'field_name': obj[2],
+ "label": obj[0],
+ "model": obj[1],
+ "field_name": obj[2],
},
)
class KMZSitemap(KMLSitemap):
- geo_format = 'kmz'
+ geo_format = "kmz"
diff --git a/django/contrib/gis/sitemaps/views.py b/django/contrib/gis/sitemaps/views.py
index be91d929f6..17eb54e60c 100644
--- a/django/contrib/gis/sitemaps/views.py
+++ b/django/contrib/gis/sitemaps/views.py
@@ -17,7 +17,10 @@ def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB
try:
klass = apps.get_model(label, model)
except LookupError:
- raise Http404('You must supply a valid app label and module name. Got "%s.%s"' % (label, model))
+ raise Http404(
+ 'You must supply a valid app label and module name. Got "%s.%s"'
+ % (label, model)
+ )
if field_name:
try:
@@ -25,7 +28,7 @@ def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB
if not isinstance(field, GeometryField):
raise FieldDoesNotExist
except FieldDoesNotExist:
- raise Http404('Invalid geometry field.')
+ raise Http404("Invalid geometry field.")
connection = connections[using]
@@ -38,8 +41,9 @@ def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB
placemarks = []
if connection.features.has_Transform_function:
qs = klass._default_manager.using(using).annotate(
- **{'%s_4326' % field_name: Transform(field_name, 4326)})
- field_name += '_4326'
+ **{"%s_4326" % field_name: Transform(field_name, 4326)}
+ )
+ field_name += "_4326"
else:
qs = klass._default_manager.using(using).all()
for mod in qs:
@@ -51,7 +55,7 @@ def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB
render = render_to_kmz
else:
render = render_to_kml
- return render('gis/kml/placemarks.kml', {'places': placemarks})
+ return render("gis/kml/placemarks.kml", {"places": placemarks})
def kmz(request, label, model, field_name=None, using=DEFAULT_DB_ALIAS):
diff --git a/django/contrib/gis/utils/__init__.py b/django/contrib/gis/utils/__init__.py
index c195ded932..26334fb6a4 100644
--- a/django/contrib/gis/utils/__init__.py
+++ b/django/contrib/gis/utils/__init__.py
@@ -10,7 +10,8 @@ try:
# LayerMapping requires DJANGO_SETTINGS_MODULE to be set,
# and ImproperlyConfigured is raised if that's not the case.
from django.contrib.gis.utils.layermapping import ( # NOQA
- LayerMapError, LayerMapping,
+ LayerMapError,
+ LayerMapping,
)
except ImproperlyConfigured:
pass
diff --git a/django/contrib/gis/utils/layermapping.py b/django/contrib/gis/utils/layermapping.py
index 3c78085489..bad4c05fb8 100644
--- a/django/contrib/gis/utils/layermapping.py
+++ b/django/contrib/gis/utils/layermapping.py
@@ -7,16 +7,26 @@
https://docs.djangoproject.com/en/dev/ref/contrib/gis/layermapping/
"""
import sys
-from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
+from decimal import Decimal
+from decimal import InvalidOperation as DecimalInvalidOperation
from pathlib import Path
from django.contrib.gis.db.models import GeometryField
from django.contrib.gis.gdal import (
- CoordTransform, DataSource, GDALException, OGRGeometry, OGRGeomType,
+ CoordTransform,
+ DataSource,
+ GDALException,
+ OGRGeometry,
+ OGRGeomType,
SpatialReference,
)
from django.contrib.gis.gdal.field import (
- OFTDate, OFTDateTime, OFTInteger, OFTInteger64, OFTReal, OFTString,
+ OFTDate,
+ OFTDateTime,
+ OFTInteger,
+ OFTInteger64,
+ OFTReal,
+ OFTString,
OFTTime,
)
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist
@@ -50,12 +60,12 @@ class LayerMapping:
# Acceptable 'base' types for a multi-geometry type.
MULTI_TYPES = {
- 1: OGRGeomType('MultiPoint'),
- 2: OGRGeomType('MultiLineString'),
- 3: OGRGeomType('MultiPolygon'),
- OGRGeomType('Point25D').num: OGRGeomType('MultiPoint25D'),
- OGRGeomType('LineString25D').num: OGRGeomType('MultiLineString25D'),
- OGRGeomType('Polygon25D').num: OGRGeomType('MultiPolygon25D'),
+ 1: OGRGeomType("MultiPoint"),
+ 2: OGRGeomType("MultiLineString"),
+ 3: OGRGeomType("MultiPolygon"),
+ OGRGeomType("Point25D").num: OGRGeomType("MultiPoint25D"),
+ OGRGeomType("LineString25D").num: OGRGeomType("MultiLineString25D"),
+ OGRGeomType("Polygon25D").num: OGRGeomType("MultiPolygon25D"),
}
# Acceptable Django field types and corresponding acceptable OGR
# counterparts.
@@ -83,10 +93,19 @@ class LayerMapping:
models.PositiveSmallIntegerField: (OFTInteger, OFTReal, OFTString),
}
- def __init__(self, model, data, mapping, layer=0,
- source_srs=None, encoding='utf-8',
- transaction_mode='commit_on_success',
- transform=True, unique=None, using=None):
+ def __init__(
+ self,
+ model,
+ data,
+ mapping,
+ layer=0,
+ source_srs=None,
+ encoding="utf-8",
+ transaction_mode="commit_on_success",
+ transform=True,
+ unique=None,
+ using=None,
+ ):
"""
A LayerMapping object is initialized using the given Model (not an instance),
a DataSource (or string path to an OGR-supported data file), and a mapping
@@ -133,6 +152,7 @@ class LayerMapping:
# Making sure the encoding exists, if not a LookupError
# exception will be thrown.
from codecs import lookup
+
lookup(encoding)
self.encoding = encoding
else:
@@ -140,7 +160,7 @@ class LayerMapping:
if unique:
self.check_unique(unique)
- transaction_mode = 'autocommit' # Has to be set to autocommit.
+ transaction_mode = "autocommit" # Has to be set to autocommit.
self.unique = unique
else:
self.unique = None
@@ -148,12 +168,12 @@ class LayerMapping:
# Setting the transaction decorator with the function in the
# transaction modes dictionary.
self.transaction_mode = transaction_mode
- if transaction_mode == 'autocommit':
+ if transaction_mode == "autocommit":
self.transaction_decorator = None
- elif transaction_mode == 'commit_on_success':
+ elif transaction_mode == "commit_on_success":
self.transaction_decorator = transaction.atomic
else:
- raise LayerMapError('Unrecognized transaction mode: %s' % transaction_mode)
+ raise LayerMapError("Unrecognized transaction mode: %s" % transaction_mode)
# #### Checking routines used during initialization ####
def check_fid_range(self, fid_range):
@@ -190,7 +210,9 @@ class LayerMapping:
try:
idx = ogr_fields.index(ogr_map_fld)
except ValueError:
- raise LayerMapError('Given mapping OGR field "%s" not found in OGR Layer.' % ogr_map_fld)
+ raise LayerMapError(
+ 'Given mapping OGR field "%s" not found in OGR Layer.' % ogr_map_fld
+ )
return idx
# No need to increment through each feature in the model, simply check
@@ -201,32 +223,43 @@ class LayerMapping:
try:
model_field = self.model._meta.get_field(field_name)
except FieldDoesNotExist:
- raise LayerMapError('Given mapping field "%s" not in given Model fields.' % field_name)
+ raise LayerMapError(
+ 'Given mapping field "%s" not in given Model fields.' % field_name
+ )
# Getting the string name for the Django field class (e.g., 'PointField').
fld_name = model_field.__class__.__name__
if isinstance(model_field, GeometryField):
if self.geom_field:
- raise LayerMapError('LayerMapping does not support more than one GeometryField per model.')
+ raise LayerMapError(
+ "LayerMapping does not support more than one GeometryField per model."
+ )
# Getting the coordinate dimension of the geometry field.
coord_dim = model_field.dim
try:
if coord_dim == 3:
- gtype = OGRGeomType(ogr_name + '25D')
+ gtype = OGRGeomType(ogr_name + "25D")
else:
gtype = OGRGeomType(ogr_name)
except GDALException:
- raise LayerMapError('Invalid mapping for GeometryField "%s".' % field_name)
+ raise LayerMapError(
+ 'Invalid mapping for GeometryField "%s".' % field_name
+ )
# Making sure that the OGR Layer's Geometry is compatible.
ltype = self.layer.geom_type
- if not (ltype.name.startswith(gtype.name) or self.make_multi(ltype, model_field)):
- raise LayerMapError('Invalid mapping geometry; model has %s%s, '
- 'layer geometry type is %s.' %
- (fld_name, '(dim=3)' if coord_dim == 3 else '', ltype))
+ if not (
+ ltype.name.startswith(gtype.name)
+ or self.make_multi(ltype, model_field)
+ ):
+ raise LayerMapError(
+ "Invalid mapping geometry; model has %s%s, "
+ "layer geometry type is %s."
+ % (fld_name, "(dim=3)" if coord_dim == 3 else "", ltype)
+ )
# Setting the `geom_field` attribute w/the name of the model field
# that is a Geometry. Also setting the coordinate dimension
@@ -243,15 +276,19 @@ class LayerMapping:
try:
rel_model._meta.get_field(rel_name)
except FieldDoesNotExist:
- raise LayerMapError('ForeignKey mapping field "%s" not in %s fields.' %
- (rel_name, rel_model.__class__.__name__))
+ raise LayerMapError(
+ 'ForeignKey mapping field "%s" not in %s fields.'
+ % (rel_name, rel_model.__class__.__name__)
+ )
fields_val = rel_model
else:
- raise TypeError('ForeignKey mapping must be of dictionary type.')
+ raise TypeError("ForeignKey mapping must be of dictionary type.")
else:
# Is the model field type supported by LayerMapping?
if model_field.__class__ not in self.FIELD_TYPES:
- raise LayerMapError('Django field type "%s" has no OGR mapping (yet).' % fld_name)
+ raise LayerMapError(
+ 'Django field type "%s" has no OGR mapping (yet).' % fld_name
+ )
# Is the OGR field in the Layer?
idx = check_ogr_fld(ogr_name)
@@ -259,8 +296,10 @@ class LayerMapping:
# Can the OGR field type be mapped to the Django field type?
if not issubclass(ogr_field, self.FIELD_TYPES[model_field.__class__]):
- raise LayerMapError('OGR field "%s" (of type %s) cannot be mapped to Django %s.' %
- (ogr_field, ogr_field.__name__, fld_name))
+ raise LayerMapError(
+ 'OGR field "%s" (of type %s) cannot be mapped to Django %s.'
+ % (ogr_field, ogr_field.__name__, fld_name)
+ )
fields_val = model_field
self.fields[field_name] = fields_val
@@ -279,7 +318,7 @@ class LayerMapping:
sr = self.layer.srs
if not sr:
- raise LayerMapError('No source reference system defined.')
+ raise LayerMapError("No source reference system defined.")
else:
return sr
@@ -295,7 +334,9 @@ class LayerMapping:
if unique not in self.mapping:
raise ValueError
else:
- raise TypeError('Unique keyword argument must be set with a tuple, list, or string.')
+ raise TypeError(
+ "Unique keyword argument must be set with a tuple, list, or string."
+ )
# Keyword argument retrieval routines ####
def feature_kwargs(self, feat):
@@ -316,7 +357,7 @@ class LayerMapping:
try:
val = self.verify_geom(feat.geom, model_field)
except GDALException:
- raise LayerMapError('Could not retrieve geometry from feature.')
+ raise LayerMapError("Could not retrieve geometry from feature.")
elif isinstance(model_field, models.base.ModelBase):
# The related _model_, not a field was passed in -- indicating
# another mapping for the related Model.
@@ -348,23 +389,34 @@ class LayerMapping:
Verify if the OGR Field contents are acceptable to the model field. If
they are, return the verified value, otherwise raise an exception.
"""
- if (isinstance(ogr_field, OFTString) and
- isinstance(model_field, (models.CharField, models.TextField))):
+ if isinstance(ogr_field, OFTString) and isinstance(
+ model_field, (models.CharField, models.TextField)
+ ):
if self.encoding and ogr_field.value is not None:
# The encoding for OGR data sources may be specified here
# (e.g., 'cp437' for Census Bureau boundary files).
val = force_str(ogr_field.value, self.encoding)
else:
val = ogr_field.value
- if model_field.max_length and val is not None and len(val) > model_field.max_length:
- raise InvalidString('%s model field maximum string length is %s, given %s characters.' %
- (model_field.name, model_field.max_length, len(val)))
- elif isinstance(ogr_field, OFTReal) and isinstance(model_field, models.DecimalField):
+ if (
+ model_field.max_length
+ and val is not None
+ and len(val) > model_field.max_length
+ ):
+ raise InvalidString(
+ "%s model field maximum string length is %s, given %s characters."
+ % (model_field.name, model_field.max_length, len(val))
+ )
+ elif isinstance(ogr_field, OFTReal) and isinstance(
+ model_field, models.DecimalField
+ ):
try:
# Creating an instance of the Decimal value to use.
d = Decimal(str(ogr_field.value))
except DecimalInvalidOperation:
- raise InvalidDecimal('Could not construct decimal from: %s' % ogr_field.value)
+ raise InvalidDecimal(
+ "Could not construct decimal from: %s" % ogr_field.value
+ )
# Getting the decimal value as a tuple.
dtup = d.as_tuple()
@@ -385,17 +437,21 @@ class LayerMapping:
# InvalidDecimal exception.
if n_prec > max_prec:
raise InvalidDecimal(
- 'A DecimalField with max_digits %d, decimal_places %d must '
- 'round to an absolute value less than 10^%d.' %
- (model_field.max_digits, model_field.decimal_places, max_prec)
+ "A DecimalField with max_digits %d, decimal_places %d must "
+ "round to an absolute value less than 10^%d."
+ % (model_field.max_digits, model_field.decimal_places, max_prec)
)
val = d
- elif isinstance(ogr_field, (OFTReal, OFTString)) and isinstance(model_field, models.IntegerField):
+ elif isinstance(ogr_field, (OFTReal, OFTString)) and isinstance(
+ model_field, models.IntegerField
+ ):
# Attempt to convert any OFTReal and OFTString value to an OFTInteger.
try:
val = int(ogr_field.value)
except ValueError:
- raise InvalidInteger('Could not construct integer from: %s' % ogr_field.value)
+ raise InvalidInteger(
+ "Could not construct integer from: %s" % ogr_field.value
+ )
else:
val = ogr_field.value
return val
@@ -412,15 +468,17 @@ class LayerMapping:
# Constructing and verifying the related model keyword arguments.
fk_kwargs = {}
for field_name, ogr_name in rel_mapping.items():
- fk_kwargs[field_name] = self.verify_ogr_field(feat[ogr_name], rel_model._meta.get_field(field_name))
+ fk_kwargs[field_name] = self.verify_ogr_field(
+ feat[ogr_name], rel_model._meta.get_field(field_name)
+ )
# Attempting to retrieve and return the related model.
try:
return rel_model.objects.using(self.using).get(**fk_kwargs)
except ObjectDoesNotExist:
raise MissingForeignKey(
- 'No ForeignKey %s model found with keyword arguments: %s' %
- (rel_model.__name__, fk_kwargs)
+ "No ForeignKey %s model found with keyword arguments: %s"
+ % (rel_model.__name__, fk_kwargs)
)
def verify_geom(self, geom, model_field):
@@ -456,13 +514,17 @@ class LayerMapping:
SpatialRefSys = self.spatial_backend.spatial_ref_sys()
try:
# Getting the target spatial reference system
- target_srs = SpatialRefSys.objects.using(self.using).get(srid=self.geo_field.srid).srs
+ target_srs = (
+ SpatialRefSys.objects.using(self.using)
+ .get(srid=self.geo_field.srid)
+ .srs
+ )
# Creating the CoordTransform object
return CoordTransform(self.source_srs, target_srs)
except Exception as exc:
raise LayerMapError(
- 'Could not translate between the data source and model geometry.'
+ "Could not translate between the data source and model geometry."
) from exc
def geometry_field(self):
@@ -477,11 +539,21 @@ class LayerMapping:
Given the OGRGeomType for a geometry and its associated GeometryField,
determine whether the geometry should be turned into a GeometryCollection.
"""
- return (geom_type.num in self.MULTI_TYPES and
- model_field.__class__.__name__ == 'Multi%s' % geom_type.django)
-
- def save(self, verbose=False, fid_range=False, step=False,
- progress=False, silent=False, stream=sys.stdout, strict=False):
+ return (
+ geom_type.num in self.MULTI_TYPES
+ and model_field.__class__.__name__ == "Multi%s" % geom_type.django
+ )
+
+ def save(
+ self,
+ verbose=False,
+ fid_range=False,
+ step=False,
+ progress=False,
+ silent=False,
+ stream=sys.stdout,
+ strict=False,
+ ):
"""
Save the contents from the OGR DataSource Layer into the database
according to the mapping dictionary given at initialization.
@@ -547,7 +619,9 @@ class LayerMapping:
if strict:
raise
elif not silent:
- stream.write('Ignoring Feature ID %s because: %s\n' % (feat.fid, msg))
+ stream.write(
+ "Ignoring Feature ID %s because: %s\n" % (feat.fid, msg)
+ )
else:
# Constructing the model using the keyword args
is_update = False
@@ -585,23 +659,29 @@ class LayerMapping:
m.save(using=self.using)
num_saved += 1
if verbose:
- stream.write('%s: %s\n' % ('Updated' if is_update else 'Saved', m))
+ stream.write(
+ "%s: %s\n" % ("Updated" if is_update else "Saved", m)
+ )
except Exception as msg:
if strict:
# Bailing out if the `strict` keyword is set.
if not silent:
stream.write(
- 'Failed to save the feature (id: %s) into the '
- 'model with the keyword arguments:\n' % feat.fid
+ "Failed to save the feature (id: %s) into the "
+ "model with the keyword arguments:\n" % feat.fid
)
- stream.write('%s\n' % kwargs)
+ stream.write("%s\n" % kwargs)
raise
elif not silent:
- stream.write('Failed to save %s:\n %s\nContinuing\n' % (kwargs, msg))
+ stream.write(
+ "Failed to save %s:\n %s\nContinuing\n" % (kwargs, msg)
+ )
# Printing progress information, if requested.
if progress and num_feat % progress_interval == 0:
- stream.write('Processed %d features, saved %d ...\n' % (num_feat, num_saved))
+ stream.write(
+ "Processed %d features, saved %d ...\n" % (num_feat, num_saved)
+ )
# Only used for status output purposes -- incremental saving uses the
# values returned here.
@@ -614,7 +694,9 @@ class LayerMapping:
if step and isinstance(step, int) and step < nfeat:
# Incremental saving is requested at the given interval (step)
if default_range:
- raise LayerMapError('The `step` keyword may not be used in conjunction with the `fid_range` keyword.')
+ raise LayerMapError(
+ "The `step` keyword may not be used in conjunction with the `fid_range` keyword."
+ )
beg, num_feat, num_saved = (0, 0, 0)
indices = range(step, nfeat, step)
n_i = len(indices)
@@ -631,7 +713,9 @@ class LayerMapping:
num_feat, num_saved = _save(step_slice, num_feat, num_saved)
beg = end
except Exception: # Deliberately catch everything
- stream.write('%s\nFailed to save slice: %s\n' % ('=-' * 20, step_slice))
+ stream.write(
+ "%s\nFailed to save slice: %s\n" % ("=-" * 20, step_slice)
+ )
raise
else:
# Otherwise, just calling the previously defined _save() function.
diff --git a/django/contrib/gis/utils/ogrinfo.py b/django/contrib/gis/utils/ogrinfo.py
index 324e41a0ad..eafa23ccae 100644
--- a/django/contrib/gis/utils/ogrinfo.py
+++ b/django/contrib/gis/utils/ogrinfo.py
@@ -20,7 +20,9 @@ def ogrinfo(data_source, num_features=10):
elif isinstance(data_source, DataSource):
pass
else:
- raise Exception('Data source parameter must be a string or a DataSource object.')
+ raise Exception(
+ "Data source parameter must be a string or a DataSource object."
+ )
for i, layer in enumerate(data_source):
print("data source : %s" % data_source.name)
@@ -44,8 +46,8 @@ def ogrinfo(data_source, num_features=10):
if isinstance(val, str):
val_fmt = ' ("%s")'
else:
- val_fmt = ' (%s)'
+ val_fmt = " (%s)"
output += val_fmt % val
else:
- output += ' (None)'
+ output += " (None)"
print(output)
diff --git a/django/contrib/gis/utils/ogrinspect.py b/django/contrib/gis/utils/ogrinspect.py
index 8c83fd5a43..c50b39ad14 100644
--- a/django/contrib/gis/utils/ogrinspect.py
+++ b/django/contrib/gis/utils/ogrinspect.py
@@ -5,12 +5,17 @@ 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, OFTInteger64, OFTReal, OFTString,
+ OFTDate,
+ OFTDateTime,
+ OFTInteger,
+ OFTInteger64,
+ OFTReal,
+ OFTString,
OFTTime,
)
-def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
+def mapping(data_source, geom_name="geom", layer_key=0, multi_geom=False):
"""
Given a DataSource, generate a dictionary that may be used
for invoking the LayerMapping utility.
@@ -30,7 +35,9 @@ def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
elif isinstance(data_source, DataSource):
pass
else:
- raise TypeError('Data source parameter must be a string or a DataSource object.')
+ raise TypeError(
+ "Data source parameter must be a string or a DataSource object."
+ )
# Creating the dictionary.
_mapping = {}
@@ -38,8 +45,8 @@ def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
# Generating the field name for each field in the layer.
for field in data_source[layer_key].fields:
mfield = field.lower()
- if mfield[-1:] == '_':
- mfield += 'field'
+ if mfield[-1:] == "_":
+ mfield += "field"
_mapping[mfield] = field
gtype = data_source[layer_key].geom_type
if multi_geom:
@@ -116,12 +123,22 @@ def ogrinspect(*args, **kwargs):
Note: Call the _ogrinspect() helper to do the heavy lifting.
"""
- return '\n'.join(_ogrinspect(*args, **kwargs))
-
-
-def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=None,
- multi_geom=False, name_field=None, imports=True,
- decimal=False, blank=False, null=False):
+ return "\n".join(_ogrinspect(*args, **kwargs))
+
+
+def _ogrinspect(
+ data_source,
+ model_name,
+ geom_name="geom",
+ layer_key=0,
+ srid=None,
+ multi_geom=False,
+ name_field=None,
+ imports=True,
+ decimal=False,
+ blank=False,
+ null=False,
+):
"""
Helper routine for `ogrinspect` that generates GeoDjango models corresponding
to the given data source. See the `ogrinspect` docstring for more details.
@@ -132,7 +149,9 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non
elif isinstance(data_source, DataSource):
pass
else:
- raise TypeError('Data source parameter must be a string or a DataSource object.')
+ raise TypeError(
+ "Data source parameter must be a string or a DataSource object."
+ )
# Getting the layer corresponding to the layer key and getting
# a string listing of all OGR fields in the Layer.
@@ -148,6 +167,7 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non
return [s.lower() for s in ogr_fields]
else:
return []
+
null_fields = process_kwarg(null)
blank_fields = process_kwarg(blank)
decimal_fields = process_kwarg(decimal)
@@ -156,29 +176,30 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non
def get_kwargs_str(field_name):
kwlist = []
if field_name.lower() in null_fields:
- kwlist.append('null=True')
+ kwlist.append("null=True")
if field_name.lower() in blank_fields:
- kwlist.append('blank=True')
+ kwlist.append("blank=True")
if kwlist:
- return ', ' + ', '.join(kwlist)
+ return ", " + ", ".join(kwlist)
else:
- return ''
+ return ""
# For those wishing to disable the imports.
if imports:
- yield '# This is an auto-generated Django model module created by ogrinspect.'
- yield 'from django.contrib.gis.db import models'
- yield ''
- yield ''
+ yield "# This is an auto-generated Django model module created by ogrinspect."
+ yield "from django.contrib.gis.db import models"
+ yield ""
+ yield ""
- yield 'class %s(models.Model):' % model_name
+ yield "class %s(models.Model):" % model_name
for field_name, width, precision, field_type in zip(
- ogr_fields, layer.field_widths, layer.field_precisions, layer.field_types):
+ ogr_fields, layer.field_widths, layer.field_precisions, layer.field_types
+ ):
# The model field name.
mfield = field_name.lower()
- if mfield[-1:] == '_':
- mfield += 'field'
+ if mfield[-1:] == "_":
+ mfield += "field"
# Getting the keyword args string.
kwargs_str = get_kwargs_str(field_name)
@@ -188,25 +209,32 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non
# may also be mapped to `DecimalField` if specified in the
# `decimal` keyword.
if field_name.lower() in decimal_fields:
- yield ' %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)' % (
- mfield, width, precision, kwargs_str
+ yield " %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)" % (
+ mfield,
+ width,
+ precision,
+ kwargs_str,
)
else:
- yield ' %s = models.FloatField(%s)' % (mfield, kwargs_str[2:])
+ yield " %s = models.FloatField(%s)" % (mfield, kwargs_str[2:])
elif field_type is OFTInteger:
- yield ' %s = models.IntegerField(%s)' % (mfield, kwargs_str[2:])
+ yield " %s = models.IntegerField(%s)" % (mfield, kwargs_str[2:])
elif field_type is OFTInteger64:
- yield ' %s = models.BigIntegerField(%s)' % (mfield, kwargs_str[2:])
+ 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)
+ yield " %s = models.CharField(max_length=%s%s)" % (
+ mfield,
+ width,
+ kwargs_str,
+ )
elif field_type is OFTDate:
- yield ' %s = models.DateField(%s)' % (mfield, kwargs_str[2:])
+ yield " %s = models.DateField(%s)" % (mfield, kwargs_str[2:])
elif field_type is OFTDateTime:
- yield ' %s = models.DateTimeField(%s)' % (mfield, kwargs_str[2:])
+ yield " %s = models.DateTimeField(%s)" % (mfield, kwargs_str[2:])
elif field_type is OFTTime:
- yield ' %s = models.TimeField(%s)' % (mfield, kwargs_str[2:])
+ yield " %s = models.TimeField(%s)" % (mfield, kwargs_str[2:])
else:
- raise TypeError('Unknown field type %s in %s' % (field_type, mfield))
+ raise TypeError("Unknown field type %s in %s" % (field_type, mfield))
# TODO: Autodetection of multigeometry types (see #7218).
gtype = layer.geom_type
@@ -217,21 +245,21 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non
# Setting up the SRID keyword string.
if srid is None:
if layer.srs is None:
- srid_str = 'srid=-1'
+ srid_str = "srid=-1"
else:
srid = layer.srs.srid
if srid is None:
- srid_str = 'srid=-1'
+ srid_str = "srid=-1"
elif srid == 4326:
# WGS84 is already the default.
- srid_str = ''
+ srid_str = ""
else:
- srid_str = 'srid=%s' % srid
+ srid_str = "srid=%s" % srid
else:
- srid_str = 'srid=%s' % srid
+ srid_str = "srid=%s" % srid
- yield ' %s = models.%s(%s)' % (geom_name, geom_field, srid_str)
+ yield " %s = models.%s(%s)" % (geom_name, geom_field, srid_str)
if name_field:
- yield ''
- yield ' def __str__(self): return self.%s' % name_field
+ yield ""
+ yield " def __str__(self): return self.%s" % name_field
diff --git a/django/contrib/gis/utils/srs.py b/django/contrib/gis/utils/srs.py
index d44d340383..2204767923 100644
--- a/django/contrib/gis/utils/srs.py
+++ b/django/contrib/gis/utils/srs.py
@@ -2,8 +2,9 @@ from django.contrib.gis.gdal import SpatialReference
from django.db import DEFAULT_DB_ALIAS, connections
-def add_srs_entry(srs, auth_name='EPSG', auth_srid=None, ref_sys_name=None,
- database=None):
+def add_srs_entry(
+ srs, auth_name="EPSG", auth_srid=None, ref_sys_name=None, database=None
+):
"""
Take a GDAL SpatialReference system and add its information to the
`spatial_ref_sys` table of the spatial backend. Doing this enables
@@ -35,12 +36,10 @@ def add_srs_entry(srs, auth_name='EPSG', auth_srid=None, ref_sys_name=None,
database = database or DEFAULT_DB_ALIAS
connection = connections[database]
- if not hasattr(connection.ops, 'spatial_version'):
- raise Exception(
- 'The `add_srs_entry` utility only works with spatial backends.'
- )
+ if not hasattr(connection.ops, "spatial_version"):
+ raise Exception("The `add_srs_entry` utility only works with spatial backends.")
if not connection.features.supports_add_srs_entry:
- raise Exception('This utility does not support your database backend.')
+ raise Exception("This utility does not support your database backend.")
SpatialRefSys = connection.ops.spatial_ref_sys()
# If argument is not a `SpatialReference` instance, use it as parameter
@@ -49,24 +48,26 @@ def add_srs_entry(srs, auth_name='EPSG', auth_srid=None, ref_sys_name=None,
srs = SpatialReference(srs)
if srs.srid is None:
- raise Exception('Spatial reference requires an SRID to be '
- 'compatible with the spatial backend.')
+ raise Exception(
+ "Spatial reference requires an SRID to be "
+ "compatible with the spatial backend."
+ )
# Initializing the keyword arguments dictionary for both PostGIS
# and SpatiaLite.
kwargs = {
- 'srid': srs.srid,
- 'auth_name': auth_name,
- 'auth_srid': auth_srid or srs.srid,
- 'proj4text': srs.proj4,
+ "srid": srs.srid,
+ "auth_name": auth_name,
+ "auth_srid": auth_srid or srs.srid,
+ "proj4text": srs.proj4,
}
# Backend-specific fields for the SpatialRefSys model.
srs_field_names = {f.name for f in SpatialRefSys._meta.get_fields()}
- if 'srtext' in srs_field_names:
- kwargs['srtext'] = srs.wkt
- if 'ref_sys_name' in srs_field_names:
+ if "srtext" in srs_field_names:
+ kwargs["srtext"] = srs.wkt
+ if "ref_sys_name" in srs_field_names:
# SpatiaLite specific
- kwargs['ref_sys_name'] = ref_sys_name or srs.name
+ kwargs["ref_sys_name"] = ref_sys_name or srs.name
# Creating the spatial_ref_sys model.
try:
diff --git a/django/contrib/gis/views.py b/django/contrib/gis/views.py
index 5b29db9fb2..346fb5b0c0 100644
--- a/django/contrib/gis/views.py
+++ b/django/contrib/gis/views.py
@@ -7,14 +7,16 @@ def feed(request, url, feed_dict=None):
if not feed_dict:
raise Http404(_("No feeds are registered."))
- slug = url.partition('/')[0]
+ slug = url.partition("/")[0]
try:
f = feed_dict[slug]
except KeyError:
- raise Http404(_('Slug %r isn’t registered.') % slug)
+ raise Http404(_("Slug %r isn’t registered.") % slug)
instance = f()
- instance.feed_url = getattr(f, 'feed_url', None) or request.path
- instance.title_template = f.title_template or ('feeds/%s_title.html' % slug)
- instance.description_template = f.description_template or ('feeds/%s_description.html' % slug)
+ instance.feed_url = getattr(f, "feed_url", None) or request.path
+ instance.title_template = f.title_template or ("feeds/%s_title.html" % slug)
+ instance.description_template = f.description_template or (
+ "feeds/%s_description.html" % slug
+ )
return instance(request)