1
0
mirror of https://github.com/django/django.git synced 2025-06-05 11:39:13 +00:00

Merge branch 'django:main' into skushagra-patch-1-issue-35119

This commit is contained in:
Kushagra S 2024-01-25 17:39:25 +05:30 committed by GitHub
commit 70a9abafc9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 216 additions and 19 deletions

View File

@ -893,11 +893,6 @@ a.deletelink:focus, a.deletelink:hover {
} }
} }
#footer {
clear: both;
padding: 10px;
}
/* COLUMN TYPES */ /* COLUMN TYPES */
.colMS { .colMS {

View File

@ -451,14 +451,10 @@ input[type="submit"], button {
@media (max-width: 767px) { @media (max-width: 767px) {
/* Layout */ /* Layout */
#header, #content, #footer { #header, #content {
padding: 15px; padding: 15px;
} }
#footer:empty {
padding: 0;
}
div.breadcrumbs { div.breadcrumbs {
padding: 10px 15px; padding: 10px 15px;
} }

View File

@ -108,9 +108,9 @@
<br class="clear"> <br class="clear">
</div> </div>
<!-- END Content --> <!-- END Content -->
{% block footer %}<div id="footer"></div>{% endblock %}
</main> </main>
</div> </div>
<footer id="footer">{% block footer %}{% endblock %}</footer>
</div> </div>
<!-- END Container --> <!-- END Container -->

View File

@ -287,6 +287,22 @@ class OGRGeometry(GDALBase):
else: else:
raise ValueError(f"Input to 'set_3d' must be a boolean, got '{value!r}'.") raise ValueError(f"Input to 'set_3d' must be a boolean, got '{value!r}'.")
@property
def is_measured(self):
"""Return True if the geometry has M coordinates."""
return capi.is_measured(self.ptr)
def set_measured(self, value):
"""Set if this geometry has M coordinates."""
if value is True:
capi.set_measured(self.ptr, 1)
elif value is False:
capi.set_measured(self.ptr, 0)
else:
raise ValueError(
f"Input to 'set_measured' must be a boolean, got '{value!r}'."
)
# #### SpatialReference-related Properties #### # #### SpatialReference-related Properties ####
# The SRS property # The SRS property
@ -386,14 +402,22 @@ class OGRGeometry(GDALBase):
sz = self.wkb_size sz = self.wkb_size
# Creating the unsigned character buffer, and passing it in by reference. # Creating the unsigned character buffer, and passing it in by reference.
buf = (c_ubyte * sz)() buf = (c_ubyte * sz)()
capi.to_wkb(self.ptr, byteorder, byref(buf)) # For backward compatibility, export old-style 99-402 extended
# dimension types when geometry does not have an M dimension.
# https://gdal.org/api/vector_c_api.html#_CPPv417OGR_G_ExportToWkb12OGRGeometryH15OGRwkbByteOrderPh
to_wkb = capi.to_iso_wkb if self.is_measured else capi.to_wkb
to_wkb(self.ptr, byteorder, byref(buf))
# Returning a buffer of the string at the pointer. # Returning a buffer of the string at the pointer.
return memoryview(string_at(buf, sz)) return memoryview(string_at(buf, sz))
@property @property
def wkt(self): def wkt(self):
"Return the WKT representation of the Geometry." "Return the WKT representation of the Geometry."
return capi.to_wkt(self.ptr, byref(c_char_p())) # For backward compatibility, export old-style 99-402 extended
# dimension types when geometry does not have an M dimension.
# https://gdal.org/api/vector_c_api.html#_CPPv417OGR_G_ExportToWkt12OGRGeometryHPPc
to_wkt = capi.to_iso_wkt if self.is_measured else capi.to_wkt
return to_wkt(self.ptr, byref(c_char_p()))
@property @property
def ewkt(self): def ewkt(self):
@ -568,11 +592,21 @@ class Point(OGRGeometry):
if self.is_3d: if self.is_3d:
return capi.getz(self.ptr, 0) return capi.getz(self.ptr, 0)
@property
def m(self):
"""Return the M coordinate for this Point."""
if self.is_measured:
return capi.getm(self.ptr, 0)
@property @property
def tuple(self): def tuple(self):
"Return the tuple of this point." "Return the tuple of this point."
if self.is_3d and self.is_measured:
return self.x, self.y, self.z, self.m
if self.is_3d: if self.is_3d:
return (self.x, self.y, self.z) return self.x, self.y, self.z
if self.is_measured:
return self.x, self.y, self.m
return self.x, self.y return self.x, self.y
coords = tuple coords = tuple
@ -753,7 +787,9 @@ GEO_CLASSES = {
6: MultiPolygon, 6: MultiPolygon,
7: GeometryCollection, 7: GeometryCollection,
101: LinearRing, 101: LinearRing,
1 + OGRGeomType.wkb25bit: Point, 2001: Point, # POINT M
3001: Point, # POINT ZM
1 + OGRGeomType.wkb25bit: Point, # POINT Z
2 + OGRGeomType.wkb25bit: LineString, 2 + OGRGeomType.wkb25bit: LineString,
3 + OGRGeomType.wkb25bit: Polygon, 3 + OGRGeomType.wkb25bit: Polygon,
4 + OGRGeomType.wkb25bit: MultiPoint, 4 + OGRGeomType.wkb25bit: MultiPoint,

View File

@ -51,6 +51,7 @@ to_kml = string_output(
getx = pnt_func(lgdal.OGR_G_GetX) getx = pnt_func(lgdal.OGR_G_GetX)
gety = pnt_func(lgdal.OGR_G_GetY) gety = pnt_func(lgdal.OGR_G_GetY)
getz = pnt_func(lgdal.OGR_G_GetZ) getz = pnt_func(lgdal.OGR_G_GetZ)
getm = pnt_func(lgdal.OGR_G_GetM)
# Geometry creation routines. # Geometry creation routines.
if GDAL_VERSION >= (3, 3): if GDAL_VERSION >= (3, 3):
@ -82,6 +83,8 @@ geom_sym_diff = geom_output(lgdal.OGR_G_SymmetricDifference, [c_void_p, c_void_p
geom_union = geom_output(lgdal.OGR_G_Union, [c_void_p, c_void_p]) geom_union = geom_output(lgdal.OGR_G_Union, [c_void_p, c_void_p])
is_3d = bool_output(lgdal.OGR_G_Is3D, [c_void_p]) is_3d = bool_output(lgdal.OGR_G_Is3D, [c_void_p])
set_3d = void_output(lgdal.OGR_G_Set3D, [c_void_p, c_int], errcheck=False) set_3d = void_output(lgdal.OGR_G_Set3D, [c_void_p, c_int], errcheck=False)
is_measured = bool_output(lgdal.OGR_G_IsMeasured, [c_void_p])
set_measured = void_output(lgdal.OGR_G_SetMeasured, [c_void_p, c_int], errcheck=False)
# Geometry modification routines. # Geometry modification routines.
add_geom = void_output(lgdal.OGR_G_AddGeometry, [c_void_p, c_void_p]) add_geom = void_output(lgdal.OGR_G_AddGeometry, [c_void_p, c_void_p])
@ -94,9 +97,13 @@ destroy_geom = void_output(lgdal.OGR_G_DestroyGeometry, [c_void_p], errcheck=Fal
to_wkb = void_output( to_wkb = void_output(
lgdal.OGR_G_ExportToWkb, None, errcheck=True lgdal.OGR_G_ExportToWkb, None, errcheck=True
) # special handling for WKB. ) # special handling for WKB.
to_iso_wkb = void_output(lgdal.OGR_G_ExportToIsoWkb, None, errcheck=True)
to_wkt = string_output( to_wkt = string_output(
lgdal.OGR_G_ExportToWkt, [c_void_p, POINTER(c_char_p)], decoding="ascii" lgdal.OGR_G_ExportToWkt, [c_void_p, POINTER(c_char_p)], decoding="ascii"
) )
to_iso_wkt = string_output(
lgdal.OGR_G_ExportToIsoWkt, [c_void_p, POINTER(c_char_p)], decoding="ascii"
)
to_gml = string_output( to_gml = string_output(
lgdal.OGR_G_ExportToGML, [c_void_p], str_result=True, decoding="ascii" lgdal.OGR_G_ExportToGML, [c_void_p], str_result=True, decoding="ascii"
) )
@ -115,7 +122,7 @@ get_geom_srs = srs_output(lgdal.OGR_G_GetSpatialReference, [c_void_p])
get_area = double_output(lgdal.OGR_G_GetArea, [c_void_p]) 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_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_dims = int_output(lgdal.OGR_G_GetDimension, [c_void_p])
get_coord_dim = int_output(lgdal.OGR_G_GetCoordinateDimension, [c_void_p]) get_coord_dim = int_output(lgdal.OGR_G_CoordinateDimension, [c_void_p])
set_coord_dim = void_output( set_coord_dim = void_output(
lgdal.OGR_G_SetCoordinateDimension, [c_void_p, c_int], errcheck=False lgdal.OGR_G_SetCoordinateDimension, [c_void_p, c_int], errcheck=False
) )

View File

@ -488,6 +488,10 @@ class LayerMapping:
if necessary (for example if the model field is MultiPolygonField while if necessary (for example if the model field is MultiPolygonField while
the mapped shapefile only contains Polygons). the mapped shapefile only contains Polygons).
""" """
# Measured geometries are not yet supported by GeoDjango models.
if geom.is_measured:
geom.set_measured(False)
# Downgrade a 3D geom to a 2D one, if necessary. # Downgrade a 3D geom to a 2D one, if necessary.
if self.coord_dim == 2 and geom.is_3d: if self.coord_dim == 2 and geom.is_3d:
geom.set_3d(False) geom.set_3d(False)

View File

@ -581,6 +581,27 @@ coordinate transformation:
>>> p.wkt >>> p.wkt
"POINT (1 2)" "POINT (1 2)"
.. attribute:: is_measured
.. versionadded:: 5.1
A boolean indicating if this geometry has M coordinates.
.. method:: set_measured(value)
.. versionadded:: 5.1
A method to add or remove the M coordinate dimension.
.. code-block:: pycon
>>> p = OGRGeometry("POINT (1 2)")
>>> p.is_measured
False
>>> p.set_measured(True)
>>> p.wkt
"POINT M (1 2 0)"
.. attribute:: geom_count .. attribute:: geom_count
Returns the number of elements in this geometry: Returns the number of elements in this geometry:
@ -864,6 +885,18 @@ coordinate transformation:
>>> OGRGeometry("POINT (1 2 3)").z >>> OGRGeometry("POINT (1 2 3)").z
3.0 3.0
.. attribute:: m
.. versionadded:: 5.1
Returns the M coordinate of this point, or ``None`` if the Point does not
have an M coordinate:
.. code-block:: pycon
>>> OGRGeometry("POINT ZM (1 2 3 4)").m
4.0
.. class:: LineString .. class:: LineString
.. attribute:: x .. attribute:: x

View File

@ -199,6 +199,39 @@ This logging does not include framework-level initialization (e.g.
``SET TIMEZONE``). Turn on query logging in your database if you wish to view ``SET TIMEZONE``). Turn on query logging in your database if you wish to view
all database queries. all database queries.
.. _django-utils-autoreloader-logger:
``django.utils.autoreload``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Log messages related to automatic code reloading during the execution of the
Django development server. This logger generates an ``INFO`` message upon
detecting a modification in a source code file and may produce ``WARNING``
messages during filesystem inspection and event subscription processes.
.. _django-contrib-gis-logger:
``django.contrib.gis``
~~~~~~~~~~~~~~~~~~~~~~
Log messages related to :doc:`contrib/gis/index` at various points: during the
loading of external GeoSpatial libraries (GEOS, GDAL, etc.) and when reporting
errors. Each ``ERROR`` log record includes the caught exception and relevant
contextual data.
.. _django-dispatch-logger:
``django.dispatch``
~~~~~~~~~~~~~~~~~~~
This logger is used in :doc:`signals`, specifically within the
:mod:`~django.dispatch.Signal` class, to report issues when dispatching a
signal to a connected receiver. The ``ERROR`` log record includes the caught
exception as ``exc_info`` and adds the following extra context:
* ``receiver``: The name of the receiver.
* ``err``: The exception that occurred when calling the receiver.
.. _django-security-logger: .. _django-security-logger:
``django.security.*`` ``django.security.*``

View File

@ -78,6 +78,11 @@ Minor features
* The new :meth:`.OGRGeometry.set_3d` method allows addition and removal of the * The new :meth:`.OGRGeometry.set_3d` method allows addition and removal of the
``Z`` coordinate dimension. ``Z`` coordinate dimension.
* :class:`~django.contrib.gis.gdal.OGRGeometry` and
:class:`~django.contrib.gis.gdal.Point` now support measured geometries
via the new :attr:`.OGRGeometry.is_measured` and :attr:`.Point.m` properties,
and the :meth:`.OGRGeometry.set_measured` method.
:mod:`django.contrib.messages` :mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -348,6 +353,10 @@ Miscellaneous
* In order to improve accessibility, the admin's changelist filter is now * In order to improve accessibility, the admin's changelist filter is now
rendered in a ``<nav>`` tag instead of a ``<div>``. rendered in a ``<nav>`` tag instead of a ``<div>``.
* In order to improve accessibility, the admin's footer is now rendered in
a ``<footer>`` tag instead of a ``<div>``, and also moved below the
``<div id="main">`` element.
* :meth:`.SimpleTestCase.assertURLEqual` and * :meth:`.SimpleTestCase.assertURLEqual` and
:meth:`~django.test.SimpleTestCase.assertInHTML` now add ``": "`` to the :meth:`~django.test.SimpleTestCase.assertInHTML` now add ``": "`` to the
``msg_prefix``. This is consistent with the behavior of other assertions. ``msg_prefix``. This is consistent with the behavior of other assertions.

View File

@ -1605,6 +1605,13 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
'<main id="content-start" class="content" tabindex="-1">', '<main id="content-start" class="content" tabindex="-1">',
) )
def test_footer(self):
response = self.client.get(reverse("admin:index"))
self.assertContains(response, '<footer id="footer">')
self.client.logout()
response = self.client.get(reverse("admin:login"))
self.assertContains(response, '<footer id="footer">')
def test_aria_describedby_for_add_and_change_links(self): def test_aria_describedby_for_add_and_change_links(self):
response = self.client.get(reverse("admin:index")) response = self.client.get(reverse("admin:index"))
tests = [ tests = [

View File

@ -672,7 +672,7 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
("PolyhedralSurface Z", 1015, False), ("PolyhedralSurface Z", 1015, False),
("TIN Z", 1016, False), ("TIN Z", 1016, False),
("Triangle Z", 1017, False), ("Triangle Z", 1017, False),
("Point M", 2001, False), ("Point M", 2001, True),
("LineString M", 2002, False), ("LineString M", 2002, False),
("Polygon M", 2003, False), ("Polygon M", 2003, False),
("MultiPoint M", 2004, False), ("MultiPoint M", 2004, False),
@ -687,7 +687,7 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
("PolyhedralSurface M", 2015, False), ("PolyhedralSurface M", 2015, False),
("TIN M", 2016, False), ("TIN M", 2016, False),
("Triangle M", 2017, False), ("Triangle M", 2017, False),
("Point ZM", 3001, False), ("Point ZM", 3001, True),
("LineString ZM", 3002, False), ("LineString ZM", 3002, False),
("Polygon ZM", 3003, False), ("Polygon ZM", 3003, False),
("MultiPoint ZM", 3004, False), ("MultiPoint ZM", 3004, False),
@ -812,6 +812,71 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
self.assertEqual(g.wkt, geom) self.assertEqual(g.wkt, geom)
self.assertEqual(g.wkb.hex(), wkb) self.assertEqual(g.wkb.hex(), wkb)
def test_measure_is_measure_and_set_measure(self):
geom = OGRGeometry("POINT (1 2 3)")
self.assertIs(geom.is_measured, False)
geom.set_measured(True)
self.assertIs(geom.is_measured, True)
self.assertEqual(geom.wkt, "POINT ZM (1 2 3 0)")
geom.set_measured(False)
self.assertIs(geom.is_measured, False)
self.assertEqual(geom.wkt, "POINT (1 2 3)")
msg = "Input to 'set_measured' must be a boolean, got 'None'"
with self.assertRaisesMessage(ValueError, msg):
geom.set_measured(None)
def test_point_m_coordinate(self):
geom = OGRGeometry("POINT ZM (1 2 3 4)")
self.assertEqual(geom.m, 4)
geom = OGRGeometry("POINT (1 2 3 4)")
self.assertEqual(geom.m, 4)
geom = OGRGeometry("POINT M (1 2 3)")
self.assertEqual(geom.m, 3)
geom = OGRGeometry("POINT Z (1 2 3)")
self.assertEqual(geom.m, None)
def test_point_m_tuple(self):
geom = OGRGeometry("POINT ZM (1 2 3 4)")
self.assertEqual(geom.tuple, (geom.x, geom.y, geom.z, geom.m))
geom = OGRGeometry("POINT M (1 2 3)")
self.assertEqual(geom.tuple, (geom.x, geom.y, geom.m))
geom = OGRGeometry("POINT Z (1 2 3)")
self.assertEqual(geom.tuple, (geom.x, geom.y, geom.z))
geom = OGRGeometry("POINT (1 2 3)")
self.assertEqual(geom.tuple, (geom.x, geom.y, geom.z))
def test_point_m_wkt_wkb(self):
wkt = "POINT ZM (1 2 3 4)"
geom = OGRGeometry(wkt)
self.assertEqual(geom.wkt, wkt)
self.assertEqual(
geom.wkb.hex(),
"01b90b0000000000000000f03f00000000000000"
"4000000000000008400000000000001040",
)
wkt = "POINT M (1 2 3)"
geom = OGRGeometry(wkt)
self.assertEqual(geom.wkt, wkt)
self.assertEqual(
geom.wkb.hex(),
"01d1070000000000000000f03f00000000000000400000000000000840",
)
def test_point_m_dimension_types(self):
geom = OGRGeometry("POINT ZM (1 2 3 4)")
self.assertEqual(geom.geom_type.name, "PointZM")
self.assertEqual(geom.geom_type.num, 3001)
geom = OGRGeometry("POINT M (1 2 3)")
self.assertEqual(geom.geom_type.name, "PointM")
self.assertEqual(geom.geom_type.num, 2001)
def test_point_m_dimension_geos(self):
"""GEOSGeometry does not yet support the M dimension."""
geom = OGRGeometry("POINT ZM (1 2 3 4)")
self.assertEqual(geom.geos.wkt, "POINT Z (1 2 3)")
geom = OGRGeometry("POINT M (1 2 3)")
self.assertEqual(geom.geos.wkt, "POINT (1 2)")
class DeprecationTests(SimpleTestCase): class DeprecationTests(SimpleTestCase):
def test_coord_setter_deprecation(self): def test_coord_setter_deprecation(self):

View File

@ -1,5 +1,5 @@
from django.core import mail from django.core import mail
from django.core.management import call_command from django.core.management import CommandError, call_command
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
@ -46,6 +46,18 @@ class SendTestEmailManagementCommand(SimpleTestCase):
], ],
) )
def test_missing_receivers(self):
"""
The command should complain if no receivers are given (and --admins or
--managers are not set).
"""
msg = (
"You must specify some email recipients, or pass the --managers or "
"--admin options."
)
with self.assertRaisesMessage(CommandError, msg):
call_command("sendtestemail")
def test_manager_receivers(self): def test_manager_receivers(self):
""" """
The mail should be sent to the email addresses specified in The mail should be sent to the email addresses specified in