structure saas with tools

This commit is contained in:
Davidson Gomes
2025-04-25 15:30:54 -03:00
commit 1aef473937
16434 changed files with 6584257 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
import numpy as np
import pytest
import shapely
from shapely import GeometryCollection, LineString, Point, wkt
from shapely.geometry import shape
@pytest.fixture()
def geometrycollection_geojson():
return {
"type": "GeometryCollection",
"geometries": [
{"type": "Point", "coordinates": (0, 3, 0)},
{"type": "LineString", "coordinates": ((2, 0), (1, 0))},
],
}
@pytest.mark.parametrize(
"geom",
[
GeometryCollection(),
GeometryCollection([]),
shape({"type": "GeometryCollection", "geometries": []}),
wkt.loads("GEOMETRYCOLLECTION EMPTY"),
],
)
def test_empty(geom):
assert geom.geom_type == "GeometryCollection"
assert geom.is_empty
assert len(geom.geoms) == 0
assert list(geom.geoms) == []
def test_empty_subgeoms():
geom = GeometryCollection([Point(), LineString()])
assert geom.geom_type == "GeometryCollection"
assert geom.is_empty
assert len(geom.geoms) == 2
parts = list(geom.geoms)
if shapely.geos_version < (3, 9, 0):
# the accessed empty 2D point has a 3D coordseq on GEOS 3.8
parts[0] = shapely.force_2d(parts[0])
assert parts == [Point(), LineString()]
def test_child_with_deleted_parent():
# test that we can remove a collection while keeping
# children around
a = LineString([(0, 0), (1, 1), (1, 2), (2, 2)])
b = LineString([(0, 0), (1, 1), (2, 1), (2, 2)])
collection = a.intersection(b)
child = collection.geoms[0]
# delete parent of child
del collection
# access geometry, this should not seg fault as 1.2.15 did
assert child.wkt is not None
def test_from_numpy_array():
geoms = np.array([Point(0, 0), LineString([(1, 1), (2, 2)])])
geom = GeometryCollection(geoms)
assert len(geom.geoms) == 2
np.testing.assert_array_equal(geoms, geom.geoms)
def test_from_geojson(geometrycollection_geojson):
geom = shape(geometrycollection_geojson)
assert geom.geom_type == "GeometryCollection"
assert len(geom.geoms) == 2
geom_types = [g.geom_type for g in geom.geoms]
assert "Point" in geom_types
assert "LineString" in geom_types
def test_geointerface(geometrycollection_geojson):
geom = shape(geometrycollection_geojson)
assert geom.__geo_interface__ == geometrycollection_geojson
def test_len_raises(geometrycollection_geojson):
geom = shape(geometrycollection_geojson)
with pytest.raises(TypeError):
len(geom)
def test_numpy_object_array():
geom = GeometryCollection([LineString([(0, 0), (1, 1)])])
ar = np.empty(1, object)
ar[:] = [geom]
assert ar[0] == geom

View File

@@ -0,0 +1,127 @@
import numpy as np
import pytest
from shapely import LineString, geos_version
from shapely.tests.common import (
line_string,
line_string_m,
line_string_z,
line_string_zm,
point,
point_m,
point_z,
point_zm,
)
class TestCoords:
"""
Shapely assumes contiguous C-order float64 data for internal ops.
Data should be converted to contiguous float64 if numpy exists.
c9a0707 broke this a little bit.
"""
def test_data_promotion(self):
coords = np.array([[12, 34], [56, 78]], dtype=np.float32)
processed_coords = np.array(LineString(coords).coords)
assert coords.tolist() == processed_coords.tolist()
def test_data_destriding(self):
coords = np.array([[12, 34], [56, 78]], dtype=np.float32)
# Easy way to introduce striding: reverse list order
processed_coords = np.array(LineString(coords[::-1]).coords)
assert coords[::-1].tolist() == processed_coords.tolist()
class TestCoordsGetItem:
def test_index_coords(self):
c = [(float(x), float(-x)) for x in range(4)]
g = LineString(c)
for i in range(-4, 4):
assert g.coords[i] == c[i]
with pytest.raises(IndexError):
g.coords[4]
with pytest.raises(IndexError):
g.coords[-5]
def test_index_coords_z(self):
c = [(float(x), float(-x), float(x * 2)) for x in range(4)]
g = LineString(c)
for i in range(-4, 4):
assert g.coords[i] == c[i]
with pytest.raises(IndexError):
g.coords[4]
with pytest.raises(IndexError):
g.coords[-5]
def test_index_coords_misc(self):
g = LineString() # empty
with pytest.raises(IndexError):
g.coords[0]
with pytest.raises(TypeError):
g.coords[0.0]
def test_slice_coords(self):
c = [(float(x), float(-x)) for x in range(4)]
g = LineString(c)
assert g.coords[1:] == c[1:]
assert g.coords[:-1] == c[:-1]
assert g.coords[::-1] == c[::-1]
assert g.coords[::2] == c[::2]
assert g.coords[:4] == c[:4]
assert g.coords[4:] == c[4:] == []
def test_slice_coords_z(self):
c = [(float(x), float(-x), float(x * 2)) for x in range(4)]
g = LineString(c)
assert g.coords[1:] == c[1:]
assert g.coords[:-1] == c[:-1]
assert g.coords[::-1] == c[::-1]
assert g.coords[::2] == c[::2]
assert g.coords[:4] == c[:4]
assert g.coords[4:] == c[4:] == []
class TestXY:
"""New geometry/coordseq method 'xy' makes numpy interop easier"""
def test_arrays(self):
x, y = LineString([(0, 0), (1, 1)]).xy
assert len(x) == 2
assert list(x) == [0.0, 1.0]
assert len(y) == 2
assert list(y) == [0.0, 1.0]
@pytest.mark.parametrize("geom", [point, point_z, line_string, line_string_z])
def test_coords_array_copy(geom):
"""Test CoordinateSequence.__array__ method."""
coord_seq = geom.coords
assert np.array(coord_seq) is not np.array(coord_seq)
assert np.array(coord_seq, copy=True) is not np.array(coord_seq, copy=True)
# Behaviour of copy=False is different between NumPy 1.x and 2.x
if int(np.version.short_version.split(".", 1)[0]) >= 2:
with pytest.raises(ValueError, match="A copy is always created"):
np.array(coord_seq, copy=False)
else:
assert np.array(coord_seq, copy=False) is np.array(coord_seq, copy=False)
@pytest.mark.skipif(geos_version < (3, 12, 0), reason="GEOS < 3.12")
def test_coords_with_m():
assert point_m.coords[:] == [(2.0, 3.0, 5.0)]
assert point_zm.coords[:] == [(2.0, 3.0, 4.0, 5.0)]
assert line_string_m.coords[:] == [
(0.0, 0.0, 1.0),
(1.0, 0.0, 2.0),
(1.0, 1.0, 3.0),
]
assert line_string_zm.coords[:] == [
(0.0, 0.0, 4.0, 1.0),
(1.0, 0.0, 4.0, 2.0),
(1.0, 1.0, 4.0, 3.0),
]

View File

@@ -0,0 +1,117 @@
from decimal import Decimal
import pytest
from shapely import (
GeometryCollection,
LinearRing,
LineString,
MultiLineString,
MultiPoint,
MultiPolygon,
Point,
Polygon,
)
items2d = [
[(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)],
[(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)],
]
items2d_mixed = [
[
(Decimal("0.0"), Decimal("0.0")),
(Decimal("70.0"), 120.0),
(140.0, Decimal("0.0")),
(0.0, 0.0),
],
[
(Decimal("60.0"), Decimal("80.0")),
(Decimal("80.0"), 80.0),
(70.0, Decimal("60.0")),
(60.0, 80.0),
],
]
items2d_decimal = [
[
(Decimal("0.0"), Decimal("0.0")),
(Decimal("70.0"), Decimal("120.0")),
(Decimal("140.0"), Decimal("0.0")),
(Decimal("0.0"), Decimal("0.0")),
],
[
(Decimal("60.0"), Decimal("80.0")),
(Decimal("80.0"), Decimal("80.0")),
(Decimal("70.0"), Decimal("60.0")),
(Decimal("60.0"), Decimal("80.0")),
],
]
items3d = [
[(0.0, 0.0, 1), (70.0, 120.0, 2), (140.0, 0.0, 3), (0.0, 0.0, 1)],
[(60.0, 80.0, 1), (80.0, 80.0, 2), (70.0, 60.0, 3), (60.0, 80.0, 1)],
]
items3d_mixed = [
[
(Decimal("0.0"), Decimal("0.0"), Decimal(1)),
(Decimal("70.0"), 120.0, Decimal(2)),
(140.0, Decimal("0.0"), 3),
(0.0, 0.0, 1),
],
[
(Decimal("60.0"), Decimal("80.0"), Decimal(1)),
(Decimal("80.0"), 80.0, 2),
(70.0, Decimal("60.0"), Decimal(3)),
(60.0, 80.0, 1),
],
]
items3d_decimal = [
[
(Decimal("0.0"), Decimal("0.0"), Decimal(1)),
(Decimal("70.0"), Decimal("120.0"), Decimal(2)),
(Decimal("140.0"), Decimal("0.0"), Decimal(3)),
(Decimal("0.0"), Decimal("0.0"), Decimal(1)),
],
[
(Decimal("60.0"), Decimal("80.0"), Decimal(1)),
(Decimal("80.0"), Decimal("80.0"), Decimal(2)),
(Decimal("70.0"), Decimal("60.0"), Decimal(3)),
(Decimal("60.0"), Decimal("80.0"), Decimal(1)),
],
]
all_geoms = [
[
Point(items[0][0]),
Point(*items[0][0]),
MultiPoint(items[0]),
LinearRing(items[0]),
LineString(items[0]),
MultiLineString(items),
Polygon(items[0]),
MultiPolygon(
[
Polygon(items[1]),
Polygon(items[0], holes=items[1:]),
]
),
GeometryCollection([Point(items[0][0]), Polygon(items[0])]),
]
for items in [
items2d,
items2d_mixed,
items2d_decimal,
items3d,
items3d_mixed,
items3d_decimal,
]
]
@pytest.mark.parametrize("geoms", list(zip(*all_geoms)))
def test_decimal(geoms):
assert geoms[0] == geoms[1] == geoms[2]
assert geoms[3] == geoms[4] == geoms[5]

View File

@@ -0,0 +1,98 @@
import math
import numpy as np
import pytest
from shapely import (
GeometryCollection,
LinearRing,
LineString,
MultiLineString,
MultiPoint,
MultiPolygon,
Point,
Polygon,
)
from shapely.geometry import mapping, shape
from shapely.geometry.base import BaseGeometry, EmptyGeometry
def empty_generator():
return iter([])
class TestEmptiness:
def test_empty_class(self):
with pytest.warns(FutureWarning):
g = EmptyGeometry()
assert g.is_empty
def test_empty_base(self):
with pytest.warns(FutureWarning):
g = BaseGeometry()
assert g.is_empty
def test_empty_point(self):
assert Point().is_empty
def test_empty_multipoint(self):
assert MultiPoint().is_empty
def test_empty_geometry_collection(self):
assert GeometryCollection().is_empty
def test_empty_linestring(self):
assert LineString().is_empty
assert LineString(None).is_empty
assert LineString([]).is_empty
assert LineString(empty_generator()).is_empty
def test_empty_multilinestring(self):
assert MultiLineString([]).is_empty
def test_empty_polygon(self):
assert Polygon().is_empty
assert Polygon(None).is_empty
assert Polygon([]).is_empty
assert Polygon(empty_generator()).is_empty
def test_empty_multipolygon(self):
assert MultiPolygon([]).is_empty
def test_empty_linear_ring(self):
assert LinearRing().is_empty
assert LinearRing(None).is_empty
assert LinearRing([]).is_empty
assert LinearRing(empty_generator()).is_empty
def test_numpy_object_array():
geoms = [Point(), GeometryCollection()]
arr = np.empty(2, object)
arr[:] = geoms
def test_shape_empty():
empty_mp = MultiPolygon()
empty_json = mapping(empty_mp)
empty_shape = shape(empty_json)
assert empty_shape.is_empty
@pytest.mark.parametrize(
"geom",
[
Point(),
LineString(),
Polygon(),
MultiPoint(),
MultiLineString(),
MultiPolygon(),
GeometryCollection(),
LinearRing(),
],
)
def test_empty_geometry_bounds(geom):
"""The bounds of an empty geometry is a tuple of NaNs"""
assert len(geom.bounds) == 4
assert all(math.isnan(v) for v in geom.bounds)

View File

@@ -0,0 +1,284 @@
import numpy as np
import pytest
import shapely
from shapely import LinearRing, LineString, MultiLineString, Point, Polygon
from shapely.tests.common import all_types, all_types_z, empty_point, ignore_invalid
all_non_empty_types = np.array(all_types + all_types_z)[
~shapely.is_empty(all_types + all_types_z)
]
# TODO add all_types_m and all_types_zm once tranform supports M coordinates
@pytest.mark.parametrize("geom", all_types + all_types_z)
def test_equality(geom):
assert geom == geom # noqa: PLR0124
transformed = shapely.transform(geom, lambda x: x, include_z=True)
if (
shapely.geos_version < (3, 9, 0)
and isinstance(geom, Point)
and geom.is_empty
and not geom.has_z
):
# the transformed empty 2D point has become 3D on GEOS 3.8
transformed = shapely.force_2d(geom)
assert geom == transformed
assert not (geom != transformed)
@pytest.mark.parametrize(
"left, right",
# automated test cases with transformed coordinate values
[(geom, shapely.transform(geom, lambda x: x + 1)) for geom in all_non_empty_types]
+ [
# (slightly) different coordinate values
(LineString([(0, 0), (1, 1)]), LineString([(0, 0), (1, 2)])),
(LineString([(0, 0), (1, 1)]), LineString([(0, 0), (1, 1 + 1e-12)])),
# different coordinate order
(LineString([(0, 0), (1, 1)]), LineString([(1, 1), (0, 0)])),
# different number of coordinates (but spatially equal)
(LineString([(0, 0), (1, 1)]), LineString([(0, 0), (1, 1), (1, 1)])),
(LineString([(0, 0), (1, 1)]), LineString([(0, 0), (0.5, 0.5), (1, 1)])),
# different order of sub-geometries
(
MultiLineString([[(1, 1), (2, 2)], [(2, 2), (3, 3)]]),
MultiLineString([[(2, 2), (3, 3)], [(1, 1), (2, 2)]]),
),
# M coordinates (don't work yet with automated cases)
pytest.param(
shapely.from_wkt("POINT M (0 0 0)"),
shapely.from_wkt("POINT M (0 0 1)"),
marks=pytest.mark.skipif(
shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
),
),
pytest.param(
shapely.from_wkt("POINT ZM (0 0 0 0)"),
shapely.from_wkt("POINT ZM (0 0 0 1)"),
marks=pytest.mark.skipif(
shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
),
),
],
)
def test_equality_false(left, right):
assert left != right
assert not (left == right)
with ignore_invalid():
cases1 = [
(LineString([(0, 1), (2, np.nan)]), LineString([(0, 1), (2, np.nan)])),
(
LineString([(0, 1), (np.nan, np.nan)]),
LineString([(0, 1), (np.nan, np.nan)]),
),
(LineString([(np.nan, 1), (2, 3)]), LineString([(np.nan, 1), (2, 3)])),
(LineString([(0, np.nan), (2, 3)]), LineString([(0, np.nan), (2, 3)])),
(
LineString([(np.nan, np.nan), (np.nan, np.nan)]),
LineString([(np.nan, np.nan), (np.nan, np.nan)]),
),
# NaN as explicit Z coordinate
# TODO: if first z is NaN -> considered as 2D -> tested below explicitly
# (
# LineString([(0, 1, np.nan), (2, 3, np.nan)]),
# LineString([(0, 1, np.nan), (2, 3, np.nan)]),
# ),
(
LineString([(0, 1, 2), (2, 3, np.nan)]),
LineString([(0, 1, 2), (2, 3, np.nan)]),
),
# (
# LineString([(0, 1, np.nan), (2, 3, 4)]),
# LineString([(0, 1, np.nan), (2, 3, 4)]),
# ),
]
@pytest.mark.parametrize("left, right", cases1)
def test_equality_with_nan(left, right):
assert left == right
assert not (left != right)
with ignore_invalid():
cases2 = [
(
LineString([(0, 1, np.nan), (2, 3, np.nan)]),
LineString([(0, 1, np.nan), (2, 3, np.nan)]),
),
(
LineString([(0, 1, np.nan), (2, 3, 4)]),
LineString([(0, 1, np.nan), (2, 3, 4)]),
),
]
@pytest.mark.parametrize("left, right", cases2)
def test_equality_with_nan_z(left, right):
assert left == right
assert not (left != right)
with ignore_invalid():
cases3 = [
(LineString([(0, np.nan), (2, 3)]), LineString([(0, 1), (2, 3)])),
(LineString([(0, 1), (2, np.nan)]), LineString([(0, 1), (2, 3)])),
(LineString([(0, 1, np.nan), (2, 3, 4)]), LineString([(0, 1, 2), (2, 3, 4)])),
(LineString([(0, 1, 2), (2, 3, np.nan)]), LineString([(0, 1, 2), (2, 3, 4)])),
pytest.param(
shapely.from_wkt("POINT M (0 0 0)"),
shapely.from_wkt("POINT M (0 0 NaN)"),
marks=pytest.mark.skipif(
shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
),
),
pytest.param(
shapely.from_wkt("POINT ZM (0 0 0 0)"),
shapely.from_wkt("POINT ZM (0 0 0 NaN)"),
marks=pytest.mark.skipif(
shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
),
),
]
@pytest.mark.parametrize("left, right", cases3)
def test_equality_with_nan_false(left, right):
assert left != right
def test_equality_with_nan_z_false():
with ignore_invalid():
left = LineString([(0, 1, np.nan), (2, 3, np.nan)])
right = LineString([(0, 1, np.nan), (2, 3, 4)])
if shapely.geos_version < (3, 10, 0):
# GEOS <= 3.9 fill the NaN with 0, so the z dimension is different
assert left != right
elif shapely.geos_version < (3, 12, 0):
# GEOS 3.10-3.11 ignore NaN for Z also when explicitly created with 3D
# and so the geometries are considered as 2D (and thus z dimension is ignored)
assert left == right
else:
assert left != right
def test_equality_z():
# different dimensionality
geom1 = Point(0, 1)
geom2 = Point(0, 1, 0)
assert geom1 != geom2
# different dimensionality with NaN z
geom2 = Point(0, 1, np.nan)
if shapely.geos_version < (3, 12, 0):
# GEOS 3.10-3.11 ignore NaN for Z also when explicitly created with 3D
# and so the geometries are considered as 2D (and thus z dimension is ignored)
assert geom1 == geom2
else:
assert geom1 != geom2
def test_equality_exact_type():
# geometries with different type but same coord seq are not equal
geom1 = LineString([(0, 0), (1, 1), (0, 1), (0, 0)])
geom2 = LinearRing([(0, 0), (1, 1), (0, 1), (0, 0)])
geom3 = Polygon([(0, 0), (1, 1), (0, 1), (0, 0)])
assert geom1 != geom2
assert geom1 != geom3
assert geom2 != geom3
# empty with different type
geom1 = shapely.from_wkt("POINT EMPTY")
geom2 = shapely.from_wkt("LINESTRING EMPTY")
assert geom1 != geom2
def test_equality_polygon():
# different exterior rings
geom1 = shapely.from_wkt("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
geom2 = shapely.from_wkt("POLYGON ((0 0, 10 0, 10 10, 0 15, 0 0))")
assert geom1 != geom2
# different number of holes
geom1 = shapely.from_wkt(
"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 2 1, 2 2, 1 1))"
)
geom2 = shapely.from_wkt(
"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 2 1, 2 2, 1 1), "
"(3 3, 4 3, 4 4, 3 3))"
)
assert geom1 != geom2
# different order of holes
geom1 = shapely.from_wkt(
"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (3 3, 4 3, 4 4, 3 3), "
"(1 1, 2 1, 2 2, 1 1))"
)
geom2 = shapely.from_wkt(
"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 2 1, 2 2, 1 1), "
"(3 3, 4 3, 4 4, 3 3))"
)
assert geom1 != geom2
@pytest.mark.parametrize("geom", all_types)
def test_comparison_notimplemented(geom):
# comparing to a non-geometry class should return NotImplemented in __eq__
# to ensure proper delegation to other (eg to ensure comparison of scalar
# with array works)
# https://github.com/shapely/shapely/issues/1056
assert geom.__eq__(1) is NotImplemented
# with array
arr = np.array([geom, geom], dtype=object)
result = arr == geom
assert isinstance(result, np.ndarray)
assert result.all()
result = geom == arr
assert isinstance(result, np.ndarray)
assert result.all()
result = arr != geom
assert isinstance(result, np.ndarray)
assert not result.any()
result = geom != arr
assert isinstance(result, np.ndarray)
assert not result.any()
def test_comparison_not_supported():
geom1 = Point(1, 1)
geom2 = Point(2, 2)
with pytest.raises(TypeError, match="not supported between instances"):
assert geom1 > geom2
with pytest.raises(TypeError, match="not supported between instances"):
assert geom1 < geom2
with pytest.raises(TypeError, match="not supported between instances"):
assert geom1 >= geom2
with pytest.raises(TypeError, match="not supported between instances"):
assert geom1 <= geom2
@pytest.mark.parametrize(
"geom", all_types + (shapely.points(np.nan, np.nan), empty_point)
)
def test_hash_same_equal(geom):
hash1 = hash(geom)
hash2 = hash(shapely.transform(geom, lambda x: x))
assert hash1 == hash2, geom
@pytest.mark.parametrize("geom", all_non_empty_types)
def test_hash_same_not_equal(geom):
assert hash(geom) != hash(shapely.transform(geom, lambda x: x + 1))

View File

@@ -0,0 +1,118 @@
import pytest
from shapely import Point, Polygon, geos_version
def test_format_invalid():
# check invalid spec formats
pt = Point(1, 2)
test_list = [
("5G", ValueError, "invalid format specifier"),
(".f", ValueError, "invalid format specifier"),
("0.2e", ValueError, "invalid format specifier"),
(".1x", ValueError, "hex representation does not specify precision"),
]
for format_spec, err, match in test_list:
with pytest.raises(err, match=match):
format(pt, format_spec)
def get_tst_format_point_params():
xy1 = (0.12345678901234567, 1.2345678901234567e10)
xy2 = (-169.910918, -18.997564)
xyz3 = (630084, 4833438, 76)
test_list = [
(".0f", xy1, "POINT (0 12345678901)", True),
(".1f", xy1, "POINT (0.1 12345678901.2)", True),
("0.2f", xy2, "POINT (-169.91 -19.00)", True),
(".3F", (float("inf"), -float("inf")), "POINT (INF -INF)", True),
]
if geos_version < (3, 10, 0):
# 'g' format varies depending on GEOS version
test_list += [
(".1g", xy1, "POINT (0.1 1e+10)", True),
(".6G", xy1, "POINT (0.123457 1.23457E+10)", True),
("0.12g", xy1, "POINT (0.123456789012 12345678901.2)", True),
("0.4g", xy2, "POINT (-169.9 -19)", True),
]
else:
test_list += [
(".1g", xy1, "POINT (0.1 12345678901.2)", False),
(".6G", xy1, "POINT (0.123457 12345678901.234568)", False),
("0.12g", xy1, "POINT (0.123456789012 12345678901.234568)", False),
("g", xy2, "POINT (-169.910918 -18.997564)", False),
("0.2g", xy2, "POINT (-169.91 -19)", False),
]
# without precisions test GEOS rounding_precision=-1; different than Python
test_list += [
("f", (1, 2), f"POINT ({1:.16f} {2:.16f})", False),
("F", xyz3, "POINT Z ({:.16f} {:.16f} {:.16f})".format(*xyz3), False),
("g", xyz3, "POINT Z (630084 4833438 76)", False),
]
return test_list
@pytest.mark.parametrize(
"format_spec, coords, expt_wkt, same_python_float", get_tst_format_point_params()
)
def test_format_point(format_spec, coords, expt_wkt, same_python_float):
pt = Point(*coords)
# basic checks
assert f"{pt}" == pt.wkt
assert format(pt, "") == pt.wkt
assert format(pt, "x") == pt.wkb_hex.lower()
assert format(pt, "X") == pt.wkb_hex
# check formatted WKT to expected
assert format(pt, format_spec) == expt_wkt, format_spec
# check Python's format consistency
text_coords = expt_wkt[expt_wkt.index("(") + 1 : expt_wkt.index(")")]
is_same = []
for coord, expt_coord in zip(coords, text_coords.split()):
py_fmt_float = format(float(coord), format_spec)
if same_python_float:
assert py_fmt_float == expt_coord, format_spec
else:
is_same.append(py_fmt_float == expt_coord)
if not same_python_float:
assert not all(is_same), f"{format_spec!r} with {expt_wkt}"
def test_format_polygon():
# check basic cases
poly = Point(0, 0).buffer(10, quad_segs=2)
assert f"{poly}" == poly.wkt
assert format(poly, "") == poly.wkt
assert format(poly, "x") == poly.wkb_hex.lower()
assert format(poly, "X") == poly.wkb_hex
# Use f-strings with extra characters and rounding precision
if geos_version < (3, 13, 0):
assert f"<{poly:.2f}>" == (
"<POLYGON ((10.00 0.00, 7.07 -7.07, 0.00 -10.00, -7.07 -7.07, "
"-10.00 -0.00, -7.07 7.07, -0.00 10.00, 7.07 7.07, 10.00 0.00))>"
)
else:
assert f"<{poly:.2f}>" == (
"<POLYGON ((10.00 0.00, 7.07 -7.07, 0.00 -10.00, -7.07 -7.07, "
"-10.00 0.00, -7.07 7.07, 0.00 10.00, 7.07 7.07, 10.00 0.00))>"
)
# 'g' format varies depending on GEOS version
if geos_version < (3, 10, 0):
assert f"{poly:.2G}" == (
"POLYGON ((10 0, 7.1 -7.1, 1.6E-14 -10, -7.1 -7.1, "
"-10 -3.2E-14, -7.1 7.1, -4.6E-14 10, 7.1 7.1, 10 0))"
)
else:
assert f"{poly:.2G}" == (
"POLYGON ((10 0, 7.07 -7.07, 0 -10, -7.07 -7.07, "
"-10 0, -7.07 7.07, 0 10, 7.07 7.07, 10 0))"
)
# check empty
empty = Polygon()
assert f"{empty}" == "POLYGON EMPTY"
assert format(empty, "") == empty.wkt
assert format(empty, ".2G") == empty.wkt
assert format(empty, "x") == empty.wkb_hex.lower()
assert format(empty, "X") == empty.wkb_hex

View File

@@ -0,0 +1,369 @@
import platform
import weakref
import numpy as np
import pytest
import shapely
from shapely import (
GeometryCollection,
LinearRing,
LineString,
MultiLineString,
MultiPoint,
MultiPolygon,
Point,
Polygon,
)
from shapely.errors import ShapelyDeprecationWarning
from shapely.testing import assert_geometries_equal
def test_polygon():
assert bool(Polygon()) is False
def test_linestring():
assert bool(LineString()) is False
def test_point():
assert bool(Point()) is False
def test_geometry_collection():
assert bool(GeometryCollection()) is False
geometries_all_types = [
Point(1, 1),
LinearRing([(0, 0), (1, 1), (0, 1), (0, 0)]),
LineString([(0, 0), (1, 1), (0, 1), (0, 0)]),
Polygon([(0, 0), (1, 1), (0, 1), (0, 0)]),
MultiPoint([(1, 1)]),
MultiLineString([[(0, 0), (1, 1), (0, 1), (0, 0)]]),
MultiPolygon([Polygon([(0, 0), (1, 1), (0, 1), (0, 0)])]),
GeometryCollection([Point(1, 1)]),
]
@pytest.mark.skipif(
platform.python_implementation() == "PyPy",
reason="Setting custom attributes doesn't fail on PyPy",
)
@pytest.mark.parametrize("geom", geometries_all_types)
def test_setattr_disallowed(geom):
with pytest.raises(AttributeError):
geom.name = "test"
@pytest.mark.parametrize("geom", geometries_all_types)
def test_weakrefable(geom):
_ = weakref.ref(geom)
def test_base_class_not_callable():
with pytest.raises(TypeError):
shapely.Geometry("POINT (1 1)")
def test_GeometryType_deprecated():
geom = Point(1, 1)
with pytest.warns(ShapelyDeprecationWarning):
geom_type = geom.geometryType()
assert geom_type == geom.geom_type
def test_type_deprecated():
geom = Point(1, 1)
with pytest.warns(ShapelyDeprecationWarning):
geom_type = geom.type
assert geom_type == geom.geom_type
@pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10")
def test_segmentize():
line = LineString([(0, 0), (0, 10)])
result = line.segmentize(max_segment_length=5)
assert result.equals(LineString([(0, 0), (0, 5), (0, 10)]))
def test_reverse():
coords = [(0, 0), (1, 2)]
line = LineString(coords)
result = line.reverse()
assert result.coords[:] == coords[::-1]
@pytest.mark.parametrize(
"op", ["union", "intersection", "difference", "symmetric_difference"]
)
@pytest.mark.parametrize("grid_size", [0, 1, 2])
def test_binary_op_grid_size(op, grid_size):
geom1 = shapely.box(0, 0, 2.5, 2.5)
geom2 = shapely.box(2, 2, 3, 3)
result = getattr(geom1, op)(geom2, grid_size=grid_size)
expected = getattr(shapely, op)(geom1, geom2, grid_size=grid_size)
assert result == expected
@pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10")
def test_dwithin():
point = Point(1, 1)
line = LineString([(0, 0), (0, 10)])
assert point.dwithin(line, 0.5) is False
assert point.dwithin(line, 1.5) is True
def test_contains_properly():
polygon = Polygon([(0, 0), (10, 10), (10, -10)])
line = LineString([(0, 0), (10, 0)])
assert polygon.contains_properly(line) is False
assert polygon.contains(line) is True
@pytest.mark.parametrize(
"op", ["convex_hull", "envelope", "oriented_envelope", "minimum_rotated_rectangle"]
)
def test_constructive_properties(op):
geom = LineString([(0, 0), (0, 10), (10, 10)])
result = getattr(geom, op)
expected = getattr(shapely, op)(geom)
assert result == expected
@pytest.mark.parametrize(
"op",
[
"crosses",
"contains",
"contains_properly",
"covered_by",
"covers",
"disjoint",
"equals",
"intersects",
"overlaps",
"touches",
"within",
],
)
def test_array_argument_binary_predicates(op):
polygon = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
points = shapely.points([(0, 0), (0.5, 0.5), (1, 1)])
result = getattr(polygon, op)(points)
assert isinstance(result, np.ndarray)
expected = np.array([getattr(polygon, op)(p) for p in points], dtype=bool)
np.testing.assert_array_equal(result, expected)
# check scalar
result = getattr(polygon, op)(points[0])
assert type(result) is bool
@pytest.mark.parametrize(
"op, kwargs",
[
pytest.param(
"dwithin",
dict(distance=0.5),
marks=pytest.mark.skipif(
shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10"
),
),
("equals_exact", dict(tolerance=0.01)),
("relate_pattern", dict(pattern="T*F**F***")),
],
)
def test_array_argument_binary_predicates2(op, kwargs):
polygon = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
points = shapely.points([(0, 0), (0.5, 0.5), (1, 1)])
result = getattr(polygon, op)(points, **kwargs)
assert isinstance(result, np.ndarray)
expected = np.array([getattr(polygon, op)(p, **kwargs) for p in points], dtype=bool)
np.testing.assert_array_equal(result, expected)
# check scalar
result = getattr(polygon, op)(points[0], **kwargs)
assert type(result) is bool
@pytest.mark.parametrize(
"op",
[
"difference",
"intersection",
"symmetric_difference",
"union",
],
)
def test_array_argument_binary_geo(op):
box = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
polygons = shapely.buffer(shapely.points([(0, 0), (0.5, 0.5), (1, 1)]), 0.5)
result = getattr(box, op)(polygons)
assert isinstance(result, np.ndarray)
expected = np.array([getattr(box, op)(g) for g in polygons], dtype=object)
assert_geometries_equal(result, expected)
# check scalar
result = getattr(box, op)(polygons[0])
assert isinstance(result, (Polygon, MultiPolygon))
@pytest.mark.parametrize("op", ["distance", "hausdorff_distance"])
def test_array_argument_float(op):
polygon = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
points = shapely.points([(0, 0), (0.5, 0.5), (1, 1)])
result = getattr(polygon, op)(points)
assert isinstance(result, np.ndarray)
expected = np.array([getattr(polygon, op)(p) for p in points], dtype="float64")
np.testing.assert_array_equal(result, expected)
# check scalar
result = getattr(polygon, op)(points[0])
assert type(result) is float
@pytest.mark.parametrize("op", ["line_interpolate_point", "interpolate"])
def test_array_argument_linear_point(op):
line = LineString([(0, 0), (0, 1), (1, 1)])
distances = np.array([0, 0.5, 1])
result = getattr(line, op)(distances)
assert isinstance(result, np.ndarray)
expected = np.array(
[line.line_interpolate_point(d) for d in distances], dtype=object
)
assert_geometries_equal(result, expected)
# check scalar
result = getattr(line, op)(distances[0])
assert isinstance(result, Point)
@pytest.mark.parametrize("op", ["line_locate_point", "project"])
def test_array_argument_linear_float(op):
line = LineString([(0, 0), (0, 1), (1, 1)])
points = shapely.points([(0, 0), (0.5, 0.5), (1, 1)])
result = getattr(line, op)(points)
assert isinstance(result, np.ndarray)
expected = np.array([line.line_locate_point(p) for p in points], dtype="float64")
np.testing.assert_array_equal(result, expected)
# check scalar
result = getattr(line, op)(points[0])
assert type(result) is float
def test_array_argument_buffer():
point = Point(1, 1)
distances = np.array([0, 0.5, 1])
result = point.buffer(distances)
assert isinstance(result, np.ndarray)
expected = np.array([point.buffer(d) for d in distances], dtype=object)
assert_geometries_equal(result, expected)
# check scalar
result = point.buffer(distances[0])
assert isinstance(result, Polygon)
def test_buffer_deprecate_positional():
point = Point(1, 1)
with pytest.deprecated_call(
match="positional argument `cap_style` for `buffer` is deprecated"
):
point.buffer(1.0, 8, "round")
with pytest.deprecated_call(
match="positional arguments `cap_style` and `join_style` "
"for `buffer` are deprecated"
):
point.buffer(1.0, 8, "round", "round")
with pytest.deprecated_call():
point.buffer(1.0, 8, "round", "round", 5.0)
with pytest.deprecated_call():
point.buffer(1.0, 8, "round", "round", 5.0, False)
def test_simplify_deprecate_positional():
linestring = LineString([(0, 0), (1, 1)])
with pytest.deprecated_call(
match="positional argument `preserve_topology` for `simplify` is deprecated"
):
linestring.simplify(1.0, True)
def test_difference_deprecate_positional():
point = Point(1, 1)
with pytest.deprecated_call(
match="positional argument `grid_size` for `difference` is deprecated"
):
point.difference(point, None)
def test_intersection_deprecate_positional():
point = Point(1, 1)
with pytest.deprecated_call(
match="positional argument `grid_size` for `intersection` is deprecated"
):
point.intersection(point, None)
def test_symmetric_difference_deprecate_positional():
point = Point(1, 1)
with pytest.deprecated_call(
match="positional argument `grid_size` for `symmetric_difference` is deprecated"
):
point.symmetric_difference(point, None)
def test_union_deprecate_positional():
point = Point(1, 1)
with pytest.deprecated_call(
match="positional argument `grid_size` for `union` is deprecated"
):
point.union(point, None)
def test_line_locate_point_deprecate_positional():
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
with pytest.deprecated_call(
match="positional argument `normalized` for `line_locate_point` is deprecated"
):
line_string.line_locate_point(Point(1, 1), False)
def test_project_deprecate_positional():
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
with pytest.deprecated_call(
match="positional argument `normalized` for `project` is deprecated"
):
line_string.project(Point(1, 1), False)
def test_line_interpolate_point_deprecate_positional():
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
with pytest.deprecated_call(
match="positional argument `normalized` for `line_interpolate_point` "
"is deprecated"
):
line_string.line_interpolate_point(0, False)
def test_interpolate_deprecate_positional():
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
with pytest.deprecated_call(
match="positional argument `normalized` for `interpolate` is deprecated"
):
line_string.interpolate(0, False)

View File

@@ -0,0 +1,28 @@
import pytest
import shapely
from shapely.affinity import translate
from shapely.geometry import GeometryCollection, LineString, MultiPoint, Point
@pytest.mark.parametrize(
"geom",
[
Point(1, 2),
MultiPoint([(1, 2), (3, 4)]),
LineString([(1, 2), (3, 4)]),
Point(0, 0).buffer(1.0),
GeometryCollection([Point(1, 2), LineString([(1, 2), (3, 4)])]),
],
ids=[
"Point",
"MultiPoint",
"LineString",
"Polygon",
"GeometryCollection",
],
)
def test_hash(geom):
h1 = hash(geom)
assert h1 == hash(shapely.from_wkb(geom.wkb))
assert h1 != hash(translate(geom, 1.0, 2.0))

View File

@@ -0,0 +1,232 @@
import numpy as np
import pytest
import shapely
from shapely import LinearRing, LineString, Point
from shapely.coords import CoordinateSequence
def test_from_coordinate_sequence():
# From coordinate tuples
line = LineString([(1.0, 2.0), (3.0, 4.0)])
assert len(line.coords) == 2
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
line = LineString([(1.0, 2.0), (3.0, 4.0)])
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
def test_from_coordinate_sequence_z():
line = LineString([(1.0, 2.0, 3.0), (3.0, 4.0, 5.0)])
assert line.has_z
assert line.coords[:] == [(1.0, 2.0, 3.0), (3.0, 4.0, 5.0)]
def test_from_points():
# From Points
line = LineString([Point(1.0, 2.0), Point(3.0, 4.0)])
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
line = LineString([Point(1.0, 2.0), Point(3.0, 4.0)])
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
def test_from_mix():
# From mix of tuples and Points
line = LineString([Point(1.0, 2.0), (2.0, 3.0), Point(3.0, 4.0)])
assert line.coords[:] == [(1.0, 2.0), (2.0, 3.0), (3.0, 4.0)]
def test_from_linestring():
# From another linestring
line = LineString([(1.0, 2.0), (3.0, 4.0)])
copy = LineString(line)
assert copy.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
assert copy.geom_type == "LineString"
def test_from_linearring():
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
ring = LinearRing(coords)
copy = LineString(ring)
assert copy.coords[:] == coords
assert copy.geom_type == "LineString"
def test_from_linestring_z():
coords = [(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)]
line = LineString(coords)
copy = LineString(line)
assert copy.coords[:] == coords
assert copy.geom_type == "LineString"
def test_from_generator():
gen = (coord for coord in [(1.0, 2.0), (3.0, 4.0)])
line = LineString(gen)
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
def test_from_empty():
line = LineString()
assert line.is_empty
assert isinstance(line.coords, CoordinateSequence)
assert line.coords[:] == []
line = LineString([])
assert line.is_empty
assert isinstance(line.coords, CoordinateSequence)
assert line.coords[:] == []
def test_from_numpy():
# Construct from a numpy array
line = LineString(np.array([[1.0, 2.0], [3.0, 4.0]]))
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
def test_numpy_empty_linestring_coords():
# Check empty
line = LineString([])
la = np.asarray(line.coords)
assert la.shape == (0, 2)
def test_numpy_object_array():
geom = LineString([(0.0, 0.0), (0.0, 1.0)])
ar = np.empty(1, object)
ar[:] = [geom]
assert ar[0] == geom
@pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested sequences:")
def test_from_invalid_dim():
# TODO(shapely-2.0) better error message?
# pytest.raises(
# ValueError, match="at least 2 coordinate tuples|at least 2 coordinates"
# ):
with pytest.raises(shapely.GEOSException):
LineString([(1, 2)])
# exact error depends on numpy version
with pytest.raises((ValueError, TypeError)):
LineString([(1, 2, 3), (4, 5)])
with pytest.raises((ValueError, TypeError)):
LineString([(1, 2), (3, 4, 5)])
msg = r"The ordinate \(last\) dimension should be 2 or 3, got {}"
with pytest.raises(ValueError, match=msg.format(4)):
LineString([(1, 2, 3, 4), (4, 5, 6, 7)])
with pytest.raises(ValueError, match=msg.format(1)):
LineString([(1,), (4,)])
def test_from_single_coordinate():
"""Test for issue #486"""
coords = [[-122.185933073564, 37.3629353839073]]
with pytest.raises(shapely.GEOSException):
ls = LineString(coords)
ls.geom_type # caused segfault before fix
class TestLineString:
def test_linestring(self):
# From coordinate tuples
line = LineString([(1.0, 2.0), (3.0, 4.0)])
assert len(line.coords) == 2
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
# Bounds
assert line.bounds == (1.0, 2.0, 3.0, 4.0)
# Coordinate access
assert tuple(line.coords) == ((1.0, 2.0), (3.0, 4.0))
assert line.coords[0] == (1.0, 2.0)
assert line.coords[1] == (3.0, 4.0)
with pytest.raises(IndexError):
line.coords[2] # index out of range
# Geo interface
assert line.__geo_interface__ == {
"type": "LineString",
"coordinates": ((1.0, 2.0), (3.0, 4.0)),
}
def test_linestring_empty(self):
# Test Non-operability of Null geometry
l_null = LineString()
assert l_null.wkt == "LINESTRING EMPTY"
assert l_null.length == 0.0
def test_equals_argument_order(self):
"""
Test equals predicate functions correctly regardless of the order
of the inputs. See issue #317.
"""
coords = ((0, 0), (1, 0), (1, 1), (0, 0))
ls = LineString(coords)
lr = LinearRing(coords)
assert ls.__eq__(lr) is False # previously incorrectly returned True
assert lr.__eq__(ls) is False
assert (ls == lr) is False
assert (lr == ls) is False
ls_clone = LineString(coords)
lr_clone = LinearRing(coords)
assert ls.__eq__(ls_clone) is True
assert lr.__eq__(lr_clone) is True
assert (ls == ls_clone) is True
assert (lr == lr_clone) is True
def test_numpy_linestring_coords(self):
from numpy.testing import assert_array_equal
line = LineString([(1.0, 2.0), (3.0, 4.0)])
expected = np.array([[1.0, 2.0], [3.0, 4.0]])
# Coordinate sequences can be adapted as well
la = np.asarray(line.coords)
assert_array_equal(la, expected)
def test_linestring_immutable():
line = LineString([(1.0, 2.0), (3.0, 4.0)])
with pytest.raises(AttributeError):
line.coords = [(-1.0, -1.0), (1.0, 1.0)]
with pytest.raises(TypeError):
line.coords[0] = (-1.0, -1.0)
def test_linestring_array_coercion():
# don't convert to array of coordinates, keep objects
line = LineString([(1.0, 2.0), (3.0, 4.0)])
arr = np.array(line)
assert arr.ndim == 0
assert arr.size == 1
assert arr.dtype == np.dtype("object")
assert arr.item() == line
def test_offset_curve_deprecate_positional():
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
with pytest.deprecated_call(
match="positional argument `quad_segs` for `offset_curve` is deprecated"
):
line_string.offset_curve(1.0, 8)
with pytest.deprecated_call(
match="positional arguments `quad_segs` and `join_style` "
"for `offset_curve` are deprecated"
):
line_string.offset_curve(1.0, 8, "round")
with pytest.deprecated_call(
match="positional arguments `quad_segs`, `join_style`, and `mitre_limit` "
"for `offset_curve` are deprecated"
):
line_string.offset_curve(1.0, 8, "round", 5.0)

View File

@@ -0,0 +1,11 @@
import numpy as np
test_int_types = [int, np.int16, np.int32, np.int64]
class MultiGeometryTestCase:
def subgeom_access_test(self, cls, geoms):
geom = cls(geoms)
for t in test_int_types:
for i, g in enumerate(geoms):
assert geom.geoms[t(i)] == g

View File

@@ -0,0 +1,77 @@
import numpy as np
import pytest
from shapely import LineString, MultiLineString
from shapely.errors import EmptyPartError
from shapely.geometry.base import dump_coords
from shapely.tests.geometry.test_multi import MultiGeometryTestCase
class TestMultiLineString(MultiGeometryTestCase):
def test_multilinestring(self):
# From coordinate tuples
geom = MultiLineString([[(1.0, 2.0), (3.0, 4.0)]])
assert isinstance(geom, MultiLineString)
assert len(geom.geoms) == 1
assert dump_coords(geom) == [[(1.0, 2.0), (3.0, 4.0)]]
# From lines
a = LineString([(1.0, 2.0), (3.0, 4.0)])
ml = MultiLineString([a])
assert len(ml.geoms) == 1
assert dump_coords(ml) == [[(1.0, 2.0), (3.0, 4.0)]]
# From another multi-line
ml2 = MultiLineString(ml)
assert len(ml2.geoms) == 1
assert dump_coords(ml2) == [[(1.0, 2.0), (3.0, 4.0)]]
# Sub-geometry Access
geom = MultiLineString([(((0.0, 0.0), (1.0, 2.0)))])
assert isinstance(geom.geoms[0], LineString)
assert dump_coords(geom.geoms[0]) == [(0.0, 0.0), (1.0, 2.0)]
with pytest.raises(IndexError): # index out of range
geom.geoms[1]
# Geo interface
assert geom.__geo_interface__ == {
"type": "MultiLineString",
"coordinates": (((0.0, 0.0), (1.0, 2.0)),),
}
def test_from_multilinestring_z(self):
coords1 = [(0.0, 1.0, 2.0), (3.0, 4.0, 5.0)]
coords2 = [(6.0, 7.0, 8.0), (9.0, 10.0, 11.0)]
# From coordinate tuples
ml = MultiLineString([coords1, coords2])
copy = MultiLineString(ml)
assert isinstance(copy, MultiLineString)
assert copy.geom_type == "MultiLineString"
assert len(copy.geoms) == 2
assert dump_coords(copy.geoms[0]) == coords1
assert dump_coords(copy.geoms[1]) == coords2
def test_numpy(self):
# Construct from a numpy array
geom = MultiLineString([np.array(((0.0, 0.0), (1.0, 2.0)))])
assert isinstance(geom, MultiLineString)
assert len(geom.geoms) == 1
assert dump_coords(geom) == [[(0.0, 0.0), (1.0, 2.0)]]
def test_subgeom_access(self):
line0 = LineString([(0.0, 1.0), (2.0, 3.0)])
line1 = LineString([(4.0, 5.0), (6.0, 7.0)])
self.subgeom_access_test(MultiLineString, [line0, line1])
def test_create_multi_with_empty_component(self):
msg = "Can't create MultiLineString with empty component"
with pytest.raises(EmptyPartError, match=msg):
MultiLineString([LineString([(0, 0), (1, 1), (2, 2)]), LineString()]).wkt
def test_numpy_object_array():
geom = MultiLineString([[[5.0, 6.0], [7.0, 8.0]]])
ar = np.empty(1, object)
ar[:] = [geom]
assert ar[0] == geom

View File

@@ -0,0 +1,93 @@
import numpy as np
import pytest
import shapely
from shapely import MultiPoint, Point
from shapely.errors import EmptyPartError
from shapely.geometry.base import dump_coords
from shapely.tests.geometry.test_multi import MultiGeometryTestCase
class TestMultiPoint(MultiGeometryTestCase):
def test_multipoint(self):
# From coordinate tuples
geom = MultiPoint([(1.0, 2.0), (3.0, 4.0)])
assert len(geom.geoms) == 2
assert dump_coords(geom) == [[(1.0, 2.0)], [(3.0, 4.0)]]
# From points
geom = MultiPoint([Point(1.0, 2.0), Point(3.0, 4.0)])
assert len(geom.geoms) == 2
assert dump_coords(geom) == [[(1.0, 2.0)], [(3.0, 4.0)]]
# From another multi-point
geom2 = MultiPoint(geom)
assert len(geom2.geoms) == 2
assert dump_coords(geom2) == [[(1.0, 2.0)], [(3.0, 4.0)]]
# Sub-geometry Access
assert isinstance(geom.geoms[0], Point)
assert geom.geoms[0].x == 1.0
assert geom.geoms[0].y == 2.0
with pytest.raises(IndexError): # index out of range
geom.geoms[2]
# Geo interface
assert geom.__geo_interface__ == {
"type": "MultiPoint",
"coordinates": ((1.0, 2.0), (3.0, 4.0)),
}
def test_multipoint_from_numpy(self):
# Construct from a numpy array
geom = MultiPoint(np.array([[0.0, 0.0], [1.0, 2.0]]))
assert isinstance(geom, MultiPoint)
assert len(geom.geoms) == 2
assert dump_coords(geom) == [[(0.0, 0.0)], [(1.0, 2.0)]]
def test_subgeom_access(self):
p0 = Point(1.0, 2.0)
p1 = Point(3.0, 4.0)
self.subgeom_access_test(MultiPoint, [p0, p1])
def test_create_multi_with_empty_component(self):
msg = "Can't create MultiPoint with empty component"
with pytest.raises(EmptyPartError, match=msg):
MultiPoint([Point(0, 0), Point()])
if shapely.geos_version < (3, 13, 0):
# for older GEOS, Point(NaN, NaN) is considered empty
with pytest.raises(EmptyPartError, match=msg):
MultiPoint([(0, 0), (np.nan, np.nan)])
with pytest.raises(EmptyPartError, match=msg):
MultiPoint(np.array([(0, 0), (np.nan, np.nan)]))
else:
result = MultiPoint([(0, 0), (np.nan, np.nan)])
expected = shapely.multipoints(
shapely.points([(0, 0), (np.nan, np.nan)], handle_nan="allow")
)
assert result == expected
def test_multipoint_array_coercion():
geom = MultiPoint([(1.0, 2.0), (3.0, 4.0)])
arr = np.array(geom)
assert arr.ndim == 0
assert arr.size == 1
assert arr.dtype == np.dtype("object")
assert arr.item() == geom
def test_numpy_object_array():
geom = MultiPoint([(1.0, 2.0), (3.0, 4.0)])
ar = np.empty(1, object)
ar[:] = [geom]
assert ar[0] == geom
def test_len_raises():
geom = MultiPoint([[5.0, 6.0], [7.0, 8.0]])
with pytest.raises(TypeError):
len(geom)

View File

@@ -0,0 +1,156 @@
import numpy as np
import pytest
from shapely import MultiPolygon, Polygon
from shapely.geometry.base import dump_coords
from shapely.tests.geometry.test_multi import MultiGeometryTestCase
class TestMultiPolygon(MultiGeometryTestCase):
def test_multipolygon(self):
# Empty
geom = MultiPolygon([])
assert geom.is_empty
assert len(geom.geoms) == 0
# From coordinate tuples
coords = [
(
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),
[((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))],
)
]
geom = MultiPolygon(coords)
assert isinstance(geom, MultiPolygon)
assert len(geom.geoms) == 1
assert dump_coords(geom) == [
[
(0.0, 0.0),
(0.0, 1.0),
(1.0, 1.0),
(1.0, 0.0),
(0.0, 0.0),
[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)],
]
]
# Or without holes
coords2 = [(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),)]
geom = MultiPolygon(coords2)
assert isinstance(geom, MultiPolygon)
assert len(geom.geoms) == 1
assert dump_coords(geom) == [
[
(0.0, 0.0),
(0.0, 1.0),
(1.0, 1.0),
(1.0, 0.0),
(0.0, 0.0),
]
]
# Or from polygons
p = Polygon(
((0, 0), (0, 1), (1, 1), (1, 0)),
[((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))],
)
geom = MultiPolygon([p])
assert len(geom.geoms) == 1
assert dump_coords(geom) == [
[
(0.0, 0.0),
(0.0, 1.0),
(1.0, 1.0),
(1.0, 0.0),
(0.0, 0.0),
[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)],
]
]
# None and empty polygons are dropped
geom_from_list_with_empty = MultiPolygon([p, None, Polygon()])
assert geom_from_list_with_empty == geom
# Or from a list of multiple polygons
geom_multiple_from_list = MultiPolygon([p, p])
assert len(geom_multiple_from_list.geoms) == 2
assert all(p == geom.geoms[0] for p in geom_multiple_from_list.geoms)
# Or from a np.array of polygons
geom_multiple_from_array = MultiPolygon(np.array([p, p]))
assert geom_multiple_from_array == geom_multiple_from_list
# Or from another multi-polygon
geom2 = MultiPolygon(geom)
assert len(geom2.geoms) == 1
assert dump_coords(geom2) == [
[
(0.0, 0.0),
(0.0, 1.0),
(1.0, 1.0),
(1.0, 0.0),
(0.0, 0.0),
[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)],
]
]
# Sub-geometry Access
assert isinstance(geom.geoms[0], Polygon)
assert dump_coords(geom.geoms[0]) == [
(0.0, 0.0),
(0.0, 1.0),
(1.0, 1.0),
(1.0, 0.0),
(0.0, 0.0),
[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)],
]
with pytest.raises(IndexError): # index out of range
geom.geoms[1]
# Geo interface
assert geom.__geo_interface__ == {
"type": "MultiPolygon",
"coordinates": [
(
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)),
((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)),
)
],
}
def test_subgeom_access(self):
poly0 = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)])
poly1 = Polygon([(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25)])
self.subgeom_access_test(MultiPolygon, [poly0, poly1])
def test_fail_list_of_multipolygons():
"""A list of multipolygons is not a valid multipolygon ctor argument"""
poly = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)])
multi = MultiPolygon(
[
(
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),
[((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))],
)
]
)
with pytest.raises(ValueError):
MultiPolygon([multi])
with pytest.raises(ValueError):
MultiPolygon([poly, multi])
def test_numpy_object_array():
geom = MultiPolygon(
[
(
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),
[((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))],
)
]
)
ar = np.empty(1, object)
ar[:] = [geom]
assert ar[0] == geom

View File

@@ -0,0 +1,201 @@
import numpy as np
import pytest
from shapely import Point, geos_version
from shapely.coords import CoordinateSequence
from shapely.errors import DimensionError, UnsupportedGEOSVersionError
def test_from_coordinates():
# Point
p = Point(1.0, 2.0)
assert p.coords[:] == [(1.0, 2.0)]
assert p.has_z is False
# PointZ
p = Point(1.0, 2.0, 3.0)
assert p.coords[:] == [(1.0, 2.0, 3.0)]
assert p.has_z
# empty
p = Point()
assert p.is_empty
assert isinstance(p.coords, CoordinateSequence)
assert p.coords[:] == []
def test_from_sequence():
# From single coordinate pair
p = Point((3.0, 4.0))
assert p.coords[:] == [(3.0, 4.0)]
p = Point([3.0, 4.0])
assert p.coords[:] == [(3.0, 4.0)]
# From coordinate sequence
p = Point([(3.0, 4.0)])
assert p.coords[:] == [(3.0, 4.0)]
p = Point([[3.0, 4.0]])
assert p.coords[:] == [(3.0, 4.0)]
# PointZ
p = Point((3.0, 4.0, 5.0))
assert p.coords[:] == [(3.0, 4.0, 5.0)]
p = Point([3.0, 4.0, 5.0])
assert p.coords[:] == [(3.0, 4.0, 5.0)]
p = Point([(3.0, 4.0, 5.0)])
assert p.coords[:] == [(3.0, 4.0, 5.0)]
def test_from_numpy():
# Construct from a numpy array
p = Point(np.array([1.0, 2.0]))
assert p.coords[:] == [(1.0, 2.0)]
p = Point(np.array([1.0, 2.0, 3.0]))
assert p.coords[:] == [(1.0, 2.0, 3.0)]
def test_from_numpy_xy():
# Construct from separate x, y numpy arrays - if those are length 1,
# this is allowed for compat with shapely 1.8
# (https://github.com/shapely/shapely/issues/1587)
p = Point(np.array([1.0]), np.array([2.0]))
assert p.coords[:] == [(1.0, 2.0)]
p = Point(np.array([1.0]), np.array([2.0]), np.array([3.0]))
assert p.coords[:] == [(1.0, 2.0, 3.0)]
def test_from_point():
# From another point
p = Point(3.0, 4.0)
q = Point(p)
assert q.coords[:] == [(3.0, 4.0)]
p = Point(3.0, 4.0, 5.0)
q = Point(p)
assert q.coords[:] == [(3.0, 4.0, 5.0)]
def test_from_generator():
gen = (coord for coord in [(1.0, 2.0)])
p = Point(gen)
assert p.coords[:] == [(1.0, 2.0)]
def test_from_invalid():
with pytest.raises(TypeError, match="takes at most 3 arguments"):
Point(1, 2, 3, 4)
# this worked in shapely 1.x, just ignoring the other coords
with pytest.raises(
ValueError, match="takes only scalar or 1-size vector arguments"
):
Point([(2, 3), (11, 4)])
class TestPoint:
def test_point(self):
# Test XY point
p = Point(1.0, 2.0)
assert p.x == 1.0
assert type(p.x) is float
assert p.y == 2.0
assert type(p.y) is float
assert p.coords[:] == [(1.0, 2.0)]
assert str(p) == p.wkt
assert p.has_z is False
with pytest.raises(DimensionError):
p.z
if geos_version >= (3, 12, 0):
assert p.has_m is False
with pytest.raises(DimensionError):
p.m
else:
with pytest.raises(UnsupportedGEOSVersionError):
p.m
# Check XYZ point
p = Point(1.0, 2.0, 3.0)
assert p.coords[:] == [(1.0, 2.0, 3.0)]
assert str(p) == p.wkt
assert p.has_z is True
assert p.z == 3.0
assert type(p.z) is float
if geos_version >= (3, 12, 0):
assert p.has_m is False
with pytest.raises(DimensionError):
p.m
# TODO: Check XYM and XYZM points
# Coordinate access
p = Point((3.0, 4.0))
assert p.x == 3.0
assert p.y == 4.0
assert tuple(p.coords) == ((3.0, 4.0),)
assert p.coords[0] == (3.0, 4.0)
with pytest.raises(IndexError): # index out of range
p.coords[1]
# Bounds
assert p.bounds == (3.0, 4.0, 3.0, 4.0)
# Geo interface
assert p.__geo_interface__ == {"type": "Point", "coordinates": (3.0, 4.0)}
def test_point_empty(self):
# Test Non-operability of Null geometry
p_null = Point()
assert p_null.wkt == "POINT EMPTY"
assert p_null.coords[:] == []
assert p_null.area == 0.0
assert p_null.__geo_interface__ == {"type": "Point", "coordinates": ()}
def test_coords(self):
# From Array.txt
p = Point(0.0, 0.0, 1.0)
coords = p.coords[0]
assert coords == (0.0, 0.0, 1.0)
# Convert to Numpy array, passing through Python sequence
a = np.asarray(coords)
assert a.ndim == 1
assert a.size == 3
assert a.shape == (3,)
def test_point_immutable():
p = Point(3.0, 4.0)
with pytest.raises(AttributeError):
p.coords = (2.0, 1.0)
with pytest.raises(TypeError):
p.coords[0] = (2.0, 1.0)
def test_point_array_coercion():
# don't convert to array of coordinates, keep objects
p = Point(3.0, 4.0)
arr = np.array(p)
assert arr.ndim == 0
assert arr.size == 1
assert arr.dtype == np.dtype("object")
assert arr.item() == p
def test_numpy_empty_point_coords():
pe = Point()
# Access the coords
a = np.asarray(pe.coords)
assert a.shape == (0, 2)
def test_numpy_object_array():
geom = Point(3.0, 4.0)
ar = np.empty(1, object)
ar[:] = [geom]
assert ar[0] == geom

View File

@@ -0,0 +1,460 @@
"""Polygons and Linear Rings"""
import numpy as np
import pytest
from shapely import LinearRing, LineString, Point, Polygon
from shapely.coords import CoordinateSequence
from shapely.errors import TopologicalError
from shapely.wkb import loads as load_wkb
def test_empty_linearring_coords():
assert LinearRing().coords[:] == []
def test_linearring_from_coordinate_sequence():
expected_coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
ring = LinearRing([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
assert ring.coords[:] == expected_coords
ring = LinearRing([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
assert ring.coords[:] == expected_coords
def test_linearring_from_points():
# From Points
expected_coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
ring = LinearRing([Point(0.0, 0.0), Point(0.0, 1.0), Point(1.0, 1.0)])
assert ring.coords[:] == expected_coords
def test_linearring_from_closed_linestring():
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
line = LineString(coords)
ring = LinearRing(line)
assert len(ring.coords) == 4
assert ring.coords[:] == coords
assert ring.geom_type == "LinearRing"
def test_linearring_from_unclosed_linestring():
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
line = LineString(coords[:-1]) # Pass in unclosed line
ring = LinearRing(line)
assert len(ring.coords) == 4
assert ring.coords[:] == coords
assert ring.geom_type == "LinearRing"
def test_linearring_from_invalid():
coords = [(0.0, 0.0), (0.0, 0.0), (0.0, 0.0)]
line = LineString(coords)
assert not line.is_valid
with pytest.raises(TopologicalError):
LinearRing(line)
def test_linearring_from_too_short_linestring():
# Creation of LinearRing request at least 3 coordinates (unclosed) or
# 4 coordinates (closed)
coords = [(0.0, 0.0), (1.0, 1.0)]
line = LineString(coords)
with pytest.raises(ValueError, match="requires at least 4 coordinates"):
LinearRing(line)
def test_linearring_from_linearring():
coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
ring = LinearRing(coords)
assert ring.coords[:] == coords
def test_linearring_from_generator():
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
gen = (coord for coord in coords)
ring = LinearRing(gen)
assert ring.coords[:] == coords
def test_linearring_from_empty():
ring = LinearRing()
assert ring.is_empty
assert isinstance(ring.coords, CoordinateSequence)
assert ring.coords[:] == []
ring = LinearRing([])
assert ring.is_empty
assert isinstance(ring.coords, CoordinateSequence)
assert ring.coords[:] == []
def test_linearring_from_numpy():
# Construct from a numpy array
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
ring = LinearRing(np.array(coords))
assert ring.coords[:] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
def test_numpy_linearring_coords():
from numpy.testing import assert_array_equal
ring = LinearRing([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
ra = np.asarray(ring.coords)
expected = np.asarray([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)])
assert_array_equal(ra, expected)
def test_numpy_empty_linearring_coords():
ring = LinearRing()
assert np.asarray(ring.coords).shape == (0, 2)
def test_numpy_object_array():
geom = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
ar = np.empty(1, object)
ar[:] = [geom]
assert ar[0] == geom
def test_polygon_from_coordinate_sequence():
coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
# Construct a polygon, exterior ring only
polygon = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
assert polygon.exterior.coords[:] == coords
assert len(polygon.interiors) == 0
polygon = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
assert polygon.exterior.coords[:] == coords
assert len(polygon.interiors) == 0
def test_polygon_from_coordinate_sequence_with_holes():
coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
# Interior rings (holes)
polygon = Polygon(coords, [[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25)]])
assert polygon.exterior.coords[:] == coords
assert len(polygon.interiors) == 1
assert len(polygon.interiors[0].coords) == 5
# Multiple interior rings with different length
coords = [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)]
holes = [
[(1, 1), (2, 1), (2, 2), (1, 2), (1, 1)],
[(3, 3), (3, 4), (4, 5), (5, 4), (5, 3), (3, 3)],
]
polygon = Polygon(coords, holes)
assert polygon.exterior.coords[:] == coords
assert len(polygon.interiors) == 2
assert len(polygon.interiors[0].coords) == 5
assert len(polygon.interiors[1].coords) == 6
def test_polygon_from_linearring():
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
ring = LinearRing(coords)
polygon = Polygon(ring)
assert polygon.exterior.coords[:] == coords
assert len(polygon.interiors) == 0
# from shell and holes linearrings
shell = LinearRing([(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)])
holes = [
LinearRing([(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)]),
LinearRing([(30.0, 10.0), (50.0, 10.0), (40.0, 30.0), (30.0, 10.0)]),
LinearRing([(90.0, 10), (110.0, 10.0), (100.0, 30.0), (90.0, 10.0)]),
]
polygon = Polygon(shell, holes)
assert polygon.exterior.coords[:] == shell.coords[:]
assert len(polygon.interiors) == 3
for i in range(3):
assert polygon.interiors[i].coords[:] == holes[i].coords[:]
def test_polygon_from_linestring():
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
line = LineString(coords)
polygon = Polygon(line)
assert polygon.exterior.coords[:] == coords
# from unclosed linestring
line = LineString(coords[:-1])
polygon = Polygon(line)
assert polygon.exterior.coords[:] == coords
def test_polygon_from_points():
polygon = Polygon([Point(0.0, 0.0), Point(0.0, 1.0), Point(1.0, 1.0)])
expected_coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
assert polygon.exterior.coords[:] == expected_coords
def test_polygon_from_polygon():
coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)]
polygon = Polygon(coords, [[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25)]])
# Test from another Polygon
copy = Polygon(polygon)
assert len(copy.exterior.coords) == 5
assert len(copy.interiors) == 1
assert len(copy.interiors[0].coords) == 5
def test_polygon_from_invalid():
# Error handling
with pytest.raises(ValueError):
# A LinearRing must have at least 3 coordinate tuples
Polygon([[1, 2], [2, 3]])
def test_polygon_from_empty():
polygon = Polygon()
assert polygon.is_empty
assert polygon.exterior.coords[:] == []
polygon = Polygon([])
assert polygon.is_empty
assert polygon.exterior.coords[:] == []
def test_polygon_from_numpy():
a = np.array(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)))
polygon = Polygon(a)
assert len(polygon.exterior.coords) == 5
assert polygon.exterior.coords[:] == [
(0.0, 0.0),
(0.0, 1.0),
(1.0, 1.0),
(1.0, 0.0),
(0.0, 0.0),
]
assert len(polygon.interiors) == 0
def test_polygon_from_generator():
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
gen = (coord for coord in coords)
polygon = Polygon(gen)
assert polygon.exterior.coords[:] == coords
class TestPolygon:
def test_linearring(self):
# Initialization
# Linear rings won't usually be created by users, but by polygons
coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))
ring = LinearRing(coords)
assert len(ring.coords) == 5
assert ring.coords[0] == ring.coords[4]
assert ring.coords[0] == ring.coords[-1]
assert ring.is_ring is True
def test_polygon(self):
coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))
# Construct a polygon, exterior ring only
polygon = Polygon(coords)
assert len(polygon.exterior.coords) == 5
# Ring Access
assert isinstance(polygon.exterior, LinearRing)
ring = polygon.exterior
assert len(ring.coords) == 5
assert ring.coords[0] == ring.coords[4]
assert ring.coords[0] == (0.0, 0.0)
assert ring.is_ring is True
assert len(polygon.interiors) == 0
# Create a new polygon from WKB
data = polygon.wkb
polygon = None
ring = None
polygon = load_wkb(data)
ring = polygon.exterior
assert len(ring.coords) == 5
assert ring.coords[0] == ring.coords[4]
assert ring.coords[0] == (0.0, 0.0)
assert ring.is_ring is True
polygon = None
# Interior rings (holes)
polygon = Polygon(
coords, [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]
)
assert len(polygon.exterior.coords) == 5
assert len(polygon.interiors[0].coords) == 5
with pytest.raises(IndexError): # index out of range
polygon.interiors[1]
# Coordinate getter raises exceptions
with pytest.raises(NotImplementedError):
polygon.coords
# Geo interface
assert polygon.__geo_interface__ == {
"type": "Polygon",
"coordinates": (
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)),
((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)),
),
}
def test_linearring_empty(self):
# Test Non-operability of Null rings
r_null = LinearRing()
assert r_null.wkt == "LINEARRING EMPTY"
assert r_null.length == 0.0
def test_dimensions(self):
# Background: see http://trac.gispython.org/lab/ticket/168
# http://lists.gispython.org/pipermail/community/2008-August/001859.html
coords = ((0.0, 0.0, 0.0), (0.0, 1.0, 0.0), (1.0, 1.0, 0.0), (1.0, 0.0, 0.0))
polygon = Polygon(coords)
assert polygon._ndim == 3
gi = polygon.__geo_interface__
assert gi["coordinates"] == (
(
(0.0, 0.0, 0.0),
(0.0, 1.0, 0.0),
(1.0, 1.0, 0.0),
(1.0, 0.0, 0.0),
(0.0, 0.0, 0.0),
),
)
e = polygon.exterior
assert e._ndim == 3
gi = e.__geo_interface__
assert gi["coordinates"] == (
(0.0, 0.0, 0.0),
(0.0, 1.0, 0.0),
(1.0, 1.0, 0.0),
(1.0, 0.0, 0.0),
(0.0, 0.0, 0.0),
)
def test_attribute_chains(self):
# Attribute Chaining
# See also ticket #151.
p = Polygon([(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)])
assert list(p.boundary.coords) == [
(0.0, 0.0),
(0.0, 1.0),
(-1.0, 1.0),
(-1.0, 0.0),
(0.0, 0.0),
]
ec = list(Point(0.0, 0.0).buffer(1.0, quad_segs=1).exterior.coords)
assert isinstance(ec, list) # TODO: this is a poor test
# Test chained access to interiors
p = Polygon(
[(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)],
[[(-0.25, 0.25), (-0.25, 0.75), (-0.75, 0.75), (-0.75, 0.25)]],
)
assert p.area == 0.75
"""Not so much testing the exact values here, which are the
responsibility of the geometry engine (GEOS), but that we can get
chain functions and properties using anonymous references.
"""
assert list(p.interiors[0].coords) == [
(-0.25, 0.25),
(-0.25, 0.75),
(-0.75, 0.75),
(-0.75, 0.25),
(-0.25, 0.25),
]
xy = next(iter(p.interiors[0].buffer(1).exterior.coords))
assert len(xy) == 2
# Test multiple operators, boundary of a buffer
ec = list(p.buffer(1).boundary.coords)
assert isinstance(ec, list) # TODO: this is a poor test
def test_empty_equality(self):
# Test equals operator, including empty geometries
# see issue #338
point1 = Point(0, 0)
polygon1 = Polygon([(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)])
polygon2 = Polygon([(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)])
polygon_empty1 = Polygon()
polygon_empty2 = Polygon()
assert point1 != polygon1
assert polygon_empty1 == polygon_empty2
assert polygon1 != polygon_empty1
assert polygon1 == polygon2
assert polygon_empty1 is not None
def test_from_bounds(self):
xmin, ymin, xmax, ymax = -180, -90, 180, 90
coords = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)]
assert Polygon(coords) == Polygon.from_bounds(xmin, ymin, xmax, ymax)
def test_empty_polygon_exterior(self):
p = Polygon()
assert p.exterior == LinearRing()
def test_linearring_immutable():
ring = LinearRing([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)])
with pytest.raises(AttributeError):
ring.coords = [(1.0, 1.0), (2.0, 2.0), (1.0, 2.0)]
with pytest.raises(TypeError):
ring.coords[0] = (1.0, 1.0)
class TestLinearRingGetItem:
def test_index_linearring(self):
shell = LinearRing([(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)])
holes = [
LinearRing([(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)]),
LinearRing([(30.0, 10.0), (50.0, 10.0), (40.0, 30.0), (30.0, 10.0)]),
LinearRing([(90.0, 10), (110.0, 10.0), (100.0, 30.0), (90.0, 10.0)]),
]
g = Polygon(shell, holes)
for i in range(-3, 3):
assert g.interiors[i].equals(holes[i])
with pytest.raises(IndexError):
g.interiors[3]
with pytest.raises(IndexError):
g.interiors[-4]
def test_index_linearring_misc(self):
g = Polygon() # empty
with pytest.raises(IndexError):
g.interiors[0]
with pytest.raises(TypeError):
g.interiors[0.0]
def test_slice_linearring(self):
shell = LinearRing([(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)])
holes = [
LinearRing([(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)]),
LinearRing([(30.0, 10.0), (50.0, 10.0), (40.0, 30.0), (30.0, 10.0)]),
LinearRing([(90.0, 10), (110.0, 10.0), (100.0, 30.0), (90.0, 10.0)]),
]
g = Polygon(shell, holes)
t = [a.equals(b) for (a, b) in zip(g.interiors[1:], holes[1:])]
assert all(t)
t = [a.equals(b) for (a, b) in zip(g.interiors[:-1], holes[:-1])]
assert all(t)
t = [a.equals(b) for (a, b) in zip(g.interiors[::-1], holes[::-1])]
assert all(t)
t = [a.equals(b) for (a, b) in zip(g.interiors[::2], holes[::2])]
assert all(t)
t = [a.equals(b) for (a, b) in zip(g.interiors[:3], holes[:3])]
assert all(t)
assert g.interiors[3:] == holes[3:] == []