Fixed #32544 -- Confirmed support for GDAL 3.2 and GEOS 3.9.
This commit is contained in:
parent
c6859f1a68
commit
e3cfba0029
|
@ -20,12 +20,15 @@ if lib_path:
|
||||||
lib_names = None
|
lib_names = None
|
||||||
elif os.name == 'nt':
|
elif os.name == 'nt':
|
||||||
# Windows NT shared libraries
|
# Windows NT shared libraries
|
||||||
lib_names = ['gdal301', 'gdal300', 'gdal204', 'gdal203', 'gdal202', 'gdal201', 'gdal20']
|
lib_names = [
|
||||||
|
'gdal302', 'gdal301', 'gdal300',
|
||||||
|
'gdal204', 'gdal203', 'gdal202', 'gdal201', 'gdal20',
|
||||||
|
]
|
||||||
elif os.name == 'posix':
|
elif os.name == 'posix':
|
||||||
# *NIX library names.
|
# *NIX library names.
|
||||||
lib_names = [
|
lib_names = [
|
||||||
'gdal', 'GDAL',
|
'gdal', 'GDAL',
|
||||||
'gdal3.1.0', 'gdal3.0.0',
|
'gdal3.2.0', 'gdal3.1.0', 'gdal3.0.0',
|
||||||
'gdal2.4.0', 'gdal2.3.0', 'gdal2.2.0', 'gdal2.1.0', 'gdal2.0.0',
|
'gdal2.4.0', 'gdal2.3.0', 'gdal2.2.0', 'gdal2.1.0', 'gdal2.0.0',
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -5,16 +5,16 @@ Installing Geospatial libraries
|
||||||
GeoDjango uses and/or provides interfaces for the following open source
|
GeoDjango uses and/or provides interfaces for the following open source
|
||||||
geospatial libraries:
|
geospatial libraries:
|
||||||
|
|
||||||
======================== ==================================== ================================ ===================================
|
======================== ==================================== ================================ ======================================
|
||||||
Program Description Required Supported Versions
|
Program Description Required Supported Versions
|
||||||
======================== ==================================== ================================ ===================================
|
======================== ==================================== ================================ ======================================
|
||||||
:doc:`GEOS <../geos>` Geometry Engine Open Source Yes 3.8, 3.7, 3.6, 3.5
|
:doc:`GEOS <../geos>` Geometry Engine Open Source Yes 3.9, 3.8, 3.7, 3.6, 3.5
|
||||||
`PROJ`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 7.x. 6.x, 5.x, 4.x
|
`PROJ`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 7.x. 6.x, 5.x, 4.x
|
||||||
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.1, 3.0, 2.4, 2.3, 2.2, 2.1, 2.0
|
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.2, 3.1, 3.0, 2.4, 2.3, 2.2, 2.1, 2.0
|
||||||
:doc:`GeoIP <../geoip2>` IP-based geolocation library No 2
|
:doc:`GeoIP <../geoip2>` IP-based geolocation library No 2
|
||||||
`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 3.0, 2.5, 2.4
|
`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 3.0, 2.5, 2.4
|
||||||
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.3
|
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.3
|
||||||
======================== ==================================== ================================ ===================================
|
======================== ==================================== ================================ ======================================
|
||||||
|
|
||||||
Note that older or more recent versions of these libraries *may* also work
|
Note that older or more recent versions of these libraries *may* also work
|
||||||
totally fine with GeoDjango. Your mileage may vary.
|
totally fine with GeoDjango. Your mileage may vary.
|
||||||
|
@ -25,6 +25,7 @@ totally fine with GeoDjango. Your mileage may vary.
|
||||||
GEOS 3.6.0 2016-10-25
|
GEOS 3.6.0 2016-10-25
|
||||||
GEOS 3.7.0 2018-09-10
|
GEOS 3.7.0 2018-09-10
|
||||||
GEOS 3.8.0 2019-10-10
|
GEOS 3.8.0 2019-10-10
|
||||||
|
GEOS 3.9.0 2020-12-14
|
||||||
GDAL 2.0.0 2015-06
|
GDAL 2.0.0 2015-06
|
||||||
GDAL 2.1.0 2016-04
|
GDAL 2.1.0 2016-04
|
||||||
GDAL 2.2.0 2017-05
|
GDAL 2.2.0 2017-05
|
||||||
|
@ -32,6 +33,7 @@ totally fine with GeoDjango. Your mileage may vary.
|
||||||
GDAL 2.4.0 2018-12
|
GDAL 2.4.0 2018-12
|
||||||
GDAL 3.0.0 2019-05
|
GDAL 3.0.0 2019-05
|
||||||
GDAL 3.1.0 2020-05-07
|
GDAL 3.1.0 2020-05-07
|
||||||
|
GDAL 3.2.0 2020-11-02
|
||||||
PostGIS 2.4.0 2017-09-30
|
PostGIS 2.4.0 2017-09-30
|
||||||
PostGIS 2.5.0 2018-09-23
|
PostGIS 2.5.0 2018-09-23
|
||||||
PostGIS 3.0.0 2019-10-20
|
PostGIS 3.0.0 2019-10-20
|
||||||
|
|
|
@ -9,4 +9,4 @@ Django 3.2.1 fixes several bugs in 3.2.0.
|
||||||
Bugfixes
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
||||||
* ...
|
* Corrected detection of GDAL 3.2 on Windows (:ticket:`32544`).
|
||||||
|
|
|
@ -378,10 +378,10 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
|
||||||
b = OGRGeometry(self.geometries.topology_geoms[i].wkt_b)
|
b = OGRGeometry(self.geometries.topology_geoms[i].wkt_b)
|
||||||
d1 = OGRGeometry(self.geometries.diff_geoms[i].wkt)
|
d1 = OGRGeometry(self.geometries.diff_geoms[i].wkt)
|
||||||
d2 = a.difference(b)
|
d2 = a.difference(b)
|
||||||
self.assertEqual(d1, d2)
|
self.assertTrue(d1.geos.equals(d2.geos))
|
||||||
self.assertEqual(d1, a - b) # __sub__ is difference operator
|
self.assertTrue(d1.geos.equals((a - b).geos)) # __sub__ is difference operator
|
||||||
a -= b # testing __isub__
|
a -= b # testing __isub__
|
||||||
self.assertEqual(d1, a)
|
self.assertTrue(d1.geos.equals(a.geos))
|
||||||
|
|
||||||
def test_intersection(self):
|
def test_intersection(self):
|
||||||
"Testing intersects() and intersection()."
|
"Testing intersects() and intersection()."
|
||||||
|
@ -391,10 +391,10 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
|
||||||
i1 = OGRGeometry(self.geometries.intersect_geoms[i].wkt)
|
i1 = OGRGeometry(self.geometries.intersect_geoms[i].wkt)
|
||||||
self.assertTrue(a.intersects(b))
|
self.assertTrue(a.intersects(b))
|
||||||
i2 = a.intersection(b)
|
i2 = a.intersection(b)
|
||||||
self.assertEqual(i1, i2)
|
self.assertTrue(i1.geos.equals(i2.geos))
|
||||||
self.assertEqual(i1, a & b) # __and__ is intersection operator
|
self.assertTrue(i1.geos.equals((a & b).geos)) # __and__ is intersection operator
|
||||||
a &= b # testing __iand__
|
a &= b # testing __iand__
|
||||||
self.assertEqual(i1, a)
|
self.assertTrue(i1.geos.equals(a.geos))
|
||||||
|
|
||||||
def test_symdifference(self):
|
def test_symdifference(self):
|
||||||
"Testing sym_difference()."
|
"Testing sym_difference()."
|
||||||
|
@ -403,10 +403,10 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
|
||||||
b = OGRGeometry(self.geometries.topology_geoms[i].wkt_b)
|
b = OGRGeometry(self.geometries.topology_geoms[i].wkt_b)
|
||||||
d1 = OGRGeometry(self.geometries.sdiff_geoms[i].wkt)
|
d1 = OGRGeometry(self.geometries.sdiff_geoms[i].wkt)
|
||||||
d2 = a.sym_difference(b)
|
d2 = a.sym_difference(b)
|
||||||
self.assertEqual(d1, d2)
|
self.assertTrue(d1.geos.equals(d2.geos))
|
||||||
self.assertEqual(d1, a ^ b) # __xor__ is symmetric difference operator
|
self.assertTrue(d1.geos.equals((a ^ b).geos)) # __xor__ is symmetric difference operator
|
||||||
a ^= b # testing __ixor__
|
a ^= b # testing __ixor__
|
||||||
self.assertEqual(d1, a)
|
self.assertTrue(d1.geos.equals(a.geos))
|
||||||
|
|
||||||
def test_union(self):
|
def test_union(self):
|
||||||
"Testing union()."
|
"Testing union()."
|
||||||
|
@ -415,10 +415,10 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
|
||||||
b = OGRGeometry(self.geometries.topology_geoms[i].wkt_b)
|
b = OGRGeometry(self.geometries.topology_geoms[i].wkt_b)
|
||||||
u1 = OGRGeometry(self.geometries.union_geoms[i].wkt)
|
u1 = OGRGeometry(self.geometries.union_geoms[i].wkt)
|
||||||
u2 = a.union(b)
|
u2 = a.union(b)
|
||||||
self.assertEqual(u1, u2)
|
self.assertTrue(u1.geos.equals(u2.geos))
|
||||||
self.assertEqual(u1, a | b) # __or__ is union operator
|
self.assertTrue(u1.geos.equals((a | b).geos)) # __or__ is union operator
|
||||||
a |= b # testing __ior__
|
a |= b # testing __ior__
|
||||||
self.assertEqual(u1, a)
|
self.assertTrue(u1.geos.equals(a.geos))
|
||||||
|
|
||||||
def test_add(self):
|
def test_add(self):
|
||||||
"Testing GeometryCollection.add()."
|
"Testing GeometryCollection.add()."
|
||||||
|
|
|
@ -89,6 +89,16 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
# MariaDB doesn't limit the number of decimals in bbox.
|
# MariaDB doesn't limit the number of decimals in bbox.
|
||||||
if connection.ops.mariadb:
|
if connection.ops.mariadb:
|
||||||
chicago_json['bbox'] = [-87.650175, 41.850385, -87.650175, 41.850385]
|
chicago_json['bbox'] = [-87.650175, 41.850385, -87.650175, 41.850385]
|
||||||
|
try:
|
||||||
|
self.assertJSONEqual(
|
||||||
|
City.objects.annotate(
|
||||||
|
geojson=functions.AsGeoJSON('point', bbox=True, crs=True, precision=5)
|
||||||
|
).get(name='Chicago').geojson,
|
||||||
|
chicago_json,
|
||||||
|
)
|
||||||
|
except AssertionError:
|
||||||
|
# Give a second chance with different coords rounding.
|
||||||
|
chicago_json['coordinates'][1] = 41.85038
|
||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
City.objects.annotate(
|
City.objects.annotate(
|
||||||
geojson=functions.AsGeoJSON('point', bbox=True, crs=True, precision=5)
|
geojson=functions.AsGeoJSON('point', bbox=True, crs=True, precision=5)
|
||||||
|
@ -295,11 +305,10 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
geom = Point(5, 23, srid=4326)
|
geom = Point(5, 23, srid=4326)
|
||||||
qs = Country.objects.annotate(inter=functions.Intersection('mpoly', geom))
|
qs = Country.objects.annotate(inter=functions.Intersection('mpoly', geom))
|
||||||
for c in qs:
|
for c in qs:
|
||||||
expected = (
|
if connection.features.empty_intersection_returns_none:
|
||||||
None if connection.features.empty_intersection_returns_none
|
self.assertIsNone(c.inter)
|
||||||
else c.mpoly.intersection(geom)
|
else:
|
||||||
)
|
self.assertIs(c.inter.empty, True)
|
||||||
self.assertEqual(c.inter, expected)
|
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_IsValid_function")
|
@skipUnlessDBFeature("has_IsValid_function")
|
||||||
def test_isvalid(self):
|
def test_isvalid(self):
|
||||||
|
@ -352,7 +361,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
State.objects.create(name='invalid', poly=invalid_geom)
|
State.objects.create(name='invalid', poly=invalid_geom)
|
||||||
invalid = State.objects.filter(name='invalid').annotate(repaired=functions.MakeValid('poly')).first()
|
invalid = State.objects.filter(name='invalid').annotate(repaired=functions.MakeValid('poly')).first()
|
||||||
self.assertIs(invalid.repaired.valid, True)
|
self.assertIs(invalid.repaired.valid, True)
|
||||||
self.assertEqual(invalid.repaired, fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', srid=invalid.poly.srid))
|
self.assertTrue(invalid.repaired.equals(fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', srid=invalid.poly.srid)))
|
||||||
|
|
||||||
@skipUnlessDBFeature('has_MakeValid_function')
|
@skipUnlessDBFeature('has_MakeValid_function')
|
||||||
def test_make_valid_multipolygon(self):
|
def test_make_valid_multipolygon(self):
|
||||||
|
@ -365,11 +374,11 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
repaired=functions.MakeValid('poly'),
|
repaired=functions.MakeValid('poly'),
|
||||||
).get()
|
).get()
|
||||||
self.assertIs(invalid.repaired.valid, True)
|
self.assertIs(invalid.repaired.valid, True)
|
||||||
self.assertEqual(invalid.repaired, fromstr(
|
self.assertTrue(invalid.repaired.equals(fromstr(
|
||||||
'MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)), '
|
'MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)), '
|
||||||
'((10 0, 10 1, 11 1, 11 0, 10 0)))',
|
'((10 0, 10 1, 11 1, 11 0, 10 0)))',
|
||||||
srid=invalid.poly.srid,
|
srid=invalid.poly.srid,
|
||||||
))
|
)))
|
||||||
self.assertEqual(len(invalid.repaired), 2)
|
self.assertEqual(len(invalid.repaired), 2)
|
||||||
|
|
||||||
@skipUnlessDBFeature('has_MakeValid_function')
|
@skipUnlessDBFeature('has_MakeValid_function')
|
||||||
|
@ -528,14 +537,14 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
def test_transform(self):
|
def test_transform(self):
|
||||||
# Pre-transformed points for Houston and Pueblo.
|
# Pre-transformed points for Houston and Pueblo.
|
||||||
ptown = fromstr('POINT(992363.390841912 481455.395105533)', srid=2774)
|
ptown = fromstr('POINT(992363.390841912 481455.395105533)', srid=2774)
|
||||||
prec = 3 # Precision is low due to version variations in PROJ and GDAL.
|
|
||||||
|
|
||||||
# Asserting the result of the transform operation with the values in
|
# Asserting the result of the transform operation with the values in
|
||||||
# the pre-transformed points.
|
# the pre-transformed points.
|
||||||
h = City.objects.annotate(pt=functions.Transform('point', ptown.srid)).get(name='Pueblo')
|
h = City.objects.annotate(pt=functions.Transform('point', ptown.srid)).get(name='Pueblo')
|
||||||
self.assertEqual(2774, h.pt.srid)
|
self.assertEqual(2774, h.pt.srid)
|
||||||
self.assertAlmostEqual(ptown.x, h.pt.x, prec)
|
# Precision is low due to version variations in PROJ and GDAL.
|
||||||
self.assertAlmostEqual(ptown.y, h.pt.y, prec)
|
self.assertLess(ptown.x - h.pt.x, 1)
|
||||||
|
self.assertLess(ptown.y - h.pt.y, 1)
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_Translate_function")
|
@skipUnlessDBFeature("has_Translate_function")
|
||||||
def test_translate(self):
|
def test_translate(self):
|
||||||
|
@ -569,11 +578,10 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
return
|
return
|
||||||
for c in qs:
|
for c in qs:
|
||||||
self.assertTrue(c.mpoly.difference(geom).equals(c.difference))
|
self.assertTrue(c.mpoly.difference(geom).equals(c.difference))
|
||||||
expected_intersection = (
|
if connection.features.empty_intersection_returns_none:
|
||||||
None if connection.features.empty_intersection_returns_none
|
self.assertIsNone(c.intersection)
|
||||||
else c.mpoly.intersection(geom)
|
else:
|
||||||
)
|
self.assertIs(c.intersection.empty, True)
|
||||||
self.assertEqual(c.intersection, expected_intersection)
|
|
||||||
self.assertTrue(c.mpoly.sym_difference(geom).equals(c.sym_difference))
|
self.assertTrue(c.mpoly.sym_difference(geom).equals(c.sym_difference))
|
||||||
self.assertTrue(c.mpoly.union(geom).equals(c.union))
|
self.assertTrue(c.mpoly.union(geom).equals(c.union))
|
||||||
|
|
||||||
|
|
|
@ -638,10 +638,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
||||||
i1 = fromstr(self.geometries.intersect_geoms[i].wkt)
|
i1 = fromstr(self.geometries.intersect_geoms[i].wkt)
|
||||||
self.assertIs(a.intersects(b), True)
|
self.assertIs(a.intersects(b), True)
|
||||||
i2 = a.intersection(b)
|
i2 = a.intersection(b)
|
||||||
self.assertEqual(i1, i2)
|
self.assertTrue(i1.equals(i2))
|
||||||
self.assertEqual(i1, a & b) # __and__ is intersection operator
|
self.assertTrue(i1.equals(a & b)) # __and__ is intersection operator
|
||||||
a &= b # testing __iand__
|
a &= b # testing __iand__
|
||||||
self.assertEqual(i1, a)
|
self.assertTrue(i1.equals(a))
|
||||||
|
|
||||||
def test_union(self):
|
def test_union(self):
|
||||||
"Testing union()."
|
"Testing union()."
|
||||||
|
@ -650,10 +650,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
||||||
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
|
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
|
||||||
u1 = fromstr(self.geometries.union_geoms[i].wkt)
|
u1 = fromstr(self.geometries.union_geoms[i].wkt)
|
||||||
u2 = a.union(b)
|
u2 = a.union(b)
|
||||||
self.assertEqual(u1, u2)
|
self.assertTrue(u1.equals(u2))
|
||||||
self.assertEqual(u1, a | b) # __or__ is union operator
|
self.assertTrue(u1.equals(a | b)) # __or__ is union operator
|
||||||
a |= b # testing __ior__
|
a |= b # testing __ior__
|
||||||
self.assertEqual(u1, a)
|
self.assertTrue(u1.equals(a))
|
||||||
|
|
||||||
def test_unary_union(self):
|
def test_unary_union(self):
|
||||||
"Testing unary_union."
|
"Testing unary_union."
|
||||||
|
@ -671,10 +671,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
||||||
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
|
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
|
||||||
d1 = fromstr(self.geometries.diff_geoms[i].wkt)
|
d1 = fromstr(self.geometries.diff_geoms[i].wkt)
|
||||||
d2 = a.difference(b)
|
d2 = a.difference(b)
|
||||||
self.assertEqual(d1, d2)
|
self.assertTrue(d1.equals(d2))
|
||||||
self.assertEqual(d1, a - b) # __sub__ is difference operator
|
self.assertTrue(d1.equals(a - b)) # __sub__ is difference operator
|
||||||
a -= b # testing __isub__
|
a -= b # testing __isub__
|
||||||
self.assertEqual(d1, a)
|
self.assertTrue(d1.equals(a))
|
||||||
|
|
||||||
def test_symdifference(self):
|
def test_symdifference(self):
|
||||||
"Testing sym_difference()."
|
"Testing sym_difference()."
|
||||||
|
@ -683,10 +683,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
||||||
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
|
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
|
||||||
d1 = fromstr(self.geometries.sdiff_geoms[i].wkt)
|
d1 = fromstr(self.geometries.sdiff_geoms[i].wkt)
|
||||||
d2 = a.sym_difference(b)
|
d2 = a.sym_difference(b)
|
||||||
self.assertEqual(d1, d2)
|
self.assertTrue(d1.equals(d2))
|
||||||
self.assertEqual(d1, a ^ b) # __xor__ is symmetric difference operator
|
self.assertTrue(d1.equals(a ^ b)) # __xor__ is symmetric difference operator
|
||||||
a ^= b # testing __ixor__
|
a ^= b # testing __ixor__
|
||||||
self.assertEqual(d1, a)
|
self.assertTrue(d1.equals(a))
|
||||||
|
|
||||||
def test_buffer(self):
|
def test_buffer(self):
|
||||||
bg = self.geometries.buffer_geoms[0]
|
bg = self.geometries.buffer_geoms[0]
|
||||||
|
|
Loading…
Reference in New Issue