Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TST: Move + clean-up tests for the scalar geometry subclasses #1257

Merged
merged 3 commits into from Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Empty file.
@@ -1,3 +1,5 @@
import numpy as np

from shapely import wkt

from shapely.geometry import LineString
Expand All @@ -9,21 +11,32 @@

@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(),
shape({"type": "GeometryCollection", "geometries": []}),
shape({"type": "GeometryCollection", "geometries": [
{"type": "Point", "coordinates": ()},
{"type": "LineString", "coordinates": (())}
]}),
wkt.loads('GEOMETRYCOLLECTION EMPTY'),
])
return {
"type": "GeometryCollection",
"geometries": [
{"type": "Point", "coordinates": (0, 3, 0)},
{"type": "LineString", "coordinates": ((2, 0), (1, 0))},
],
}


@pytest.mark.parametrize(
"geom",
[
GeometryCollection(),
shape({"type": "GeometryCollection", "geometries": []}),
shape(
{
"type": "GeometryCollection",
"geometries": [
{"type": "Point", "coordinates": ()},
{"type": "LineString", "coordinates": (())},
],
}
),
wkt.loads("GEOMETRYCOLLECTION EMPTY"),
],
)
def test_empty(geom):
assert geom.type == "GeometryCollection"
assert geom.type == geom.geom_type
Expand Down Expand Up @@ -70,8 +83,6 @@ def test_len_raises(geometrycollection_geojson):

@pytest.mark.filterwarnings("error:An exception was ignored") # NumPy 1.21
def test_numpy_object_array():
np = pytest.importorskip("numpy")

geom = GeometryCollection([LineString([(0, 0), (1, 1)])])
ar = np.empty(1, object)
ar[:] = [geom]
Expand Down
37 changes: 37 additions & 0 deletions shapely/tests/geometry/test_geometry_base.py
@@ -0,0 +1,37 @@
from shapely import geometry

import pytest


def test_polygon():
assert bool(geometry.Polygon()) is False


def test_linestring():
assert bool(geometry.LineString()) is False


def test_point():
assert bool(geometry.Point()) is False


def test_geometry_collection():
assert bool(geometry.GeometryCollection()) is False


@pytest.mark.parametrize(
"geom",
[
geometry.Point(1, 1),
geometry.LinearRing([(0, 0), (1, 1), (0, 1), (0, 0)]),
geometry.LineString([(0, 0), (1, 1), (0, 1), (0, 0)]),
geometry.Polygon([(0, 0), (1, 1), (0, 1), (0, 0)]),
geometry.MultiPoint([(1, 1)]),
geometry.MultiLineString([[(0, 0), (1, 1), (0, 1), (0, 0)]]),
geometry.MultiPolygon([geometry.Polygon([(0, 0), (1, 1), (0, 1), (0, 0)])]),
geometry.GeometryCollection([geometry.Point(1, 1)]),
],
)
def test_setattr_disallowed(geom):
with pytest.raises(AttributeError):
geom.name = "test"
@@ -1,12 +1,10 @@
from . import unittest, numpy, shapely20_deprecated
from .conftest import shapely20_todo
import pytest
import numpy as np

import shapely
from shapely.coords import CoordinateSequence
from shapely.errors import ShapelyDeprecationWarning
from shapely.geometry import LineString, Point, LinearRing

import shapely
import pytest


def test_from_coordinate_sequence():
Expand Down Expand Up @@ -45,23 +43,23 @@ def test_from_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'
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'
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'
assert copy.geom_type == "LineString"


def test_from_generator():
Expand All @@ -84,28 +82,21 @@ def test_from_empty():

def test_from_numpy():
# Construct from a numpy array
np = pytest.importorskip("numpy")

line = LineString(np.array([[1.0, 2.0], [3.0, 4.0]]))
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]


@pytest.mark.filterwarnings("error:An exception was ignored") # NumPy 1.21
def test_numpy_empty_linestring_coords():
np = pytest.importorskip("numpy")

# Check empty
line = LineString([])
la = np.asarray(line.coords)

assert la.shape == (0, 2)


@shapely20_deprecated
@pytest.mark.filterwarnings("error:An exception was ignored") # NumPy 1.21
def test_numpy_object_array():
np = pytest.importorskip("numpy")

geom = LineString([(0.0, 0.0), (0.0, 1.0)])
ar = np.empty(1, object)
ar[:] = [geom]
Expand All @@ -120,10 +111,16 @@ def test_from_invalid_dim():
with pytest.raises(shapely.GEOSException):
LineString([(1, 2)])

with pytest.raises(ValueError, match="Inconsistent coordinate dimensionality|Input operand 0 does not have enough dimensions"):
with pytest.raises(
ValueError,
match="Inconsistent coordinate dimensionality|Input operand 0 does not have enough dimensions",
):
LineString([(1, 2, 3), (4, 5)])

with pytest.raises(ValueError, match="Inconsistent coordinate dimensionality|Input operand 0 does not have enough dimensions"):
with pytest.raises(
ValueError,
match="Inconsistent coordinate dimensionality|Input operand 0 does not have enough dimensions",
):
LineString([(1, 2), (3, 4, 5)])

# TODO better error, right now raises AssertionError
Expand All @@ -139,35 +136,35 @@ def test_from_single_coordinate():
ls.geom_type # caused segfault before fix


class LineStringTestCase(unittest.TestCase):

class TestLineString:
def test_linestring(self):

# From coordinate tuples
line = LineString(((1.0, 2.0), (3.0, 4.0)))
self.assertEqual(len(line.coords), 2)
self.assertEqual(line.coords[:], [(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
self.assertEqual(line.bounds, (1.0, 2.0, 3.0, 4.0))
assert line.bounds == (1.0, 2.0, 3.0, 4.0)

# Coordinate access
self.assertEqual(tuple(line.coords), ((1.0, 2.0), (3.0, 4.0)))
self.assertEqual(line.coords[0], (1.0, 2.0))
self.assertEqual(line.coords[1], (3.0, 4.0))
with self.assertRaises(IndexError):
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
self.assertEqual(line.__geo_interface__,
{'type': 'LineString',
'coordinates': ((1.0, 2.0), (3.0, 4.0))})
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()
self.assertEqual(l_null.wkt, 'LINESTRING EMPTY')
self.assertEqual(l_null.length, 0.0)
assert l_null.wkt == "LINESTRING EMPTY"
assert l_null.length == 0.0

def test_equals_argument_order(self):
"""
Expand All @@ -178,28 +175,27 @@ def test_equals_argument_order(self):
ls = LineString(coords)
lr = LinearRing(coords)

self.assertFalse(ls.__eq__(lr)) # previously incorrectly returned True
self.assertFalse(lr.__eq__(ls))
self.assertFalse(ls == lr)
self.assertFalse(lr == ls)
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)

self.assertTrue(ls.__eq__(ls_clone))
self.assertTrue(lr.__eq__(lr_clone))
self.assertTrue(ls == ls_clone)
self.assertTrue(lr == lr_clone)
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

@unittest.skipIf(not numpy, 'Numpy required')
def test_numpy_linestring_coords(self):
from numpy.testing import assert_array_equal

line = LineString(((1.0, 2.0), (3.0, 4.0)))
expected = numpy.array([[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 = numpy.asarray(line.coords)
la = np.asarray(line.coords)
assert_array_equal(la, expected)


Expand All @@ -213,11 +209,8 @@ def test_linestring_immutable():
line.coords[0] = (-1.0, -1.0)


@unittest.skipIf(not numpy, 'Numpy required')
def test_linestring_array_coercion():
# don't convert to array of coordinates, keep objects
import numpy as np

line = LineString(((1.0, 2.0), (3.0, 4.0)))
arr = np.array(line)
assert arr.ndim == 0
Expand Down
11 changes: 11 additions & 0 deletions shapely/tests/geometry/test_multi.py
@@ -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)] == geoms[i]
81 changes: 81 additions & 0 deletions shapely/tests/geometry/test_multilinestring.py
@@ -0,0 +1,81 @@
from .test_multi import MultiGeometryTestCase

import numpy as np

import pytest

from shapely.errors import EmptyPartError
from shapely.geometry import LineString, MultiLineString
from shapely.geometry.base import dump_coords


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


@pytest.mark.filterwarnings("error:An exception was ignored") # NumPy 1.21
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