diff --git a/tests/gis_tests/data/geometries.json b/tests/gis_tests/data/geometries.json
index eb6c64b6d9..6856ac793a 100644
--- a/tests/gis_tests/data/geometries.json
+++ b/tests/gis_tests/data/geometries.json
@@ -11,12 +11,12 @@
{"wkt": "MULTIPOLYGON (((180 60, 240 160, 300 60, 180 60)), ((80 80, 180 60, 160 140, 240 160, 360 140, 300 60, 420 100, 320 280, 120 260, 80 80)))", "valid": true, "num_geom": 2, "n_p": 14}
],
"errors": [
- {"wkt": "GEOMETR##!@#%#............a32515", "bad": true, "hex": false},
- {"wkt": "Foo.Bar", "bad": true, "hex": false},
- {"wkt": "POINT (5, 23)", "bad": true, "hex": false},
- {"wkt": "AAABBBDDDAAD##@#1113511111-098111111111111111533333333333333", "bad": true, "hex": true},
- {"wkt": "FFFFFFFFFFFFFFFFF1355555555555555555565111", "bad": true, "hex": true},
- {"wkt": "", "bad": true, "hex": false}
+ {"wkt": "GEOMETR##!@#%#............a32515", "bad": true, "hex": false, "msg": "String input unrecognized as WKT EWKT, and HEXEWKB."},
+ {"wkt": "Foo.Bar", "bad": true, "hex": false, "msg": "String input unrecognized as WKT EWKT, and HEXEWKB."},
+ {"wkt": "POINT (5, 23)", "bad": true, "hex": false, "msg": "Error encountered checking Geometry returned from GEOS C function \"GEOSWKTReader_read_r\"."},
+ {"wkt": "AAABBBDDDAAD##@#1113511111-098111111111111111533333333333333", "bad": true, "hex": true, "msg": "String input unrecognized as WKT EWKT, and HEXEWKB."},
+ {"wkt": "FFFFFFFFFFFFFFFFF1355555555555555555565111", "bad": true, "hex": true, "msg": "Error encountered checking Geometry returned from GEOS C function \"GEOSWKBReader_readHEX_r\"."},
+ {"wkt": "", "bad": true, "hex": false, "msg": "String input unrecognized as WKT EWKT, and HEXEWKB."}
],
"wkt_out": [
{"wkt": "POINT (110 130)", "ewkt": "POINT (110 130)", "kml": "110.0,130.0,0", "gml": "110,130"},
diff --git a/tests/gis_tests/geos_tests/test_geos.py b/tests/gis_tests/geos_tests/test_geos.py
index 724555560b..88d0344972 100644
--- a/tests/gis_tests/geos_tests/test_geos.py
+++ b/tests/gis_tests/geos_tests/test_geos.py
@@ -28,17 +28,34 @@ from django.contrib.gis.shortcuts import numpy
from django.template import Context
from django.template.engine import Engine
from django.test import SimpleTestCase
+from django.utils.version import PY312
from ..test_data import TestDataMixin
class GEOSTest(SimpleTestCase, TestDataMixin):
+
+ error_checking_geom = (
+ 'Error encountered checking Geometry returned from GEOS C function "{}".'
+ )
+
+ def assertArgumentTypeError(self, i, bad_type):
+ if PY312:
+ msg = (
+ f"argument {i}: TypeError: '{bad_type}' object cannot be interpreted "
+ "as an integer"
+ )
+ else:
+ msg = f"argument {i}: TypeError: wrong type"
+ return self.assertRaisesMessage(ctypes.ArgumentError, msg)
+
def test_wkt(self):
"Testing WKT output."
for g in self.geometries.wkt_out:
- geom = fromstr(g.wkt)
- if geom.hasz:
- self.assertEqual(g.ewkt, geom.wkt)
+ with self.subTest(g=g):
+ geom = fromstr(g.wkt)
+ if geom.hasz:
+ self.assertEqual(g.ewkt, geom.wkt)
def test_wkt_invalid(self):
msg = "String input unrecognized as WKT EWKT, and HEXEWKB."
@@ -50,8 +67,9 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
def test_hex(self):
"Testing HEX output."
for g in self.geometries.hex_wkt:
- geom = fromstr(g.wkt)
- self.assertEqual(g.hex, geom.hex.decode())
+ with self.subTest(g=g):
+ geom = fromstr(g.wkt)
+ self.assertEqual(g.hex, geom.hex.decode())
def test_hexewkb(self):
"Testing (HEX)EWKB output."
@@ -92,28 +110,35 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
geom = fromstr(tg.wkt)
kml = getattr(tg, "kml", False)
if kml:
- self.assertEqual(kml, geom.kml)
+ with self.subTest(tg=tg):
+ self.assertEqual(kml, geom.kml)
def test_errors(self):
"Testing the Error handlers."
# string-based
for err in self.geometries.errors:
- with self.assertRaises((GEOSException, ValueError)):
+ with (
+ self.subTest(err=err.wkt),
+ self.assertRaisesMessage((GEOSException, ValueError), err.msg),
+ ):
fromstr(err.wkt)
# Bad WKB
- with self.assertRaises(GEOSException):
+ with self.assertRaisesMessage(
+ GEOSException, self.error_checking_geom.format("GEOSWKBReader_read_r")
+ ):
GEOSGeometry(memoryview(b"0"))
class NotAGeometry:
pass
- # Some other object
- with self.assertRaises(TypeError):
- GEOSGeometry(NotAGeometry())
- # None
- with self.assertRaises(TypeError):
- GEOSGeometry(None)
+ for geom in (NotAGeometry(), None):
+ msg = f"Improper geometry input type: {type(geom)}"
+ with (
+ self.subTest(geom=geom),
+ self.assertRaisesMessage(TypeError, msg),
+ ):
+ GEOSGeometry(geom)
def test_wkb(self):
"Testing WKB output."
@@ -128,7 +153,8 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
geom_h = GEOSGeometry(g.hex)
# we need to do this so decimal places get normalized
geom_t = fromstr(g.wkt)
- self.assertEqual(geom_t.wkt, geom_h.wkt)
+ with self.subTest(g=g):
+ self.assertEqual(geom_t.wkt, geom_h.wkt)
def test_create_wkb(self):
"Testing creation from WKB."
@@ -137,7 +163,8 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
geom_h = GEOSGeometry(wkb)
# we need to do this so decimal places get normalized
geom_t = fromstr(g.wkt)
- self.assertEqual(geom_t.wkt, geom_h.wkt)
+ with self.subTest(g=g):
+ self.assertEqual(geom_t.wkt, geom_h.wkt)
def test_ewkt(self):
"Testing EWKT."
@@ -146,19 +173,21 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
for p in self.geometries.polygons:
ewkt = "SRID=%d;%s" % (srid, p.wkt)
poly = fromstr(ewkt)
- self.assertEqual(srid, poly.srid)
- self.assertEqual(srid, poly.shell.srid)
- self.assertEqual(srid, fromstr(poly.ewkt).srid) # Checking export
+ with self.subTest(p=p):
+ self.assertEqual(srid, poly.srid)
+ self.assertEqual(srid, poly.shell.srid)
+ self.assertEqual(srid, fromstr(poly.ewkt).srid) # Checking export
def test_json(self):
"Testing GeoJSON input/output (via GDAL)."
for g in self.geometries.json_geoms:
geom = GEOSGeometry(g.wkt)
- if not hasattr(g, "not_equal"):
- # Loading jsons to prevent decimal differences
- self.assertEqual(json.loads(g.json), json.loads(geom.json))
- self.assertEqual(json.loads(g.json), json.loads(geom.geojson))
- self.assertEqual(GEOSGeometry(g.wkt, 4326), GEOSGeometry(geom.json))
+ with self.subTest(g=g):
+ if not hasattr(g, "not_equal"):
+ # Loading jsons to prevent decimal differences
+ self.assertEqual(json.loads(g.json), json.loads(geom.json))
+ self.assertEqual(json.loads(g.json), json.loads(geom.geojson))
+ self.assertEqual(GEOSGeometry(g.wkt, 4326), GEOSGeometry(geom.json))
def test_json_srid(self):
geojson_data = {
@@ -187,7 +216,8 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
for fh in (wkt_f, wkb_f):
fh.seek(0)
pnt = fromfile(fh)
- self.assertEqual(ref_pnt, pnt)
+ with self.subTest(fh=fh):
+ self.assertEqual(ref_pnt, pnt)
def test_eq(self):
"Testing equivalence."
@@ -201,9 +231,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
# Error shouldn't be raise on equivalence testing with
# an invalid type.
for g in (p, ls):
- self.assertIsNotNone(g)
- self.assertNotEqual(g, {"foo": "bar"})
- self.assertIsNot(g, False)
+ with self.subTest(g=g):
+ self.assertIsNotNone(g)
+ self.assertNotEqual(g, {"foo": "bar"})
+ self.assertIsNot(g, False)
def test_hash(self):
point_1 = Point(5, 23)
@@ -331,55 +362,56 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
for p in self.geometries.points:
# Creating the point from the WKT
pnt = fromstr(p.wkt)
- self.assertEqual(pnt.geom_type, "Point")
- self.assertEqual(pnt.geom_typeid, 0)
- self.assertEqual(pnt.dims, 0)
- self.assertEqual(p.x, pnt.x)
- self.assertEqual(p.y, pnt.y)
- self.assertEqual(pnt, fromstr(p.wkt))
- self.assertIs(pnt == prev, False) # Use assertIs() to test __eq__.
+ with self.subTest(p=p):
+ self.assertEqual(pnt.geom_type, "Point")
+ self.assertEqual(pnt.geom_typeid, 0)
+ self.assertEqual(pnt.dims, 0)
+ self.assertEqual(p.x, pnt.x)
+ self.assertEqual(p.y, pnt.y)
+ self.assertEqual(pnt, fromstr(p.wkt))
+ self.assertIs(pnt == prev, False) # Use assertIs() to test __eq__.
- # Making sure that the point's X, Y components are what we expect
- self.assertAlmostEqual(p.x, pnt.tuple[0], 9)
- self.assertAlmostEqual(p.y, pnt.tuple[1], 9)
+ # Making sure that the point's X, Y components are what we expect
+ self.assertAlmostEqual(p.x, pnt.tuple[0], 9)
+ self.assertAlmostEqual(p.y, pnt.tuple[1], 9)
- # Testing the third dimension, and getting the tuple arguments
- if hasattr(p, "z"):
- self.assertIs(pnt.hasz, True)
- self.assertEqual(p.z, pnt.z)
- self.assertEqual(p.z, pnt.tuple[2], 9)
- tup_args = (p.x, p.y, p.z)
- set_tup1 = (2.71, 3.14, 5.23)
- set_tup2 = (5.23, 2.71, 3.14)
- else:
- self.assertIs(pnt.hasz, False)
- self.assertIsNone(pnt.z)
- tup_args = (p.x, p.y)
- set_tup1 = (2.71, 3.14)
- set_tup2 = (3.14, 2.71)
+ # Testing the third dimension, and getting the tuple arguments
+ if hasattr(p, "z"):
+ self.assertIs(pnt.hasz, True)
+ self.assertEqual(p.z, pnt.z)
+ self.assertEqual(p.z, pnt.tuple[2], 9)
+ tup_args = (p.x, p.y, p.z)
+ set_tup1 = (2.71, 3.14, 5.23)
+ set_tup2 = (5.23, 2.71, 3.14)
+ else:
+ self.assertIs(pnt.hasz, False)
+ self.assertIsNone(pnt.z)
+ tup_args = (p.x, p.y)
+ set_tup1 = (2.71, 3.14)
+ set_tup2 = (3.14, 2.71)
- # Centroid operation on point should be point itself
- self.assertEqual(p.centroid, pnt.centroid.tuple)
+ # Centroid operation on point should be point itself
+ self.assertEqual(p.centroid, pnt.centroid.tuple)
- # Now testing the different constructors
- pnt2 = Point(tup_args) # e.g., Point((1, 2))
- pnt3 = Point(*tup_args) # e.g., Point(1, 2)
- self.assertEqual(pnt, pnt2)
- self.assertEqual(pnt, pnt3)
+ # Now testing the different constructors
+ pnt2 = Point(tup_args) # e.g., Point((1, 2))
+ pnt3 = Point(*tup_args) # e.g., Point(1, 2)
+ self.assertEqual(pnt, pnt2)
+ self.assertEqual(pnt, pnt3)
- # Now testing setting the x and y
- pnt.y = 3.14
- pnt.x = 2.71
- self.assertEqual(3.14, pnt.y)
- self.assertEqual(2.71, pnt.x)
+ # Now testing setting the x and y
+ pnt.y = 3.14
+ pnt.x = 2.71
+ self.assertEqual(3.14, pnt.y)
+ self.assertEqual(2.71, pnt.x)
- # Setting via the tuple/coords property
- pnt.tuple = set_tup1
- self.assertEqual(set_tup1, pnt.tuple)
- pnt.coords = set_tup2
- self.assertEqual(set_tup2, pnt.coords)
+ # Setting via the tuple/coords property
+ pnt.tuple = set_tup1
+ self.assertEqual(set_tup1, pnt.tuple)
+ pnt.coords = set_tup2
+ self.assertEqual(set_tup2, pnt.coords)
- prev = pnt # setting the previous geometry
+ prev = pnt # setting the previous geometry
def test_point_reverse(self):
point = GEOSGeometry("POINT(144.963 -37.8143)", 4326)
@@ -391,56 +423,64 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
"Testing MultiPoint objects."
for mp in self.geometries.multipoints:
mpnt = fromstr(mp.wkt)
- self.assertEqual(mpnt.geom_type, "MultiPoint")
- self.assertEqual(mpnt.geom_typeid, 4)
- self.assertEqual(mpnt.dims, 0)
+ with self.subTest(mp=mp):
+ self.assertEqual(mpnt.geom_type, "MultiPoint")
+ self.assertEqual(mpnt.geom_typeid, 4)
+ self.assertEqual(mpnt.dims, 0)
- self.assertAlmostEqual(mp.centroid[0], mpnt.centroid.tuple[0], 9)
- self.assertAlmostEqual(mp.centroid[1], mpnt.centroid.tuple[1], 9)
+ self.assertAlmostEqual(mp.centroid[0], mpnt.centroid.tuple[0], 9)
+ self.assertAlmostEqual(mp.centroid[1], mpnt.centroid.tuple[1], 9)
- with self.assertRaises(IndexError):
- mpnt.__getitem__(len(mpnt))
- self.assertEqual(mp.centroid, mpnt.centroid.tuple)
- self.assertEqual(mp.coords, tuple(m.tuple for m in mpnt))
- for p in mpnt:
- self.assertEqual(p.geom_type, "Point")
- self.assertEqual(p.geom_typeid, 0)
- self.assertIs(p.empty, False)
- self.assertIs(p.valid, True)
+ mpnt_len = len(mpnt)
+ msg = f"invalid index: {mpnt_len}"
+ with self.assertRaisesMessage(IndexError, msg):
+ mpnt.__getitem__(mpnt_len)
+ self.assertEqual(mp.centroid, mpnt.centroid.tuple)
+ self.assertEqual(mp.coords, tuple(m.tuple for m in mpnt))
+ for p in mpnt:
+ self.assertEqual(p.geom_type, "Point")
+ self.assertEqual(p.geom_typeid, 0)
+ self.assertIs(p.empty, False)
+ self.assertIs(p.valid, True)
def test_linestring(self):
"Testing LineString objects."
prev = fromstr("POINT(0 0)")
for line in self.geometries.linestrings:
ls = fromstr(line.wkt)
- self.assertEqual(ls.geom_type, "LineString")
- self.assertEqual(ls.geom_typeid, 1)
- self.assertEqual(ls.dims, 1)
- self.assertIs(ls.empty, False)
- self.assertIs(ls.ring, False)
- if hasattr(line, "centroid"):
- self.assertEqual(line.centroid, ls.centroid.tuple)
- if hasattr(line, "tup"):
- self.assertEqual(line.tup, ls.tuple)
+ with self.subTest(line=line):
+ self.assertEqual(ls.geom_type, "LineString")
+ self.assertEqual(ls.geom_typeid, 1)
+ self.assertEqual(ls.dims, 1)
+ self.assertIs(ls.empty, False)
+ self.assertIs(ls.ring, False)
+ if hasattr(line, "centroid"):
+ self.assertEqual(line.centroid, ls.centroid.tuple)
+ if hasattr(line, "tup"):
+ self.assertEqual(line.tup, ls.tuple)
- self.assertEqual(ls, fromstr(line.wkt))
- self.assertIs(ls == prev, False) # Use assertIs() to test __eq__.
- with self.assertRaises(IndexError):
- ls.__getitem__(len(ls))
- prev = ls
+ self.assertEqual(ls, fromstr(line.wkt))
+ self.assertIs(ls == prev, False) # Use assertIs() to test __eq__.
+ ls_len = len(ls)
+ msg = f"invalid index: {ls_len}"
+ with self.assertRaisesMessage(IndexError, msg):
+ ls.__getitem__(ls_len)
+ prev = ls
- # Creating a LineString from a tuple, list, and numpy array
- self.assertEqual(ls, LineString(ls.tuple)) # tuple
- self.assertEqual(ls, LineString(*ls.tuple)) # as individual arguments
- self.assertEqual(ls, LineString([list(tup) for tup in ls.tuple])) # as list
- # Point individual arguments
- self.assertEqual(
- ls.wkt, LineString(*tuple(Point(tup) for tup in ls.tuple)).wkt
- )
- if numpy:
+ # Creating a LineString from a tuple, list, and numpy array
+ self.assertEqual(ls, LineString(ls.tuple)) # tuple
+ self.assertEqual(ls, LineString(*ls.tuple)) # as individual arguments
self.assertEqual(
- ls, LineString(numpy.array(ls.tuple))
- ) # as numpy array
+ ls, LineString([list(tup) for tup in ls.tuple])
+ ) # as list
+ # Point individual arguments
+ self.assertEqual(
+ ls.wkt, LineString(*tuple(Point(tup) for tup in ls.tuple)).wkt
+ )
+ if numpy:
+ self.assertEqual(
+ ls, LineString(numpy.array(ls.tuple))
+ ) # as numpy array
with self.assertRaisesMessage(
TypeError, "Each coordinate should be a sequence (list or tuple)"
@@ -499,46 +539,52 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
prev = fromstr("POINT(0 0)")
for line in self.geometries.multilinestrings:
ml = fromstr(line.wkt)
- self.assertEqual(ml.geom_type, "MultiLineString")
- self.assertEqual(ml.geom_typeid, 5)
- self.assertEqual(ml.dims, 1)
+ with self.subTest(line=line):
+ self.assertEqual(ml.geom_type, "MultiLineString")
+ self.assertEqual(ml.geom_typeid, 5)
+ self.assertEqual(ml.dims, 1)
- self.assertAlmostEqual(line.centroid[0], ml.centroid.x, 9)
- self.assertAlmostEqual(line.centroid[1], ml.centroid.y, 9)
+ self.assertAlmostEqual(line.centroid[0], ml.centroid.x, 9)
+ self.assertAlmostEqual(line.centroid[1], ml.centroid.y, 9)
- self.assertEqual(ml, fromstr(line.wkt))
- self.assertIs(ml == prev, False) # Use assertIs() to test __eq__.
- prev = ml
+ self.assertEqual(ml, fromstr(line.wkt))
+ self.assertIs(ml == prev, False) # Use assertIs() to test __eq__.
+ prev = ml
- for ls in ml:
- self.assertEqual(ls.geom_type, "LineString")
- self.assertEqual(ls.geom_typeid, 1)
- self.assertIs(ls.empty, False)
+ for ls in ml:
+ self.assertEqual(ls.geom_type, "LineString")
+ self.assertEqual(ls.geom_typeid, 1)
+ self.assertIs(ls.empty, False)
- with self.assertRaises(IndexError):
- ml.__getitem__(len(ml))
- self.assertEqual(ml.wkt, MultiLineString(*tuple(s.clone() for s in ml)).wkt)
- self.assertEqual(
- ml, MultiLineString(*tuple(LineString(s.tuple) for s in ml))
- )
+ ml_len = len(ml)
+ msg = f"invalid index: {ml_len}"
+ with self.assertRaisesMessage(IndexError, msg):
+ ml.__getitem__(ml_len)
+ self.assertEqual(
+ ml.wkt, MultiLineString(*tuple(s.clone() for s in ml)).wkt
+ )
+ self.assertEqual(
+ ml, MultiLineString(*tuple(LineString(s.tuple) for s in ml))
+ )
def test_linearring(self):
"Testing LinearRing objects."
for rr in self.geometries.linearrings:
lr = fromstr(rr.wkt)
- self.assertEqual(lr.geom_type, "LinearRing")
- self.assertEqual(lr.geom_typeid, 2)
- self.assertEqual(lr.dims, 1)
- self.assertEqual(rr.n_p, len(lr))
- self.assertIs(lr.valid, True)
- self.assertIs(lr.empty, False)
+ with self.subTest(rr=rr):
+ self.assertEqual(lr.geom_type, "LinearRing")
+ self.assertEqual(lr.geom_typeid, 2)
+ self.assertEqual(lr.dims, 1)
+ self.assertEqual(rr.n_p, len(lr))
+ self.assertIs(lr.valid, True)
+ self.assertIs(lr.empty, False)
- # Creating a LinearRing from a tuple, list, and numpy array
- self.assertEqual(lr, LinearRing(lr.tuple))
- self.assertEqual(lr, LinearRing(*lr.tuple))
- self.assertEqual(lr, LinearRing([list(tup) for tup in lr.tuple]))
- if numpy:
- self.assertEqual(lr, LinearRing(numpy.array(lr.tuple)))
+ # Creating a LinearRing from a tuple, list, and numpy array
+ self.assertEqual(lr, LinearRing(lr.tuple))
+ self.assertEqual(lr, LinearRing(*lr.tuple))
+ self.assertEqual(lr, LinearRing([list(tup) for tup in lr.tuple]))
+ if numpy:
+ self.assertEqual(lr, LinearRing(numpy.array(lr.tuple)))
with self.assertRaisesMessage(
ValueError, "LinearRing requires at least 4 points, got 3."
@@ -582,66 +628,77 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
for p in self.geometries.polygons:
# Creating the Polygon, testing its properties.
poly = fromstr(p.wkt)
- self.assertEqual(poly.geom_type, "Polygon")
- self.assertEqual(poly.geom_typeid, 3)
- self.assertEqual(poly.dims, 2)
- self.assertIs(poly.empty, False)
- self.assertIs(poly.ring, False)
- self.assertEqual(p.n_i, poly.num_interior_rings)
- self.assertEqual(p.n_i + 1, len(poly)) # Testing __len__
- self.assertEqual(p.n_p, poly.num_points)
+ with self.subTest(p=p):
+ self.assertEqual(poly.geom_type, "Polygon")
+ self.assertEqual(poly.geom_typeid, 3)
+ self.assertEqual(poly.dims, 2)
+ self.assertIs(poly.empty, False)
+ self.assertIs(poly.ring, False)
+ self.assertEqual(p.n_i, poly.num_interior_rings)
+ self.assertEqual(p.n_i + 1, len(poly)) # Testing __len__
+ self.assertEqual(p.n_p, poly.num_points)
- # Area & Centroid
- self.assertAlmostEqual(p.area, poly.area, 9)
- self.assertAlmostEqual(p.centroid[0], poly.centroid.tuple[0], 9)
- self.assertAlmostEqual(p.centroid[1], poly.centroid.tuple[1], 9)
+ # Area & Centroid
+ self.assertAlmostEqual(p.area, poly.area, 9)
+ self.assertAlmostEqual(p.centroid[0], poly.centroid.tuple[0], 9)
+ self.assertAlmostEqual(p.centroid[1], poly.centroid.tuple[1], 9)
- # Testing the geometry equivalence
- self.assertEqual(poly, fromstr(p.wkt))
- # Should not be equal to previous geometry
- self.assertIs(poly == prev, False) # Use assertIs() to test __eq__.
- self.assertIs(poly != prev, True) # Use assertIs() to test __ne__.
+ # Testing the geometry equivalence
+ self.assertEqual(poly, fromstr(p.wkt))
+ # Should not be equal to previous geometry
+ self.assertIs(poly == prev, False) # Use assertIs() to test __eq__.
+ self.assertIs(poly != prev, True) # Use assertIs() to test __ne__.
- # Testing the exterior ring
- ring = poly.exterior_ring
- self.assertEqual(ring.geom_type, "LinearRing")
- self.assertEqual(ring.geom_typeid, 2)
- if p.ext_ring_cs:
- self.assertEqual(p.ext_ring_cs, ring.tuple)
- self.assertEqual(p.ext_ring_cs, poly[0].tuple) # Testing __getitem__
+ # Testing the exterior ring
+ ring = poly.exterior_ring
+ self.assertEqual(ring.geom_type, "LinearRing")
+ self.assertEqual(ring.geom_typeid, 2)
+ if p.ext_ring_cs:
+ self.assertEqual(p.ext_ring_cs, ring.tuple)
+ self.assertEqual(
+ p.ext_ring_cs, poly[0].tuple
+ ) # Testing __getitem__
- # Testing __getitem__ and __setitem__ on invalid indices
- with self.assertRaises(IndexError):
- poly.__getitem__(len(poly))
- with self.assertRaises(IndexError):
- poly.__setitem__(len(poly), False)
- with self.assertRaises(IndexError):
- poly.__getitem__(-1 * len(poly) - 1)
+ # Testing __getitem__ and __setitem__ on invalid indices
+ poly_len = len(poly)
+ msg = f"invalid index: {poly_len}"
+ with self.assertRaisesMessage(IndexError, msg):
+ poly.__getitem__(poly_len)
+ with self.assertRaisesMessage(IndexError, msg):
+ poly.__setitem__(poly_len, False)
+ negative_index = -1 * poly_len - 1
+ msg = f"invalid index: {negative_index}"
+ with self.assertRaisesMessage(IndexError, msg):
+ poly.__getitem__(negative_index)
- # Testing __iter__
- for r in poly:
- self.assertEqual(r.geom_type, "LinearRing")
- self.assertEqual(r.geom_typeid, 2)
+ # Testing __iter__
+ for r in poly:
+ self.assertEqual(r.geom_type, "LinearRing")
+ self.assertEqual(r.geom_typeid, 2)
- # Testing polygon construction.
- with self.assertRaises(TypeError):
- Polygon(0, [1, 2, 3])
- with self.assertRaises(TypeError):
- Polygon("foo")
+ # Testing polygon construction.
+ msg = (
+ "Parameter must be a sequence of LinearRings or "
+ "objects that can initialize to LinearRings"
+ )
+ with self.assertRaisesMessage(TypeError, msg):
+ Polygon(0, [1, 2, 3])
+ with self.assertRaisesMessage(TypeError, msg):
+ Polygon("foo")
- # Polygon(shell, (hole1, ... holeN))
- ext_ring, *int_rings = poly
- self.assertEqual(poly, Polygon(ext_ring, int_rings))
+ # Polygon(shell, (hole1, ... holeN))
+ ext_ring, *int_rings = poly
+ self.assertEqual(poly, Polygon(ext_ring, int_rings))
- # Polygon(shell_tuple, hole_tuple1, ... , hole_tupleN)
- ring_tuples = tuple(r.tuple for r in poly)
- self.assertEqual(poly, Polygon(*ring_tuples))
+ # Polygon(shell_tuple, hole_tuple1, ... , hole_tupleN)
+ ring_tuples = tuple(r.tuple for r in poly)
+ self.assertEqual(poly, Polygon(*ring_tuples))
- # Constructing with tuples of LinearRings.
- self.assertEqual(poly.wkt, Polygon(*tuple(r for r in poly)).wkt)
- self.assertEqual(
- poly.wkt, Polygon(*tuple(LinearRing(r.tuple) for r in poly)).wkt
- )
+ # Constructing with tuples of LinearRings.
+ self.assertEqual(poly.wkt, Polygon(*tuple(r for r in poly)).wkt)
+ self.assertEqual(
+ poly.wkt, Polygon(*tuple(LinearRing(r.tuple) for r in poly)).wkt
+ )
def test_polygons_templates(self):
# Accessing Polygon attributes in templates should work.
@@ -667,24 +724,28 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
fromstr("POINT (0 0)")
for mp in self.geometries.multipolygons:
mpoly = fromstr(mp.wkt)
- self.assertEqual(mpoly.geom_type, "MultiPolygon")
- self.assertEqual(mpoly.geom_typeid, 6)
- self.assertEqual(mpoly.dims, 2)
- self.assertEqual(mp.valid, mpoly.valid)
+ with self.subTest(mp=mp):
+ self.assertEqual(mpoly.geom_type, "MultiPolygon")
+ self.assertEqual(mpoly.geom_typeid, 6)
+ self.assertEqual(mpoly.dims, 2)
+ self.assertEqual(mp.valid, mpoly.valid)
- if mp.valid:
- self.assertEqual(mp.num_geom, mpoly.num_geom)
- self.assertEqual(mp.n_p, mpoly.num_coords)
- self.assertEqual(mp.num_geom, len(mpoly))
- with self.assertRaises(IndexError):
- mpoly.__getitem__(len(mpoly))
- for p in mpoly:
- self.assertEqual(p.geom_type, "Polygon")
- self.assertEqual(p.geom_typeid, 3)
- self.assertIs(p.valid, True)
- self.assertEqual(
- mpoly.wkt, MultiPolygon(*tuple(poly.clone() for poly in mpoly)).wkt
- )
+ if mp.valid:
+ mpoly_len = len(mpoly)
+ self.assertEqual(mp.num_geom, mpoly.num_geom)
+ self.assertEqual(mp.n_p, mpoly.num_coords)
+ self.assertEqual(mp.num_geom, mpoly_len)
+ msg = f"invalid index: {mpoly_len}"
+ with self.assertRaisesMessage(IndexError, msg):
+ mpoly.__getitem__(mpoly_len)
+ for p in mpoly:
+ self.assertEqual(p.geom_type, "Polygon")
+ self.assertEqual(p.geom_typeid, 3)
+ self.assertIs(p.valid, True)
+ self.assertEqual(
+ mpoly.wkt,
+ MultiPolygon(*tuple(poly.clone() for poly in mpoly)).wkt,
+ )
def test_memory_hijinks(self):
"Testing Geometry __del__() on rings and polygons."
@@ -713,46 +774,49 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
def test_coord_seq(self):
"Testing Coordinate Sequence objects."
for p in self.geometries.polygons:
- if p.ext_ring_cs:
- # Constructing the polygon and getting the coordinate sequence
- poly = fromstr(p.wkt)
- cs = poly.exterior_ring.coord_seq
+ with self.subTest(p=p):
+ if p.ext_ring_cs:
+ # Constructing the polygon and getting the coordinate sequence
+ poly = fromstr(p.wkt)
+ cs = poly.exterior_ring.coord_seq
- self.assertEqual(
- p.ext_ring_cs, cs.tuple
- ) # done in the Polygon test too.
- self.assertEqual(
- len(p.ext_ring_cs), len(cs)
- ) # Making sure __len__ works
+ self.assertEqual(
+ p.ext_ring_cs, cs.tuple
+ ) # done in the Polygon test too.
+ self.assertEqual(
+ len(p.ext_ring_cs), len(cs)
+ ) # Making sure __len__ works
- # Checks __getitem__ and __setitem__
- for i in range(len(p.ext_ring_cs)):
- c1 = p.ext_ring_cs[i] # Expected value
- c2 = cs[i] # Value from coordseq
- self.assertEqual(c1, c2)
+ # Checks __getitem__ and __setitem__
+ for i in range(len(p.ext_ring_cs)):
+ c1 = p.ext_ring_cs[i] # Expected value
+ c2 = cs[i] # Value from coordseq
+ self.assertEqual(c1, c2)
- # Constructing the test value to set the coordinate sequence with
- if len(c1) == 2:
- tset = (5, 23)
- else:
- tset = (5, 23, 8)
- cs[i] = tset
-
- # Making sure every set point matches what we expect
- for j in range(len(tset)):
+ # Construct the test value to set the coordinate sequence with
+ if len(c1) == 2:
+ tset = (5, 23)
+ else:
+ tset = (5, 23, 8)
cs[i] = tset
- self.assertEqual(tset[j], cs[i][j])
+
+ # Making sure every set point matches what we expect
+ for j in range(len(tset)):
+ cs[i] = tset
+ self.assertEqual(tset[j], cs[i][j])
def test_relate_pattern(self):
"Testing relate() and relate_pattern()."
g = fromstr("POINT (0 0)")
- with self.assertRaises(GEOSException):
+ msg = "invalid intersection matrix pattern"
+ with self.assertRaisesMessage(GEOSException, msg):
g.relate_pattern(0, "invalid pattern, yo")
for rg in self.geometries.relate_geoms:
a = fromstr(rg.wkt_a)
b = fromstr(rg.wkt_b)
- self.assertEqual(rg.result, a.relate_pattern(b, rg.pattern))
- self.assertEqual(rg.pattern, a.relate(b))
+ with self.subTest(rg=rg):
+ self.assertEqual(rg.result, a.relate_pattern(b, rg.pattern))
+ self.assertEqual(rg.pattern, a.relate(b))
def test_intersection(self):
"Testing intersects() and intersection()."
@@ -760,12 +824,13 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
a = fromstr(self.geometries.topology_geoms[i].wkt_a)
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
i1 = fromstr(self.geometries.intersect_geoms[i].wkt)
- self.assertIs(a.intersects(b), True)
i2 = a.intersection(b)
- self.assertTrue(i1.equals(i2))
- self.assertTrue(i1.equals(a & b)) # __and__ is intersection operator
- a &= b # testing __iand__
- self.assertTrue(i1.equals(a))
+ with self.subTest(i=i):
+ self.assertIs(a.intersects(b), True)
+ self.assertTrue(i1.equals(i2))
+ self.assertTrue(i1.equals(a & b)) # __and__ is intersection operator
+ a &= b # testing __iand__
+ self.assertTrue(i1.equals(a))
def test_union(self):
"Testing union()."
@@ -774,10 +839,11 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
u1 = fromstr(self.geometries.union_geoms[i].wkt)
u2 = a.union(b)
- self.assertTrue(u1.equals(u2))
- self.assertTrue(u1.equals(a | b)) # __or__ is union operator
- a |= b # testing __ior__
- self.assertTrue(u1.equals(a))
+ with self.subTest(i=i):
+ self.assertTrue(u1.equals(u2))
+ self.assertTrue(u1.equals(a | b)) # __or__ is union operator
+ a |= b # testing __ior__
+ self.assertTrue(u1.equals(a))
def test_unary_union(self):
"Testing unary_union."
@@ -786,7 +852,8 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
u1 = fromstr(self.geometries.union_geoms[i].wkt)
u2 = GeometryCollection(a, b).unary_union
- self.assertTrue(u1.equals(u2))
+ with self.subTest(i=i):
+ self.assertTrue(u1.equals(u2))
def test_difference(self):
"Testing difference()."
@@ -795,10 +862,11 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
d1 = fromstr(self.geometries.diff_geoms[i].wkt)
d2 = a.difference(b)
- self.assertTrue(d1.equals(d2))
- self.assertTrue(d1.equals(a - b)) # __sub__ is difference operator
- a -= b # testing __isub__
- self.assertTrue(d1.equals(a))
+ with self.subTest(i=i):
+ self.assertTrue(d1.equals(d2))
+ self.assertTrue(d1.equals(a - b)) # __sub__ is difference operator
+ a -= b # testing __isub__
+ self.assertTrue(d1.equals(a))
def test_symdifference(self):
"Testing sym_difference()."
@@ -807,19 +875,20 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
b = fromstr(self.geometries.topology_geoms[i].wkt_b)
d1 = fromstr(self.geometries.sdiff_geoms[i].wkt)
d2 = a.sym_difference(b)
- self.assertTrue(d1.equals(d2))
- self.assertTrue(
- d1.equals(a ^ b)
- ) # __xor__ is symmetric difference operator
- a ^= b # testing __ixor__
- self.assertTrue(d1.equals(a))
+ with self.subTest(i=i):
+ self.assertTrue(d1.equals(d2))
+ self.assertTrue(
+ d1.equals(a ^ b)
+ ) # __xor__ is symmetric difference operator
+ a ^= b # testing __ixor__
+ self.assertTrue(d1.equals(a))
def test_buffer(self):
bg = self.geometries.buffer_geoms[0]
g = fromstr(bg.wkt)
# Can't use a floating-point for the number of quadsegs.
- with self.assertRaises(ctypes.ArgumentError):
+ with self.assertArgumentTypeError(4, "float"):
g.buffer(bg.width, quadsegs=1.1)
self._test_buffer(self.geometries.buffer_geoms, "buffer")
@@ -829,21 +898,22 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
g = fromstr(bg.wkt)
# Can't use a floating-point for the number of quadsegs.
- with self.assertRaises(ctypes.ArgumentError):
+ with self.assertArgumentTypeError(4, "float"):
g.buffer_with_style(bg.width, quadsegs=1.1)
# Can't use a floating-point for the end cap style.
- with self.assertRaises(ctypes.ArgumentError):
+ with self.assertArgumentTypeError(5, "float"):
g.buffer_with_style(bg.width, end_cap_style=1.2)
# Can't use a end cap style that is not in the enum.
- with self.assertRaises(GEOSException):
+ msg = self.error_checking_geom.format("GEOSBufferWithStyle_r")
+ with self.assertRaisesMessage(GEOSException, msg):
g.buffer_with_style(bg.width, end_cap_style=55)
# Can't use a floating-point for the join style.
- with self.assertRaises(ctypes.ArgumentError):
+ with self.assertArgumentTypeError(6, "float"):
g.buffer_with_style(bg.width, join_style=1.3)
# Can't use a join style that is not in the enum.
- with self.assertRaises(GEOSException):
+ with self.assertRaisesMessage(GEOSException, msg):
g.buffer_with_style(bg.width, join_style=66)
self._test_buffer(
@@ -873,19 +943,20 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
if hasattr(bg, kwarg_name)
}
buf = getattr(g, buffer_method_name)(**buf_kwargs)
- self.assertEqual(exp_buf.num_coords, buf.num_coords)
- self.assertEqual(len(exp_buf), len(buf))
+ with self.subTest(bg=bg):
+ self.assertEqual(exp_buf.num_coords, buf.num_coords)
+ self.assertEqual(len(exp_buf), len(buf))
- # Now assuring that each point in the buffer is almost equal
- for j in range(len(exp_buf)):
- exp_ring = exp_buf[j]
- buf_ring = buf[j]
- self.assertEqual(len(exp_ring), len(buf_ring))
- for k in range(len(exp_ring)):
- # Asserting the X, Y of each point are almost equal (due to
- # floating point imprecision).
- self.assertAlmostEqual(exp_ring[k][0], buf_ring[k][0], 9)
- self.assertAlmostEqual(exp_ring[k][1], buf_ring[k][1], 9)
+ # Now assuring that each point in the buffer is almost equal
+ for j in range(len(exp_buf)):
+ exp_ring = exp_buf[j]
+ buf_ring = buf[j]
+ self.assertEqual(len(exp_ring), len(buf_ring))
+ for k in range(len(exp_ring)):
+ # Asserting the X, Y of each point are almost equal (due to
+ # floating point imprecision).
+ self.assertAlmostEqual(exp_ring[k][0], buf_ring[k][0], 9)
+ self.assertAlmostEqual(exp_ring[k][1], buf_ring[k][1], 9)
def test_covers(self):
poly = Polygon(((0, 0), (0, 10), (10, 10), (10, 0), (0, 0)))
@@ -905,14 +976,15 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
self.assertEqual(4326, pnt.srid)
pnt.srid = 3084
self.assertEqual(3084, pnt.srid)
- with self.assertRaises(ctypes.ArgumentError):
+ with self.assertArgumentTypeError(3, "str"):
pnt.srid = "4326"
# Testing SRID keyword on fromstr(), and on Polygon rings.
poly = fromstr(self.geometries.polygons[1].wkt, srid=4269)
self.assertEqual(4269, poly.srid)
for ring in poly:
- self.assertEqual(4269, ring.srid)
+ with self.subTest(ring=ring):
+ self.assertEqual(4269, ring.srid)
poly.srid = 4326
self.assertEqual(4326, poly.shell.srid)
@@ -922,7 +994,8 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
)
self.assertEqual(32021, gc.srid)
for i in range(len(gc)):
- self.assertEqual(32021, gc[i].srid)
+ with self.subTest(i=i):
+ self.assertEqual(32021, gc[i].srid)
# GEOS may get the SRID from HEXEWKB
# 'POINT(5 23)' at SRID=4326 in hex form -- obtained from PostGIS
@@ -956,49 +1029,54 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
"""Test with a null srid and a srid unknown to GDAL."""
for srid in [None, 999999]:
pnt = Point(111200, 220900, srid=srid)
- self.assertTrue(
- pnt.ewkt.startswith(
- ("SRID=%s;" % srid if srid else "") + "POINT (111200"
+ with self.subTest(srid=srid):
+ self.assertTrue(
+ pnt.ewkt.startswith(
+ ("SRID=%s;" % srid if srid else "") + "POINT (111200"
+ )
)
- )
- self.assertIsInstance(pnt.ogr, gdal.OGRGeometry)
- self.assertIsNone(pnt.srs)
+ self.assertIsInstance(pnt.ogr, gdal.OGRGeometry)
+ self.assertIsNone(pnt.srs)
- # Test conversion from custom to a known srid
- c2w = gdal.CoordTransform(
- gdal.SpatialReference(
- "+proj=mill +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +R_A +datum=WGS84 "
- "+units=m +no_defs"
- ),
- gdal.SpatialReference(4326),
- )
- new_pnt = pnt.transform(c2w, clone=True)
- self.assertEqual(new_pnt.srid, 4326)
- self.assertAlmostEqual(new_pnt.x, 1, 1)
- self.assertAlmostEqual(new_pnt.y, 2, 1)
+ # Test conversion from custom to a known srid
+ c2w = gdal.CoordTransform(
+ gdal.SpatialReference(
+ "+proj=mill +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +R_A +datum=WGS84 "
+ "+units=m +no_defs"
+ ),
+ gdal.SpatialReference(4326),
+ )
+ new_pnt = pnt.transform(c2w, clone=True)
+ self.assertEqual(new_pnt.srid, 4326)
+ self.assertAlmostEqual(new_pnt.x, 1, 1)
+ self.assertAlmostEqual(new_pnt.y, 2, 1)
def test_mutable_geometries(self):
"Testing the mutability of Polygons and Geometry Collections."
# ### Testing the mutability of Polygons ###
for p in self.geometries.polygons:
poly = fromstr(p.wkt)
+ msg = (
+ "Parameter must be a sequence of LinearRings or objects that can "
+ "initialize to LinearRings"
+ )
+ with self.subTest(p=p):
+ # Should only be able to use __setitem__ with LinearRing geometries.
+ with self.assertRaisesMessage(TypeError, msg):
+ poly.__setitem__(0, LineString((1, 1), (2, 2)))
- # Should only be able to use __setitem__ with LinearRing geometries.
- with self.assertRaises(TypeError):
- poly.__setitem__(0, LineString((1, 1), (2, 2)))
+ # Construct the new shell by adding 500 to every point in the old shell.
+ shell_tup = poly.shell.tuple
+ new_coords = []
+ for point in shell_tup:
+ new_coords.append((point[0] + 500.0, point[1] + 500.0))
+ new_shell = LinearRing(*tuple(new_coords))
- # Constructing the new shell by adding 500 to every point in the old shell.
- shell_tup = poly.shell.tuple
- new_coords = []
- for point in shell_tup:
- new_coords.append((point[0] + 500.0, point[1] + 500.0))
- new_shell = LinearRing(*tuple(new_coords))
-
- # Assigning polygon's exterior ring w/the new shell
- poly.exterior_ring = new_shell
- str(new_shell) # new shell is still accessible
- self.assertEqual(poly.exterior_ring, new_shell)
- self.assertEqual(poly[0], new_shell)
+ # Assigning polygon's exterior ring w/the new shell
+ poly.exterior_ring = new_shell
+ str(new_shell) # new shell is still accessible
+ self.assertEqual(poly.exterior_ring, new_shell)
+ self.assertEqual(poly[0], new_shell)
# ### Testing the mutability of Geometry Collections
for tg in self.geometries.multipoints:
@@ -1007,12 +1085,13 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
# Creating a random point.
pnt = mp[i]
new = Point(random.randint(21, 100), random.randint(21, 100))
- # Testing the assignment
- mp[i] = new
- str(new) # what was used for the assignment is still accessible
- self.assertEqual(mp[i], new)
- self.assertEqual(mp[i].wkt, new.wkt)
- self.assertNotEqual(pnt, mp[i])
+ with self.subTest(tg=tg, i=i):
+ # Testing the assignment
+ mp[i] = new
+ str(new) # what was used for the assignment is still accessible
+ self.assertEqual(mp[i], new)
+ self.assertEqual(mp[i].wkt, new.wkt)
+ self.assertNotEqual(pnt, mp[i])
# MultiPolygons involve much more memory management because each
# Polygon w/in the collection has its own rings.
@@ -1028,12 +1107,13 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
r[k] = (r[k][0] + 500.0, r[k][1] + 500.0)
poly[j] = r
- self.assertNotEqual(mpoly[i], poly)
- # Testing the assignment
- mpoly[i] = poly
- str(poly) # Still accessible
- self.assertEqual(mpoly[i], poly)
- self.assertNotEqual(mpoly[i], old_poly)
+ with self.subTest(tg=tg, i=i, j=j):
+ self.assertNotEqual(mpoly[i], poly)
+ # Testing the assignment
+ mpoly[i] = poly
+ str(poly) # Still accessible
+ self.assertEqual(mpoly[i], poly)
+ self.assertNotEqual(mpoly[i], old_poly)
# Extreme (!!) __setitem__ -- no longer works, have to detect
# in the first object that __setitem__ is called in the subsequent
@@ -1056,9 +1136,9 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
p[:] = (1, 2)
self.assertEqual(p.wkt, Point(1, 2))
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, "Must have at least 2 items"):
p[:] = (1,)
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, "Cannot have more than 3 items"):
p[:] = (1, 2, 3, 4, 5)
def test_linestring_list_assignment(self):
@@ -1070,7 +1150,7 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
ls[:] = ((0, 0), (1, 1), (2, 2))
self.assertEqual(ls, LineString((0, 0), (1, 1), (2, 2)))
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, "Must have at least 2 items"):
ls[:] = (1,)
def test_linearring_list_assignment(self):
@@ -1082,7 +1162,7 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
ls[:] = ((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))
self.assertEqual(ls, LinearRing((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)))
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, "Must have at least 4 items"):
ls[:] = ((0, 0), (1, 1), (2, 2))
def test_polygon_list_assignment(self):
@@ -1114,7 +1194,8 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
# Testing a 3D Point
pnt = Point(2, 3, 8)
self.assertEqual((2.0, 3.0, 8.0), pnt.coords)
- with self.assertRaises(TypeError):
+ msg = "Dimension of value does not match."
+ with self.assertRaisesMessage(TypeError, msg):
pnt.tuple = (1.0, 2.0)
pnt.coords = (1.0, 2.0, 3.0)
self.assertEqual((1.0, 2.0, 3.0), pnt.coords)
@@ -1122,7 +1203,7 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
# Testing a 3D LineString
ls = LineString((2.0, 3.0, 8.0), (50.0, 250.0, -117.0))
self.assertEqual(((2.0, 3.0, 8.0), (50.0, 250.0, -117.0)), ls.tuple)
- with self.assertRaises(TypeError):
+ with self.assertRaisesMessage(TypeError, msg):
ls.__setitem__(0, (1.0, 2.0))
ls[0] = (1.0, 2.0, 3.0)
self.assertEqual((1.0, 2.0, 3.0), ls[0])
@@ -1186,36 +1267,40 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
geoms.append(LineString(numpy.array([])))
for g in geoms:
- self.assertIs(g.empty, True)
+ with self.subTest(g=g):
+ self.assertIs(g.empty, True)
- # Testing len() and num_geom.
- if isinstance(g, Polygon):
- self.assertEqual(1, len(g)) # Has one empty linear ring
- self.assertEqual(1, g.num_geom)
- self.assertEqual(0, len(g[0]))
- elif isinstance(g, (Point, LineString)):
- self.assertEqual(1, g.num_geom)
- self.assertEqual(0, len(g))
- else:
- self.assertEqual(0, g.num_geom)
- self.assertEqual(0, len(g))
+ # Testing len() and num_geom.
+ if isinstance(g, Polygon):
+ self.assertEqual(1, len(g)) # Has one empty linear ring
+ self.assertEqual(1, g.num_geom)
+ self.assertEqual(0, len(g[0]))
+ elif isinstance(g, (Point, LineString)):
+ self.assertEqual(1, g.num_geom)
+ self.assertEqual(0, len(g))
+ else:
+ self.assertEqual(0, g.num_geom)
+ self.assertEqual(0, len(g))
- # Testing __getitem__ (doesn't work on Point or Polygon)
- if isinstance(g, Point):
- # IndexError is not raised in GEOS 3.8.0.
- if geos_version_tuple() != (3, 8, 0):
- with self.assertRaises(IndexError):
- g.x
- elif isinstance(g, Polygon):
- lr = g.shell
- self.assertEqual("LINEARRING EMPTY", lr.wkt)
- self.assertEqual(0, len(lr))
- self.assertIs(lr.empty, True)
- with self.assertRaises(IndexError):
- lr.__getitem__(0)
- else:
- with self.assertRaises(IndexError):
- g.__getitem__(0)
+ # Testing __getitem__ (doesn't work on Point or Polygon)
+ if isinstance(g, Point):
+ # IndexError is not raised in GEOS 3.8.0.
+ if geos_version_tuple() != (3, 8, 0):
+ msg = "invalid GEOS Geometry index:"
+ with self.assertRaisesMessage(IndexError, msg):
+ g.x
+ elif isinstance(g, Polygon):
+ lr = g.shell
+ self.assertEqual("LINEARRING EMPTY", lr.wkt)
+ self.assertEqual(0, len(lr))
+ self.assertIs(lr.empty, True)
+ msg = "invalid index: 0"
+ with self.assertRaisesMessage(IndexError, msg):
+ lr.__getitem__(0)
+ else:
+ msg = "invalid index: 0"
+ with self.assertRaisesMessage(IndexError, msg):
+ g.__getitem__(0)
def test_collection_dims(self):
gc = GeometryCollection([])
@@ -1306,8 +1391,9 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
# correct as having a 1 meter accuracy.
prec = -1
for p in (t1, t2, t3, k2):
- self.assertAlmostEqual(trans.x, p.x, prec)
- self.assertAlmostEqual(trans.y, p.y, prec)
+ with self.subTest(p=p):
+ self.assertAlmostEqual(trans.x, p.x, prec)
+ self.assertAlmostEqual(trans.y, p.y, prec)
def test_transform_3d(self):
p3d = GEOSGeometry("POINT (5 23 100)", 4326)
@@ -1332,22 +1418,14 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
def test_transform_nosrid(self):
"""Testing `transform` method (no SRID or negative SRID)"""
-
- g = GEOSGeometry("POINT (-104.609 38.255)", srid=None)
- with self.assertRaises(GEOSException):
- g.transform(2774)
-
- g = GEOSGeometry("POINT (-104.609 38.255)", srid=None)
- with self.assertRaises(GEOSException):
- g.transform(2774, clone=True)
-
- g = GEOSGeometry("POINT (-104.609 38.255)", srid=-1)
- with self.assertRaises(GEOSException):
- g.transform(2774)
-
- g = GEOSGeometry("POINT (-104.609 38.255)", srid=-1)
- with self.assertRaises(GEOSException):
- g.transform(2774, clone=True)
+ msg = "Calling transform() with no SRID set is not supported"
+ for srid, clone in itertools.product((None, -1), (True, False)):
+ g = GEOSGeometry("POINT (-104.609 38.255)", srid=srid)
+ with (
+ self.subTest(srid=srid, clone=clone),
+ self.assertRaisesMessage(GEOSException, msg),
+ ):
+ g.transform(2774, clone=clone)
def test_extent(self):
"Testing `extent` method."
@@ -1382,8 +1460,9 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
for geom in tgeoms:
s1 = pickle.dumps(geom)
g1 = pickle.loads(s1)
- self.assertEqual(geom, g1)
- self.assertEqual(geom.srid, g1.srid)
+ with self.subTest(geom=geom):
+ self.assertEqual(geom, g1)
+ self.assertEqual(geom.srid, g1.srid)
def test_prepared(self):
"Testing PreparedGeometry support."
@@ -1397,9 +1476,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
pnts = [Point(5, 5), Point(7.5, 7.5), Point(2.5, 7.5)]
for pnt in pnts:
# Results should be the same (but faster)
- self.assertEqual(mpoly.contains(pnt), prep.contains(pnt))
- self.assertEqual(mpoly.intersects(pnt), prep.intersects(pnt))
- self.assertEqual(mpoly.covers(pnt), prep.covers(pnt))
+ with self.subTest(pnt=pnt):
+ self.assertEqual(mpoly.contains(pnt), prep.contains(pnt))
+ self.assertEqual(mpoly.intersects(pnt), prep.intersects(pnt))
+ self.assertEqual(mpoly.covers(pnt), prep.covers(pnt))
self.assertTrue(prep.crosses(fromstr("LINESTRING(1 1, 15 15)")))
self.assertTrue(prep.disjoint(Point(-5, -5)))
@@ -1643,5 +1723,5 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
# Step into CoordSeq iterator.
next(it)
ls[:] = []
- with self.assertRaises(IndexError):
+ with self.assertRaisesMessage(IndexError, "invalid index: 1"):
next(it)
diff --git a/tests/gis_tests/geos_tests/test_geos_mutation.py b/tests/gis_tests/geos_tests/test_geos_mutation.py
index c239ab3efe..eada4d664b 100644
--- a/tests/gis_tests/geos_tests/test_geos_mutation.py
+++ b/tests/gis_tests/geos_tests/test_geos_mutation.py
@@ -2,8 +2,6 @@
# Modified from original contribution by Aryeh Leib Taurog, which was
# released under the New BSD license.
-import unittest
-
from django.contrib.gis.geos import (
LinearRing,
LineString,
@@ -12,6 +10,7 @@ from django.contrib.gis.geos import (
Polygon,
fromstr,
)
+from django.test import SimpleTestCase
def api_get_distance(x):
@@ -77,7 +76,7 @@ geos_function_tests = [
]
-class GEOSMutationTest(unittest.TestCase):
+class GEOSMutationTest(SimpleTestCase):
"""
Tests Pythonic Mutability of Python GEOS geometry wrappers
get/set/delitem on a slice, normal list methods
@@ -87,33 +86,41 @@ class GEOSMutationTest(unittest.TestCase):
"Testing Geometry IndexError"
p = Point(1, 2)
for i in range(-2, 2):
- p._checkindex(i)
- with self.assertRaises(IndexError):
- p._checkindex(2)
- with self.assertRaises(IndexError):
- p._checkindex(-3)
+ with self.subTest(i=i):
+ p._checkindex(i)
+
+ for i in (2, -3):
+ with (
+ self.subTest(i=i),
+ self.assertRaisesMessage(IndexError, f"invalid index: {i}"),
+ ):
+ p._checkindex(i)
def test01_PointMutations(self):
"Testing Point mutations"
for p in (Point(1, 2, 3), fromstr("POINT (1 2 3)")):
- self.assertEqual(
- p._get_single_external(1), 2.0, "Point _get_single_external"
- )
+ with self.subTest(p=p):
+ self.assertEqual(
+ p._get_single_external(1), 2.0, "Point _get_single_external"
+ )
- # _set_single
- p._set_single(0, 100)
- self.assertEqual(p.coords, (100.0, 2.0, 3.0), "Point _set_single")
+ # _set_single
+ p._set_single(0, 100)
+ self.assertEqual(p.coords, (100.0, 2.0, 3.0), "Point _set_single")
- # _set_list
- p._set_list(2, (50, 3141))
- self.assertEqual(p.coords, (50.0, 3141.0), "Point _set_list")
+ # _set_list
+ p._set_list(2, (50, 3141))
+ self.assertEqual(p.coords, (50.0, 3141.0), "Point _set_list")
def test02_PointExceptions(self):
"Testing Point exceptions"
- with self.assertRaises(TypeError):
- Point(range(1))
- with self.assertRaises(TypeError):
- Point(range(4))
+ msg = "Invalid parameters given for Point initialization."
+ for i in (range(1), range(4)):
+ with (
+ self.subTest(i=i),
+ self.assertRaisesMessage(TypeError, msg),
+ ):
+ Point(i)
def test03_PointApi(self):
"Testing Point API"
@@ -121,7 +128,8 @@ class GEOSMutationTest(unittest.TestCase):
for p in (Point(1, 2, 3), fromstr("POINT (1 2 3)")):
p[0:2] = [4, 5]
for f in geos_function_tests:
- self.assertEqual(f(q), f(p), "Point " + f.__name__)
+ with self.subTest(p=p, f=f):
+ self.assertEqual(f(q), f(p), "Point " + f.__name__)
def test04_LineStringMutations(self):
"Testing LineString mutations"
@@ -129,29 +137,31 @@ class GEOSMutationTest(unittest.TestCase):
LineString((1, 0), (4, 1), (6, -1)),
fromstr("LINESTRING (1 0,4 1,6 -1)"),
):
- self.assertEqual(
- ls._get_single_external(1),
- (4.0, 1.0),
- "LineString _get_single_external",
- )
+ with self.subTest(ls=ls):
+ self.assertEqual(
+ ls._get_single_external(1),
+ (4.0, 1.0),
+ "LineString _get_single_external",
+ )
- # _set_single
- ls._set_single(0, (-50, 25))
- self.assertEqual(
- ls.coords,
- ((-50.0, 25.0), (4.0, 1.0), (6.0, -1.0)),
- "LineString _set_single",
- )
+ # _set_single
+ ls._set_single(0, (-50, 25))
+ self.assertEqual(
+ ls.coords,
+ ((-50.0, 25.0), (4.0, 1.0), (6.0, -1.0)),
+ "LineString _set_single",
+ )
- # _set_list
- ls._set_list(2, ((-50.0, 25.0), (6.0, -1.0)))
- self.assertEqual(
- ls.coords, ((-50.0, 25.0), (6.0, -1.0)), "LineString _set_list"
- )
+ # _set_list
+ ls._set_list(2, ((-50.0, 25.0), (6.0, -1.0)))
+ self.assertEqual(
+ ls.coords, ((-50.0, 25.0), (6.0, -1.0)), "LineString _set_list"
+ )
- lsa = LineString(ls.coords)
- for f in geos_function_tests:
- self.assertEqual(f(lsa), f(ls), "LineString " + f.__name__)
+ lsa = LineString(ls.coords)
+ for f in geos_function_tests:
+ with self.subTest(f=f):
+ self.assertEqual(f(lsa), f(ls), "LineString " + f.__name__)
def test05_Polygon(self):
"Testing Polygon mutations"
@@ -162,37 +172,45 @@ class GEOSMutationTest(unittest.TestCase):
),
fromstr("POLYGON ((1 0,4 1,6 -1,8 10,1 0),(5 4,6 4,6 3,5 4))"),
):
- self.assertEqual(
- pg._get_single_external(0),
- LinearRing((1, 0), (4, 1), (6, -1), (8, 10), (1, 0)),
- "Polygon _get_single_external(0)",
- )
- self.assertEqual(
- pg._get_single_external(1),
- LinearRing((5, 4), (6, 4), (6, 3), (5, 4)),
- "Polygon _get_single_external(1)",
- )
+ with self.subTest(pg=pg):
+ self.assertEqual(
+ pg._get_single_external(0),
+ LinearRing((1, 0), (4, 1), (6, -1), (8, 10), (1, 0)),
+ "Polygon _get_single_external(0)",
+ )
+ self.assertEqual(
+ pg._get_single_external(1),
+ LinearRing((5, 4), (6, 4), (6, 3), (5, 4)),
+ "Polygon _get_single_external(1)",
+ )
- # _set_list
- pg._set_list(
- 2,
- (
- ((1, 2), (10, 0), (12, 9), (-1, 15), (1, 2)),
- ((4, 2), (5, 2), (5, 3), (4, 2)),
- ),
- )
- self.assertEqual(
- pg.coords,
- (
- ((1.0, 2.0), (10.0, 0.0), (12.0, 9.0), (-1.0, 15.0), (1.0, 2.0)),
- ((4.0, 2.0), (5.0, 2.0), (5.0, 3.0), (4.0, 2.0)),
- ),
- "Polygon _set_list",
- )
+ # _set_list
+ pg._set_list(
+ 2,
+ (
+ ((1, 2), (10, 0), (12, 9), (-1, 15), (1, 2)),
+ ((4, 2), (5, 2), (5, 3), (4, 2)),
+ ),
+ )
+ self.assertEqual(
+ pg.coords,
+ (
+ (
+ (1.0, 2.0),
+ (10.0, 0.0),
+ (12.0, 9.0),
+ (-1.0, 15.0),
+ (1.0, 2.0),
+ ),
+ ((4.0, 2.0), (5.0, 2.0), (5.0, 3.0), (4.0, 2.0)),
+ ),
+ "Polygon _set_list",
+ )
- lsa = Polygon(*pg.coords)
- for f in geos_function_tests:
- self.assertEqual(f(lsa), f(pg), "Polygon " + f.__name__)
+ lsa = Polygon(*pg.coords)
+ for f in geos_function_tests:
+ with self.subTest(f=f):
+ self.assertEqual(f(lsa), f(pg), "Polygon " + f.__name__)
def test06_Collection(self):
"Testing Collection mutations"
@@ -201,17 +219,21 @@ class GEOSMutationTest(unittest.TestCase):
fromstr("MULTIPOINT (3 4,-1 2,5 -4,2 8)"),
)
for mp in points:
- self.assertEqual(
- mp._get_single_external(2),
- Point(5, -4),
- "Collection _get_single_external",
- )
+ with self.subTest(mp=mp):
+ self.assertEqual(
+ mp._get_single_external(2),
+ Point(5, -4),
+ "Collection _get_single_external",
+ )
- mp._set_list(3, map(Point, ((5, 5), (3, -2), (8, 1))))
- self.assertEqual(
- mp.coords, ((5.0, 5.0), (3.0, -2.0), (8.0, 1.0)), "Collection _set_list"
- )
+ mp._set_list(3, map(Point, ((5, 5), (3, -2), (8, 1))))
+ self.assertEqual(
+ mp.coords,
+ ((5.0, 5.0), (3.0, -2.0), (8.0, 1.0)),
+ "Collection _set_list",
+ )
- lsa = MultiPoint(*map(Point, ((5, 5), (3, -2), (8, 1))))
- for f in geos_function_tests:
- self.assertEqual(f(lsa), f(mp), "MultiPoint " + f.__name__)
+ lsa = MultiPoint(*map(Point, ((5, 5), (3, -2), (8, 1))))
+ for f in geos_function_tests:
+ with self.subTest(f=f):
+ self.assertEqual(f(lsa), f(mp), "MultiPoint " + f.__name__)
diff --git a/tests/gis_tests/geos_tests/test_io.py b/tests/gis_tests/geos_tests/test_io.py
index cab4b0ed5b..35cf0c11ad 100644
--- a/tests/gis_tests/geos_tests/test_io.py
+++ b/tests/gis_tests/geos_tests/test_io.py
@@ -25,7 +25,8 @@ class GEOSIOTest(SimpleTestCase):
g2 = wkt_r.read(wkt)
for geom in (g1, g2):
- self.assertEqual(ref, geom)
+ with self.subTest(geom=geom):
+ self.assertEqual(ref, geom)
# Should only accept string objects.
with self.assertRaises(TypeError):
@@ -67,7 +68,8 @@ class GEOSIOTest(SimpleTestCase):
g2 = wkb_r.read(hex_bin)
g3 = wkb_r.read(hex_str)
for geom in (g1, g2, g3):
- self.assertEqual(ref, geom)
+ with self.subTest(geom=geom):
+ self.assertEqual(ref, geom)
bad_input = (1, 5.23, None, False)
for bad_wkb in bad_input:
@@ -89,9 +91,13 @@ class GEOSIOTest(SimpleTestCase):
self.assertEqual(wkb1, wkb_w.write(g))
# Ensuring bad byteorders are not accepted.
+ msg = "Byte order parameter must be 0 (Big Endian) or 1 (Little Endian)."
for bad_byteorder in (-1, 2, 523, "foo", None):
# Equivalent of `wkb_w.byteorder = bad_byteorder`
- with self.assertRaises(ValueError):
+ with (
+ self.subTest(bad_byteorder=bad_byteorder),
+ self.assertRaisesMessage(ValueError, msg),
+ ):
wkb_w._set_byteorder(bad_byteorder)
# Setting the byteorder to 0 (for Big Endian)
@@ -114,9 +120,11 @@ class GEOSIOTest(SimpleTestCase):
wkb3d_srid = memoryview(binascii.a2b_hex(hex3d_srid))
# Ensuring bad output dimensions are not accepted
+ msg = "WKB output dimension must be 2 or 3"
for bad_outdim in (-1, 0, 1, 4, 423, "foo", None):
- with self.assertRaisesMessage(
- ValueError, "WKB output dimension must be 2 or 3"
+ with (
+ self.subTest(bad_outdim=bad_outdim),
+ self.assertRaisesMessage(ValueError, msg),
):
wkb_w.outdim = bad_outdim
@@ -221,9 +229,12 @@ class GEOSIOTest(SimpleTestCase):
wkb_w.byteorder = byteorder
for srid, hex in enumerate(hexes):
wkb_w.srid = srid
- self.assertEqual(wkb_w.write_hex(p), hex)
- self.assertEqual(
- GEOSGeometry(wkb_w.write_hex(p)), p if srid else p_no_srid
- )
- self.assertEqual(wkb_w.write(p), memoryview(binascii.a2b_hex(hex)))
- self.assertEqual(GEOSGeometry(wkb_w.write(p)), p if srid else p_no_srid)
+ with self.subTest(byteorder=byteorder, hexes=hexes):
+ self.assertEqual(wkb_w.write_hex(p), hex)
+ self.assertEqual(
+ GEOSGeometry(wkb_w.write_hex(p)), p if srid else p_no_srid
+ )
+ self.assertEqual(wkb_w.write(p), memoryview(binascii.a2b_hex(hex)))
+ self.assertEqual(
+ GEOSGeometry(wkb_w.write(p)), p if srid else p_no_srid
+ )
diff --git a/tests/gis_tests/geos_tests/test_mutable_list.py b/tests/gis_tests/geos_tests/test_mutable_list.py
index a092f603cb..1a66812d2b 100644
--- a/tests/gis_tests/geos_tests/test_mutable_list.py
+++ b/tests/gis_tests/geos_tests/test_mutable_list.py
@@ -4,9 +4,8 @@
# Modified from original contribution by Aryeh Leib Taurog, which was
# released under the New BSD license.
-import unittest
-
from django.contrib.gis.geos.mutable_list import ListMixin
+from django.test import SimpleTestCase
class UserListA(ListMixin):
@@ -54,7 +53,7 @@ def nextRange(length):
nextRange.start = 0
-class ListMixinTest(unittest.TestCase):
+class ListMixinTest(SimpleTestCase):
"""
Tests base class ListMixin by comparing a list clone which is
a ListMixin subclass with a real Python list.
@@ -79,22 +78,24 @@ class ListMixinTest(unittest.TestCase):
"Slice retrieval"
pl, ul = self.lists_of_len()
for i in self.limits_plus(1):
- self.assertEqual(pl[i:], ul[i:], "slice [%d:]" % (i))
- self.assertEqual(pl[:i], ul[:i], "slice [:%d]" % (i))
+ with self.subTest(i=i):
+ self.assertEqual(pl[i:], ul[i:], "slice [%d:]" % (i))
+ self.assertEqual(pl[:i], ul[:i], "slice [:%d]" % (i))
+
+ for j in self.limits_plus(1):
+ self.assertEqual(pl[i:j], ul[i:j], "slice [%d:%d]" % (i, j))
+ for k in self.step_range():
+ self.assertEqual(
+ pl[i:j:k], ul[i:j:k], "slice [%d:%d:%d]" % (i, j, k)
+ )
- for j in self.limits_plus(1):
- self.assertEqual(pl[i:j], ul[i:j], "slice [%d:%d]" % (i, j))
for k in self.step_range():
- self.assertEqual(
- pl[i:j:k], ul[i:j:k], "slice [%d:%d:%d]" % (i, j, k)
- )
-
- for k in self.step_range():
- self.assertEqual(pl[i::k], ul[i::k], "slice [%d::%d]" % (i, k))
- self.assertEqual(pl[:i:k], ul[:i:k], "slice [:%d:%d]" % (i, k))
+ self.assertEqual(pl[i::k], ul[i::k], "slice [%d::%d]" % (i, k))
+ self.assertEqual(pl[:i:k], ul[:i:k], "slice [:%d:%d]" % (i, k))
for k in self.step_range():
- self.assertEqual(pl[::k], ul[::k], "slice [::%d]" % (k))
+ with self.subTest(k=k):
+ self.assertEqual(pl[::k], ul[::k], "slice [::%d]" % (k))
def test02_setslice(self):
"Slice assignment"
@@ -105,120 +106,135 @@ class ListMixinTest(unittest.TestCase):
pl, ul = self.lists_of_len()
for slen in range(self.limit + 1):
ssl = nextRange(slen)
- ul[:] = ssl
- pl[:] = ssl
- self.assertEqual(pl, ul[:], "set slice [:]")
+ with self.subTest(slen=slen):
+ ul[:] = ssl
+ pl[:] = ssl
+ self.assertEqual(pl, ul[:], "set slice [:]")
- for i in self.limits_plus(1):
- ssl = nextRange(slen)
- ul[i:] = ssl
- pl[i:] = ssl
- self.assertEqual(pl, ul[:], "set slice [%d:]" % (i))
-
- ssl = nextRange(slen)
- ul[:i] = ssl
- pl[:i] = ssl
- self.assertEqual(pl, ul[:], "set slice [:%d]" % (i))
-
- for j in self.limits_plus(1):
+ for i in self.limits_plus(1):
ssl = nextRange(slen)
- ul[i:j] = ssl
- pl[i:j] = ssl
- self.assertEqual(pl, ul[:], "set slice [%d:%d]" % (i, j))
+ ul[i:] = ssl
+ pl[i:] = ssl
+ self.assertEqual(pl, ul[:], "set slice [%d:]" % (i))
+
+ ssl = nextRange(slen)
+ ul[:i] = ssl
+ pl[:i] = ssl
+ self.assertEqual(pl, ul[:], "set slice [:%d]" % (i))
+
+ for j in self.limits_plus(1):
+ ssl = nextRange(slen)
+ ul[i:j] = ssl
+ pl[i:j] = ssl
+ self.assertEqual(pl, ul[:], "set slice [%d:%d]" % (i, j))
+
+ for k in self.step_range():
+ ssl = nextRange(len(ul[i:j:k]))
+ ul[i:j:k] = ssl
+ pl[i:j:k] = ssl
+ self.assertEqual(
+ pl, ul[:], "set slice [%d:%d:%d]" % (i, j, k)
+ )
+
+ sliceLen = len(ul[i:j:k])
+ msg = (
+ f"attempt to assign sequence of size {sliceLen + 1} "
+ f"to extended slice of size {sliceLen}"
+ )
+ with self.assertRaisesMessage(ValueError, msg):
+ setfcn(ul, i, j, k, sliceLen + 1)
+ if sliceLen > 2:
+ msg = (
+ f"attempt to assign sequence of size {sliceLen - 1}"
+ f" to extended slice of size {sliceLen}"
+ )
+ with self.assertRaisesMessage(ValueError, msg):
+ setfcn(ul, i, j, k, sliceLen - 1)
for k in self.step_range():
- ssl = nextRange(len(ul[i:j:k]))
- ul[i:j:k] = ssl
- pl[i:j:k] = ssl
- self.assertEqual(pl, ul[:], "set slice [%d:%d:%d]" % (i, j, k))
+ ssl = nextRange(len(ul[i::k]))
+ ul[i::k] = ssl
+ pl[i::k] = ssl
+ self.assertEqual(pl, ul[:], "set slice [%d::%d]" % (i, k))
- sliceLen = len(ul[i:j:k])
- with self.assertRaises(ValueError):
- setfcn(ul, i, j, k, sliceLen + 1)
- if sliceLen > 2:
- with self.assertRaises(ValueError):
- setfcn(ul, i, j, k, sliceLen - 1)
+ ssl = nextRange(len(ul[:i:k]))
+ ul[:i:k] = ssl
+ pl[:i:k] = ssl
+ self.assertEqual(pl, ul[:], "set slice [:%d:%d]" % (i, k))
for k in self.step_range():
- ssl = nextRange(len(ul[i::k]))
- ul[i::k] = ssl
- pl[i::k] = ssl
- self.assertEqual(pl, ul[:], "set slice [%d::%d]" % (i, k))
-
- ssl = nextRange(len(ul[:i:k]))
- ul[:i:k] = ssl
- pl[:i:k] = ssl
- self.assertEqual(pl, ul[:], "set slice [:%d:%d]" % (i, k))
-
- for k in self.step_range():
- ssl = nextRange(len(ul[::k]))
- ul[::k] = ssl
- pl[::k] = ssl
- self.assertEqual(pl, ul[:], "set slice [::%d]" % (k))
+ ssl = nextRange(len(ul[::k]))
+ ul[::k] = ssl
+ pl[::k] = ssl
+ self.assertEqual(pl, ul[:], "set slice [::%d]" % (k))
def test03_delslice(self):
"Delete slice"
for Len in range(self.limit):
pl, ul = self.lists_of_len(Len)
- del pl[:]
- del ul[:]
- self.assertEqual(pl[:], ul[:], "del slice [:]")
- for i in range(-Len - 1, Len + 1):
- pl, ul = self.lists_of_len(Len)
- del pl[i:]
- del ul[i:]
- self.assertEqual(pl[:], ul[:], "del slice [%d:]" % (i))
- pl, ul = self.lists_of_len(Len)
- del pl[:i]
- del ul[:i]
- self.assertEqual(pl[:], ul[:], "del slice [:%d]" % (i))
- for j in range(-Len - 1, Len + 1):
+ with self.subTest(Len=Len):
+ del pl[:]
+ del ul[:]
+ self.assertEqual(pl[:], ul[:], "del slice [:]")
+ for i in range(-Len - 1, Len + 1):
pl, ul = self.lists_of_len(Len)
- del pl[i:j]
- del ul[i:j]
- self.assertEqual(pl[:], ul[:], "del slice [%d:%d]" % (i, j))
+ del pl[i:]
+ del ul[i:]
+ self.assertEqual(pl[:], ul[:], "del slice [%d:]" % (i))
+ pl, ul = self.lists_of_len(Len)
+ del pl[:i]
+ del ul[:i]
+ self.assertEqual(pl[:], ul[:], "del slice [:%d]" % (i))
+ for j in range(-Len - 1, Len + 1):
+ pl, ul = self.lists_of_len(Len)
+ del pl[i:j]
+ del ul[i:j]
+ self.assertEqual(pl[:], ul[:], "del slice [%d:%d]" % (i, j))
+ for k in [*range(-Len - 1, 0), *range(1, Len)]:
+ pl, ul = self.lists_of_len(Len)
+ del pl[i:j:k]
+ del ul[i:j:k]
+ self.assertEqual(
+ pl[:], ul[:], "del slice [%d:%d:%d]" % (i, j, k)
+ )
+
for k in [*range(-Len - 1, 0), *range(1, Len)]:
pl, ul = self.lists_of_len(Len)
- del pl[i:j:k]
- del ul[i:j:k]
- self.assertEqual(
- pl[:], ul[:], "del slice [%d:%d:%d]" % (i, j, k)
- )
+ del pl[:i:k]
+ del ul[:i:k]
+ self.assertEqual(pl[:], ul[:], "del slice [:%d:%d]" % (i, k))
+
+ pl, ul = self.lists_of_len(Len)
+ del pl[i::k]
+ del ul[i::k]
+ self.assertEqual(pl[:], ul[:], "del slice [%d::%d]" % (i, k))
for k in [*range(-Len - 1, 0), *range(1, Len)]:
pl, ul = self.lists_of_len(Len)
- del pl[:i:k]
- del ul[:i:k]
- self.assertEqual(pl[:], ul[:], "del slice [:%d:%d]" % (i, k))
-
- pl, ul = self.lists_of_len(Len)
- del pl[i::k]
- del ul[i::k]
- self.assertEqual(pl[:], ul[:], "del slice [%d::%d]" % (i, k))
-
- for k in [*range(-Len - 1, 0), *range(1, Len)]:
- pl, ul = self.lists_of_len(Len)
- del pl[::k]
- del ul[::k]
- self.assertEqual(pl[:], ul[:], "del slice [::%d]" % (k))
+ del pl[::k]
+ del ul[::k]
+ self.assertEqual(pl[:], ul[:], "del slice [::%d]" % (k))
def test04_get_set_del_single(self):
"Get/set/delete single item"
pl, ul = self.lists_of_len()
for i in self.limits_plus(0):
- self.assertEqual(pl[i], ul[i], "get single item [%d]" % i)
+ with self.subTest(i=i):
+ self.assertEqual(pl[i], ul[i], "get single item [%d]" % i)
for i in self.limits_plus(0):
pl, ul = self.lists_of_len()
pl[i] = 100
ul[i] = 100
- self.assertEqual(pl[:], ul[:], "set single item [%d]" % i)
+ with self.subTest(i=i):
+ self.assertEqual(pl[:], ul[:], "set single item [%d]" % i)
for i in self.limits_plus(0):
pl, ul = self.lists_of_len()
del pl[i]
del ul[i]
- self.assertEqual(pl[:], ul[:], "del single item [%d]" % i)
+ with self.subTest(i=i):
+ self.assertEqual(pl[:], ul[:], "del single item [%d]" % i)
def test05_out_of_range_exceptions(self):
"Out of range exceptions"
@@ -234,12 +250,14 @@ class ListMixinTest(unittest.TestCase):
pl, ul = self.lists_of_len()
for i in (-1 - self.limit, self.limit):
- with self.assertRaises(IndexError): # 'set index %d' % i)
- setfcn(ul, i)
- with self.assertRaises(IndexError): # 'get index %d' % i)
- getfcn(ul, i)
- with self.assertRaises(IndexError): # 'del index %d' % i)
- delfcn(ul, i)
+ msg = f"invalid index: {i}"
+ with self.subTest(i=i):
+ with self.assertRaisesMessage(IndexError, msg):
+ setfcn(ul, i)
+ with self.assertRaisesMessage(IndexError, msg):
+ getfcn(ul, i)
+ with self.assertRaisesMessage(IndexError, msg):
+ delfcn(ul, i)
def test06_list_methods(self):
"List methods"
@@ -260,12 +278,14 @@ class ListMixinTest(unittest.TestCase):
pl, ul = self.lists_of_len()
pl.insert(i, 50)
ul.insert(i, 50)
- self.assertEqual(pl[:], ul[:], "insert at %d" % i)
+ with self.subTest(i=i):
+ self.assertEqual(pl[:], ul[:], "insert at %d" % i)
for i in self.limits_plus(0):
pl, ul = self.lists_of_len()
- self.assertEqual(pl.pop(i), ul.pop(i), "popped value at %d" % i)
- self.assertEqual(pl[:], ul[:], "after pop at %d" % i)
+ with self.subTest(i=i):
+ self.assertEqual(pl.pop(i), ul.pop(i), "popped value at %d" % i)
+ self.assertEqual(pl[:], ul[:], "after pop at %d" % i)
pl, ul = self.lists_of_len()
self.assertEqual(pl.pop(), ul.pop(i), "popped value")
@@ -276,23 +296,26 @@ class ListMixinTest(unittest.TestCase):
def popfcn(x, i):
x.pop(i)
- with self.assertRaises(IndexError):
+ with self.assertRaisesMessage(IndexError, "invalid index: 3"):
popfcn(ul, self.limit)
- with self.assertRaises(IndexError):
+ with self.assertRaisesMessage(IndexError, "invalid index: -4"):
popfcn(ul, -1 - self.limit)
pl, ul = self.lists_of_len()
for val in range(self.limit):
- self.assertEqual(pl.index(val), ul.index(val), "index of %d" % val)
+ with self.subTest(val=val):
+ self.assertEqual(pl.index(val), ul.index(val), "index of %d" % val)
for val in self.limits_plus(2):
- self.assertEqual(pl.count(val), ul.count(val), "count %d" % val)
+ with self.subTest(val=val):
+ self.assertEqual(pl.count(val), ul.count(val), "count %d" % val)
for val in range(self.limit):
pl, ul = self.lists_of_len()
pl.remove(val)
ul.remove(val)
- self.assertEqual(pl[:], ul[:], "after remove val %d" % val)
+ with self.subTest(val=val):
+ self.assertEqual(pl[:], ul[:], "after remove val %d" % val)
def indexfcn(x, v):
return x.index(v)
@@ -300,9 +323,10 @@ class ListMixinTest(unittest.TestCase):
def removefcn(x, v):
return x.remove(v)
- with self.assertRaises(ValueError):
+ msg = "40 not found in object"
+ with self.assertRaisesMessage(ValueError, msg):
indexfcn(ul, 40)
- with self.assertRaises(ValueError):
+ with self.assertRaisesMessage(ValueError, msg):
removefcn(ul, 40)
def test07_allowed_types(self):
@@ -315,9 +339,10 @@ class ListMixinTest(unittest.TestCase):
def setfcn(x, i, v):
x[i] = v
- with self.assertRaises(TypeError):
+ msg = "Invalid type encountered in the arguments."
+ with self.assertRaisesMessage(TypeError, msg):
setfcn(ul, 2, "hello")
- with self.assertRaises(TypeError):
+ with self.assertRaisesMessage(TypeError, msg):
setfcn(ul, slice(0, 3, 2), ("hello", "goodbye"))
def test08_min_length(self):
@@ -331,17 +356,20 @@ class ListMixinTest(unittest.TestCase):
def setfcn(x, i):
x[:i] = []
+ msg = "Must have at least 3 items"
for i in range(len(ul) - ul._minlength + 1, len(ul)):
- with self.assertRaises(ValueError):
- delfcn(ul, i)
- with self.assertRaises(ValueError):
- setfcn(ul, i)
+ with self.subTest(i=i):
+ with self.assertRaisesMessage(ValueError, msg):
+ delfcn(ul, i)
+ with self.assertRaisesMessage(ValueError, msg):
+ setfcn(ul, i)
del ul[: len(ul) - ul._minlength]
ul._maxlength = 4
for i in range(0, ul._maxlength - len(ul)):
- ul.append(i)
- with self.assertRaises(ValueError):
+ with self.subTest(i=i):
+ ul.append(i)
+ with self.assertRaisesMessage(ValueError, "Cannot have more than 4 items"):
ul.append(10)
def test09_iterable_check(self):
@@ -351,22 +379,28 @@ class ListMixinTest(unittest.TestCase):
def setfcn(x, i, v):
x[i] = v
- with self.assertRaises(TypeError):
+ with self.assertRaisesMessage(
+ TypeError, "can only assign an iterable to a slice"
+ ):
setfcn(ul, slice(0, 3, 2), 2)
def test10_checkindex(self):
"Index check"
pl, ul = self.lists_of_len()
for i in self.limits_plus(0):
- if i < 0:
- self.assertEqual(
- ul._checkindex(i), i + self.limit, "_checkindex(neg index)"
- )
- else:
- self.assertEqual(ul._checkindex(i), i, "_checkindex(pos index)")
+ with self.subTest(i=i):
+ if i < 0:
+ self.assertEqual(
+ ul._checkindex(i), i + self.limit, "_checkindex(neg index)"
+ )
+ else:
+ self.assertEqual(ul._checkindex(i), i, "_checkindex(pos index)")
for i in (-self.limit - 1, self.limit):
- with self.assertRaises(IndexError):
+ with (
+ self.subTest(i=i),
+ self.assertRaisesMessage(IndexError, f"invalid index: {i}"),
+ ):
ul._checkindex(i)
def test_11_sorting(self):