| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351 |
- import json
- import pickle
- import struct
- import warnings
- from contextlib import nullcontext
- import numpy as np
- import pytest
- import shapely
- from shapely import (
- GeometryCollection,
- GEOSException,
- LinearRing,
- LineString,
- MultiLineString,
- MultiPoint,
- MultiPolygon,
- Point,
- Polygon,
- )
- from shapely.errors import UnsupportedGEOSVersionError
- from shapely.testing import assert_geometries_equal
- from shapely.tests.common import (
- all_types,
- all_types_m,
- all_types_z,
- all_types_zm,
- empty_point,
- empty_point_m,
- empty_point_z,
- empty_point_zm,
- equal_geometries_abnormally_yield_unequal,
- multi_point_empty,
- multi_point_empty_m,
- multi_point_empty_z,
- multi_point_empty_zm,
- point,
- point_m,
- point_z,
- point_zm,
- polygon_z,
- )
- EWKBZ = 0x80000000
- EWKBM = 0x40000000
- EWKBZM = EWKBZ | EWKBM
- ISOWKBZ = 1000
- ISOWKBM = 2000
- ISOWKBZM = ISOWKBZ + ISOWKBM
- POINT11_WKB = struct.pack("<BI2d", 1, 1, 1.0, 1.0)
- NAN = struct.pack("<d", float("nan"))
- POINT_NAN_WKB = struct.pack("<BI", 1, 1) + (NAN * 2)
- POINTZ_NAN_WKB = struct.pack("<BI", 1, 1 | EWKBZ) + (NAN * 3)
- POINTM_NAN_WKB = struct.pack("<BI", 1, 1 | EWKBM) + (NAN * 3)
- POINTZM_NAN_WKB = struct.pack("<BI", 1, 1 | EWKBZM) + (NAN * 4)
- MULTIPOINT_NAN_WKB = struct.pack("<BII", 1, 4, 1) + POINT_NAN_WKB
- MULTIPOINTZ_NAN_WKB = struct.pack("<BII", 1, 4 | EWKBZ, 1) + POINTZ_NAN_WKB
- MULTIPOINTM_NAN_WKB = struct.pack("<BII", 1, 4 | EWKBM, 1) + POINTM_NAN_WKB
- MULTIPOINTZM_NAN_WKB = struct.pack("<BII", 1, 4 | EWKBZM, 1) + POINTZM_NAN_WKB
- GEOMETRYCOLLECTION_NAN_WKB = struct.pack("<BII", 1, 7, 1) + POINT_NAN_WKB
- GEOMETRYCOLLECTIONZ_NAN_WKB = struct.pack("<BII", 1, 7 | EWKBZ, 1) + POINTZ_NAN_WKB
- GEOMETRYCOLLECTIONM_NAN_WKB = struct.pack("<BII", 1, 7 | EWKBM, 1) + POINTM_NAN_WKB
- GEOMETRYCOLLECTIONZM_NAN_WKB = struct.pack("<BII", 1, 7 | EWKBZM, 1) + POINTZM_NAN_WKB
- NESTED_COLLECTION_NAN_WKB = struct.pack("<BII", 1, 7, 1) + MULTIPOINT_NAN_WKB
- NESTED_COLLECTIONZ_NAN_WKB = struct.pack("<BII", 1, 7 | EWKBZ, 1) + MULTIPOINTZ_NAN_WKB
- NESTED_COLLECTIONM_NAN_WKB = struct.pack("<BII", 1, 7 | EWKBM, 1) + MULTIPOINTM_NAN_WKB
- NESTED_COLLECTIONZM_NAN_WKB = (
- struct.pack("<BII", 1, 7 | EWKBZM, 1) + MULTIPOINTZM_NAN_WKB
- )
- INVALID_WKB = "01030000000100000002000000507daec600b1354100de02498e5e3d41306ea321fcb03541a011a53d905e3d41" # noqa: E501
- GEOJSON_GEOMETRY = json.dumps({"type": "Point", "coordinates": [125.6, 10.1]}, indent=4)
- GEOJSON_FEATURE = json.dumps(
- {
- "type": "Feature",
- "geometry": {"type": "Point", "coordinates": [125.6, 10.1]},
- "properties": {"name": "Dinagat Islands"},
- },
- indent=4,
- )
- GEOJSON_FEATURECOLECTION = json.dumps(
- {
- "type": "FeatureCollection",
- "features": [
- {
- "type": "Feature",
- "geometry": {"type": "Point", "coordinates": [102.0, 0.6]},
- "properties": {"prop0": "value0"},
- },
- {
- "type": "Feature",
- "geometry": {
- "type": "LineString",
- "coordinates": [
- [102.0, 0.0],
- [103.0, 1.0],
- [104.0, 0.0],
- [105.0, 1.0],
- ],
- },
- "properties": {"prop1": 0.0, "prop0": "value0"},
- },
- {
- "type": "Feature",
- "geometry": {
- "type": "Polygon",
- "coordinates": [
- [
- [100.0, 0.0],
- [101.0, 0.0],
- [101.0, 1.0],
- [100.0, 1.0],
- [100.0, 0.0],
- ]
- ],
- },
- "properties": {"prop1": {"this": "that"}, "prop0": "value0"},
- },
- ],
- },
- indent=4,
- )
- GEOJSON_GEOMETRY_EXPECTED = shapely.points(125.6, 10.1)
- GEOJSON_COLLECTION_EXPECTED = [
- shapely.points([102.0, 0.6]),
- shapely.linestrings([[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]]),
- shapely.polygons(
- [[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]
- ),
- ]
- def test_from_wkt():
- expected = shapely.points(1, 1)
- actual = shapely.from_wkt("POINT (1 1)")
- assert_geometries_equal(actual, expected)
- # also accept bytes
- actual = shapely.from_wkt(b"POINT (1 1)")
- assert_geometries_equal(actual, expected)
- def test_from_wkt_none():
- # None propagates
- assert shapely.from_wkt(None) is None
- @pytest.mark.parametrize(
- "wkt, on_invalid, error, message",
- [
- (1, "raise", TypeError, "Expected bytes or string, got int"),
- ("", "ignore", None, None),
- ("", "warn", Warning, "Expected word but encountered end of stream"),
- ("", "raise", GEOSException, "Expected word but encountered end of stream"),
- ("", "unsupported_option", ValueError, "not a valid option"),
- ("LINESTRING (0 0)", "ignore", None, None),
- ("LINESTRING (0 0)", "raise", GEOSException, "must contain 0 or >1 elements"),
- ("LINESTRING (0 0)", "warn", Warning, "must contain 0 or >1 elements"),
- ("NOT A WKT STRING", "ignore", None, None),
- ("NOT A WKT STRING", "warn", Warning, "Unknown type: 'NOT'"),
- ("POLYGON ((0 0, 0 0))", "ignore", None, None),
- ("POLYGON ((0 0, 0 0))", "raise", GEOSException, "Invalid number of points"),
- ("POLYGON ((0 0, 0 0))", "warn", Warning, "Invalid number of points"),
- ],
- )
- def test_from_wkt_on_invalid(wkt, on_invalid, error, message):
- if on_invalid == "warn":
- handler = pytest.warns(error, match=message)
- elif on_invalid == "raise":
- handler = pytest.raises(error, match=message)
- elif on_invalid == "ignore":
- handler = nullcontext()
- else:
- handler = pytest.raises(error, match=message)
- with handler:
- result = shapely.from_wkt(wkt, on_invalid=on_invalid)
- assert result is None
- @pytest.mark.skipif(
- shapely.geos_version < (3, 11, 0),
- reason="on_invalid='fix' not supported with GEOS < 3.11",
- )
- @pytest.mark.parametrize(
- "wkt, expected_wkt",
- [
- ("", None),
- ("LINESTRING (0 0)", None),
- ("NOT A WKT STRING", None),
- ("POLYGON ((0 0, 0 0))", None),
- ("POLYGON ((0 0, 1 1, 0 1))", "POLYGON ((0 0, 1 1, 0 1, 0 0))"),
- ("POLYGON ((0 0, 1 1))", "POLYGON ((0 0, 1 1, 0 0))"),
- ("MULTIPOLYGON (((5 5, 6 6, 6 5, 5 5)), ((0 0, 0 0)))", None),
- (
- "MULTIPOLYGON (((5 5, 6 6, 6 5, 5 5)), ((0 0, 1 1)))",
- "MULTIPOLYGON (((5 5, 6 6, 6 5, 5 5)), ((0 0, 1 1, 0 0)))",
- ),
- (
- "GEOMETRYCOLLECTION (POLYGON ((5 5, 6 6, 6 5, 5 5)), POLYGON ((0 0, 0 0)))",
- None,
- ),
- ],
- )
- def test_from_wkt_on_invalid_fix(wkt, expected_wkt):
- """Tests for on_invalid="fix".
- Geometries that cannot be fixed are returned as None.
- """
- geom = shapely.from_wkt(wkt, on_invalid="fix")
- assert shapely.to_wkt(geom) == expected_wkt
- @pytest.mark.skipif(
- shapely.geos_version >= (3, 11, 0),
- reason="on_invalid='fix' is supported with GEOS >= 3.11",
- )
- def test_from_wkt_on_invalid_fix_unsupported_geos():
- """on_invalid="fix" not supported with GEOS < 3.11"""
- with pytest.raises(
- ValueError, match="on_invalid='fix' only supported for GEOS >= 3.11"
- ):
- _ = shapely.from_wkt("", on_invalid="fix")
- @pytest.mark.parametrize("geom", all_types)
- def test_from_wkt_all_types(geom):
- wkt = shapely.to_wkt(geom)
- actual = shapely.from_wkt(wkt)
- if equal_geometries_abnormally_yield_unequal(geom):
- # check abnormal test
- with pytest.raises(AssertionError):
- assert_geometries_equal(actual, geom)
- else:
- # normal test
- assert_geometries_equal(actual, geom)
- @pytest.mark.parametrize(
- "wkt",
- ("POINT EMPTY", "LINESTRING EMPTY", "POLYGON EMPTY", "GEOMETRYCOLLECTION EMPTY"),
- )
- def test_from_wkt_empty(wkt):
- geom = shapely.from_wkt(wkt)
- assert shapely.is_geometry(geom).all()
- assert shapely.is_empty(geom).all()
- assert shapely.to_wkt(geom) == wkt
- # WKT from https://github.com/libgeos/geos/blob/main/tests/unit/io/WKBReaderTest.cpp
- @pytest.mark.parametrize(
- "wkt",
- (
- "CIRCULARSTRING(1 3,2 4,3 1)",
- "COMPOUNDCURVE(CIRCULARSTRING(1 3,2 4,3 1),(3 1,0 0))",
- "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,2 0,2 1,2 3,4 3),(4 3,4 5,1 4,0 0)),CIRCULARSTRING(1.7 1,1.4 0.4,1.6 0.4,1.6 0.5,1.7 1))", # noqa: E501
- "MULTICURVE((0 0,5 5),COMPOUNDCURVE((-1 -1,0 0),CIRCULARSTRING(0 0,1 1,2 0)),CIRCULARSTRING(4 0,4 4,8 4))", # noqa: E501
- "MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1)),((10 10,14 12,11 10,10 10),(11 11,11.5 11,11 11.5,11 11)))", # noqa: E501
- ),
- )
- def test_from_wkt_nonlinear_unsupported(wkt):
- if shapely.geos_version >= (3, 13, 0):
- with pytest.raises(
- NotImplementedError,
- match="Nonlinear geometry types are not currently supported",
- ):
- shapely.from_wkt(wkt)
- else:
- # prior to GEOS 3.13 nonlinear types were rejected by GEOS on read from WKT
- with pytest.raises(shapely.errors.GEOSException, match="Unknown type"):
- shapely.from_wkt(wkt)
- def test_from_wkb():
- expected = shapely.points(1, 1)
- actual = shapely.from_wkb(POINT11_WKB)
- assert_geometries_equal(actual, expected)
- def test_from_wkb_hex():
- # HEX form
- expected = shapely.points(1, 1)
- actual = shapely.from_wkb("0101000000000000000000F03F000000000000F03F")
- assert_geometries_equal(actual, expected)
- actual = shapely.from_wkb(b"0101000000000000000000F03F000000000000F03F")
- assert_geometries_equal(actual, expected)
- def test_from_wkb_none():
- # None propagates
- assert shapely.from_wkb(None) is None
- @pytest.mark.parametrize(
- "wkb, on_invalid, error, message",
- [
- (1, "raise", TypeError, "Expected bytes or string, got int"),
- ("", "ignore", None, None),
- ("", "raise", GEOSException, "Unexpected EOF parsing WKB"),
- ("", "warn", Warning, "Unexpected EOF parsing WKB"),
- ("", "unsupported_option", ValueError, "not a valid option"),
- (b"\x01\x01\x00\x00\x00\x00", "ignore", None, None),
- (b"\x01\x01\x00\x00\x00\x00", "raise", GEOSException, "ParseException"),
- (b"\x01\x01\x00\x00\x00\x00", "warn", Warning, "ParseException"),
- (INVALID_WKB, "ignore", None, None),
- (
- INVALID_WKB,
- "raise",
- GEOSException,
- "Points of LinearRing do not form a closed linestring",
- ),
- (
- INVALID_WKB,
- "warn",
- Warning,
- "Points of LinearRing do not form a closed linestring",
- ),
- ],
- )
- def test_from_wkb_on_invalid(wkb, on_invalid, error, message):
- if on_invalid == "warn":
- handler = pytest.warns(error, match=message)
- elif on_invalid == "raise":
- handler = pytest.raises(error, match=message)
- elif on_invalid == "ignore":
- handler = nullcontext()
- else:
- handler = pytest.raises(error, match=message)
- with handler:
- result = shapely.from_wkb(wkb, on_invalid=on_invalid)
- assert result is None
- @pytest.mark.skipif(
- shapely.geos_version < (3, 11, 0),
- reason="on_invalid='fix' not supported with GEOS < 3.11",
- )
- @pytest.mark.parametrize(
- "wkb, expected_wkt",
- [
- (b"", None),
- (b"\x01\x01\x00\x00\x00\x00", None),
- (
- INVALID_WKB,
- "POLYGON ((1421568.7761 1924750.2852, 1421564.1314 1924752.2408, 1421568.7761 1924750.2852))", # noqa: E501
- ),
- ],
- )
- def test_from_wkb_on_invalid_fix(wkb, expected_wkt):
- """Tests for on_invalid="fix".
- Geometries that cannot be fixed are returned as None.
- """
- geom = shapely.from_wkb(wkb, on_invalid="fix")
- assert shapely.to_wkt(geom) == expected_wkt
- @pytest.mark.skipif(
- shapely.geos_version >= (3, 11, 0),
- reason="on_invalid='fix' is supported with GEOS >= 3.11",
- )
- def test_from_wkb_on_invalid_fix_unsupported_geos():
- """on_invalid="fix" not supported with GEOS < 3.11"""
- with pytest.raises(
- ValueError, match="on_invalid='fix' only supported for GEOS >= 3.11"
- ):
- _ = shapely.from_wkb(b"", on_invalid="fix")
- @pytest.mark.parametrize("geom", all_types)
- @pytest.mark.parametrize("use_hex", [False, True])
- @pytest.mark.parametrize("byte_order", [0, 1])
- def test_from_wkb_all_types(geom, use_hex, byte_order):
- if shapely.get_type_id(geom) == shapely.GeometryType.LINEARRING:
- pytest.skip("Linearrings are not preserved in WKB")
- wkb = shapely.to_wkb(geom, hex=use_hex, byte_order=byte_order)
- actual = shapely.from_wkb(wkb)
- assert_geometries_equal(actual, geom)
- @pytest.mark.parametrize("geom", all_types_z)
- @pytest.mark.parametrize("use_hex", [False, True])
- @pytest.mark.parametrize("byte_order", [0, 1])
- def test_from_wkb_all_types_z(geom, use_hex, byte_order):
- if shapely.get_type_id(geom) == shapely.GeometryType.LINEARRING:
- pytest.skip("Linearrings are not preserved in WKB")
- wkb = shapely.to_wkb(geom, hex=use_hex, byte_order=byte_order)
- actual = shapely.from_wkb(wkb)
- assert_geometries_equal(actual, geom)
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- @pytest.mark.parametrize("geom", all_types_m)
- @pytest.mark.parametrize("use_hex", [False, True])
- @pytest.mark.parametrize("byte_order", [0, 1])
- def test_from_wkb_all_types_m(geom, use_hex, byte_order):
- if shapely.get_type_id(geom) == shapely.GeometryType.LINEARRING:
- pytest.skip("Linearrings are not preserved in WKB")
- wkb = shapely.to_wkb(geom, hex=use_hex, byte_order=byte_order)
- actual = shapely.from_wkb(wkb)
- assert_geometries_equal(actual, geom)
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- @pytest.mark.parametrize("geom", all_types_zm)
- @pytest.mark.parametrize("use_hex", [False, True])
- @pytest.mark.parametrize("byte_order", [0, 1])
- def test_from_wkb_all_types_zm(geom, use_hex, byte_order):
- if shapely.get_type_id(geom) == shapely.GeometryType.LINEARRING:
- pytest.skip("Linearrings are not preserved in WKB")
- wkb = shapely.to_wkb(geom, hex=use_hex, byte_order=byte_order)
- actual = shapely.from_wkb(wkb)
- assert_geometries_equal(actual, geom)
- @pytest.mark.parametrize(
- "geom",
- (Point(), LineString(), Polygon(), GeometryCollection()),
- )
- def test_from_wkb_empty(geom):
- wkb = shapely.to_wkb(geom)
- geom = shapely.from_wkb(wkb)
- assert shapely.is_geometry(geom).all()
- assert shapely.is_empty(geom).all()
- assert shapely.to_wkb(geom) == wkb
- # WKB from https://github.com/libgeos/geos/blob/main/tests/unit/io/WKBReaderTest.cpp
- @pytest.mark.parametrize(
- "wkb",
- (
- # "CIRCULARSTRING(1 3,2 4,3 1)",
- "010800000003000000000000000000F03F0000000000000840000000000000004000000000000010400000000000000840000000000000F03F",
- # "COMPOUNDCURVE(CIRCULARSTRING(1 3,2 4,3 1),(3 1,0 0))",
- "01090000200E16000002000000010800000003000000000000000000F03F0000000000000840000000000000004000000000000010400000000000000840000000000000F03F0102000000020000000000000000000840000000000000F03F00000000000000000000000000000000",
- # "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,2 0,2 1,2 3,4 3),(4 3,4 5,1 4,0 0)),CIRCULARSTRING(1.7 1,1.4 0.4,1.6 0.4,1.6 0.5,1.7 1))", # noqa: E501
- "010A0000200E1600000200000001090000000200000001080000000500000000000000000000000000000000000000000000000000004000000000000000000000000000000040000000000000F03F00000000000000400000000000000840000000000000104000000000000008400102000000040000000000000000001040000000000000084000000000000010400000000000001440000000000000F03F000000000000104000000000000000000000000000000000010800000005000000333333333333FB3F000000000000F03F666666666666F63F9A9999999999D93F9A9999999999F93F9A9999999999D93F9A9999999999F93F000000000000E03F333333333333FB3F000000000000F03F",
- # "MULTICURVE((0 0,5 5),COMPOUNDCURVE((-1 -1,0 0),CIRCULARSTRING(0 0,1 1,2 0)),CIRCULARSTRING(4 0,4 4,8 4))", # noqa: E501
- "010B000000030000000102000000020000000000000000000000000000000000000000000000000014400000000000001440010900000002000000010200000002000000000000000000F0BF000000000000F0BF0000000000000000000000000000000001080000000300000000000000000000000000000000000000000000000000F03F000000000000F03F00000000000000400000000000000000010800000003000000000000000000104000000000000000000000000000001040000000000000104000000000000020400000000000001040",
- # "MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1)),((10 10,14 12,11 10,10 10),(11 11,11.5 11,11 11.5,11 11)))", # noqa: E501
- "010C00000002000000010A000000020000000108000000050000000000000000000000000000000000000000000000000010400000000000000000000000000000104000000000000010400000000000000000000000000000104000000000000000000000000000000000010200000004000000000000000000F03F000000000000F03F000000000000084000000000000008400000000000000840000000000000F03F000000000000F03F000000000000F03F01030000000200000004000000000000000000244000000000000024400000000000002C40000000000000284000000000000026400000000000002440000000000000244000000000000024400400000000000000000026400000000000002640000000000000274000000000000026400000000000002640000000000000274000000000000026400000000000002640",
- ),
- )
- def test_from_wkb_nonlinear_unsupported(wkb):
- if shapely.geos_version >= (3, 13, 0):
- with pytest.raises(
- NotImplementedError,
- match="Nonlinear geometry types are not currently supported",
- ):
- shapely.from_wkb(wkb)
- else:
- # prior to GEOS 3.13 nonlinear types were rejected by GEOS on read from WKB
- with pytest.raises(shapely.errors.GEOSException, match="Unknown WKB type"):
- shapely.from_wkb(wkb)
- def test_to_wkt():
- point = shapely.points(1, 1)
- actual = shapely.to_wkt(point)
- assert actual == "POINT (1 1)"
- actual = shapely.to_wkt(point, trim=False)
- assert actual == "POINT (1.000000 1.000000)"
- actual = shapely.to_wkt(point, rounding_precision=3, trim=False)
- assert actual == "POINT (1.000 1.000)"
- def test_to_wkt_z():
- point = shapely.points(1, 2, 3)
- assert shapely.to_wkt(point) == "POINT Z (1 2 3)"
- assert shapely.to_wkt(point, output_dimension=2) == "POINT (1 2)"
- assert shapely.to_wkt(point, output_dimension=3) == "POINT Z (1 2 3)"
- assert shapely.to_wkt(point, old_3d=True) == "POINT (1 2 3)"
- if shapely.geos_version >= (3, 12, 0):
- assert shapely.to_wkt(point, output_dimension=4) == "POINT Z (1 2 3)"
- def test_to_wkt_m():
- point = shapely.from_wkt("POINT M (1 2 4)")
- assert shapely.to_wkt(point, output_dimension=2) == "POINT (1 2)"
- if shapely.geos_version < (3, 12, 0):
- # previous behavior was to incorrectly parse M as Z
- assert shapely.to_wkt(point) == "POINT Z (1 2 4)"
- assert shapely.to_wkt(point, output_dimension=3) == "POINT Z (1 2 4)"
- assert shapely.to_wkt(point, old_3d=True) == "POINT (1 2 4)"
- else:
- assert shapely.to_wkt(point) == "POINT M (1 2 4)"
- assert shapely.to_wkt(point, output_dimension=3) == "POINT M (1 2 4)"
- assert shapely.to_wkt(point, output_dimension=4) == "POINT M (1 2 4)"
- assert shapely.to_wkt(point, old_3d=True) == "POINT M (1 2 4)"
- def test_to_wkt_zm():
- point = shapely.from_wkt("POINT ZM (1 2 3 4)")
- assert shapely.to_wkt(point, output_dimension=2) == "POINT (1 2)"
- assert shapely.to_wkt(point, output_dimension=3) == "POINT Z (1 2 3)"
- if shapely.geos_version < (3, 12, 0):
- # previous behavior was to parse and ignore M
- assert shapely.to_wkt(point) == "POINT Z (1 2 3)"
- assert shapely.to_wkt(point, old_3d=True) == "POINT (1 2 3)"
- else:
- assert shapely.to_wkt(point) == "POINT ZM (1 2 3 4)"
- assert shapely.to_wkt(point, output_dimension=4) == "POINT ZM (1 2 3 4)"
- assert shapely.to_wkt(point, old_3d=True) == "POINT (1 2 3 4)"
- def test_to_wkt_none():
- # None propagates
- assert shapely.to_wkt(None) is None
- def test_to_wkt_array_with_empty_z():
- # See GH-2004
- empty_wkt = ["POINT Z EMPTY", None, "POLYGON Z EMPTY"]
- empty_geoms = shapely.from_wkt(empty_wkt)
- assert list(shapely.to_wkt(empty_geoms)) == empty_wkt
- def test_to_wkt_exceptions():
- with pytest.raises(TypeError):
- shapely.to_wkt(1)
- with pytest.raises(shapely.GEOSException):
- shapely.to_wkt(point, output_dimension=5)
- def test_to_wkt_point_empty():
- assert shapely.to_wkt(empty_point) == "POINT EMPTY"
- @pytest.mark.parametrize(
- "wkt",
- [
- "POINT Z EMPTY",
- "LINESTRING Z EMPTY",
- "LINEARRING Z EMPTY",
- "POLYGON Z EMPTY",
- ],
- )
- def test_to_wkt_empty_z(wkt):
- assert shapely.to_wkt(shapely.from_wkt(wkt)) == wkt
- def test_to_wkt_geometrycollection_with_point_empty():
- collection = shapely.geometrycollections([empty_point, point])
- # do not check the full value as some GEOS versions give
- # GEOMETRYCOLLECTION Z (...) and others give GEOMETRYCOLLECTION (...)
- assert shapely.to_wkt(collection).endswith("(POINT EMPTY, POINT (2 3))")
- def test_to_wkt_multipoint_with_point_empty():
- geom = shapely.multipoints([empty_point, point])
- if shapely.geos_version >= (3, 12, 0):
- expected = "MULTIPOINT (EMPTY, (2 3))"
- else:
- # invalid WKT form
- expected = "MULTIPOINT (EMPTY, 2 3)"
- assert shapely.to_wkt(geom) == expected
- @pytest.mark.parametrize("geom", [Point(1e100, 0), Point(0, 1e100)])
- def test_to_wkt_large_float_ok(geom):
- # https://github.com/shapely/shapely/issues/1903
- shapely.to_wkt(geom)
- assert "Exception in WKT writer" not in repr(geom)
- @pytest.mark.parametrize("geom", [Point(1e101, 0), Point(0, 1e101)])
- def test_to_wkt_large_float(geom):
- if shapely.geos_version >= (3, 13, 0):
- # round-trip WKT
- assert geom.equals(shapely.from_wkt(shapely.to_wkt(geom)))
- else:
- # https://github.com/shapely/shapely/issues/1903
- with pytest.raises(
- ValueError, match="WKT output of coordinates greater than.*"
- ):
- shapely.to_wkt(geom)
- assert "Exception in WKT writer" in repr(geom)
- @pytest.mark.parametrize(
- "geom",
- [
- # We implemented our own "GetZMax", so go through all geometry types:
- Point(0, 0, 1e101),
- LineString([(0, 0, 0), (0, 0, 1e101)]),
- LinearRing([(0, 0, 0), (0, 1, 0), (1, 0, 1e101), (0, 0, 0)]),
- Polygon([(0, 0, 0), (0, 1, 0), (1, 0, 1e101), (0, 0, 0)]),
- Polygon(
- [(0, 0, 0), (0, 10, 0), (10, 0, 0), (0, 0, 0)],
- [[(0, 0, 0), (0, 1, 0), (1, 0, 1e101), (0, 0, 0)]],
- ),
- MultiPoint([(0, 0, 0), (0, 0, 1e101)]),
- MultiLineString(
- [LineString([(0, 0, 0), (0, 1, 0)]), LineString([(0, 0, 0), (0, 1, 1e101)])]
- ),
- MultiPolygon(
- [polygon_z, Polygon([(0, 0, 0), (0, 1, 0), (1, 0, 1e101), (0, 0, 0)])]
- ),
- GeometryCollection([point_z, Point(0, 0, 1e101)]),
- GeometryCollection([GeometryCollection([Point(0, 0, 1e101)])]),
- LineString([(0, 0, np.nan), (0, 0, 1e101)]),
- Polygon([(0, 0, np.nan), (0, 1, 0), (1, 0, 1e101), (0, 0, 0)]),
- GeometryCollection([Point(0, 0), Point(0, 0, 1e101)]),
- ],
- )
- def test_to_wkt_large_float_3d_no_crash(geom):
- # https://github.com/shapely/shapely/issues/1903
- # just test if there is a crash (detailed behaviour differs per GEOS version)
- try:
- shapely.to_wkt(geom)
- except ValueError as e:
- assert str(e).startswith("WKT output of coordinates greater than")
- repr(geom)
- def test_to_wkt_large_float_skip_z():
- # https://github.com/shapely/shapely/issues/1903
- assert shapely.to_wkt(Point(0, 0, 1e101), output_dimension=2) == "POINT (0 0)"
- def test_to_wkt_large_float_no_trim():
- # https://github.com/shapely/shapely/issues/1903
- # don't test the exact number, it is ridiculously large and probably platform
- # dependent
- assert shapely.to_wkt(Point(1e101, 0), trim=False).startswith("POINT (")
- def test_repr():
- assert repr(point) == "<POINT (2 3)>"
- assert repr(point_z) == "<POINT Z (2 3 4)>"
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- def test_repr_m():
- assert repr(point_m) == "<POINT M (2 3 5)>"
- assert repr(point_zm) == "<POINT ZM (2 3 4 5)>"
- def test_repr_max_length():
- # the repr is limited to 80 characters
- geom = shapely.linestrings(np.arange(1000), np.arange(1000))
- representation = repr(geom)
- assert len(representation) == 80
- assert representation.endswith("...>")
- def test_repr_point_z_empty():
- assert repr(empty_point_z) == "<POINT Z EMPTY>"
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- def test_repr_point_m_empty():
- assert repr(empty_point_m) == "<POINT M EMPTY>"
- assert repr(empty_point_zm) == "<POINT ZM EMPTY>"
- def test_to_wkb():
- point = shapely.points(1, 1)
- actual = shapely.to_wkb(point, byte_order=1)
- assert actual == POINT11_WKB
- def test_to_wkb_hex():
- point = shapely.points(1, 1)
- actual = shapely.to_wkb(point, hex=True, byte_order=1)
- le = "01"
- point_type = "01000000"
- coord = "000000000000F03F" # 1.0 as double (LE)
- assert actual == le + point_type + 2 * coord
- def test_to_wkb_z():
- point = shapely.points(1, 2, 3)
- expected_wkb = struct.pack("<BI2d", 1, 1, 1.0, 2.0)
- expected_wkb_z = struct.pack("<BI3d", 1, 1 | EWKBZ, 1.0, 2.0, 3.0)
- assert shapely.to_wkb(point, byte_order=1) == expected_wkb_z
- assert shapely.to_wkb(point, output_dimension=2, byte_order=1) == expected_wkb
- assert shapely.to_wkb(point, output_dimension=3, byte_order=1) == expected_wkb_z
- if shapely.geos_version >= (3, 12, 0):
- assert shapely.to_wkb(point, output_dimension=4, byte_order=1) == expected_wkb_z
- def test_to_wkb_m():
- # POINT M (1 2 4)
- point = shapely.from_wkb(struct.pack("<BI3d", 1, 1 | EWKBM, 1.0, 2.0, 4.0))
- expected_wkb = struct.pack("<BI2d", 1, 1, 1.0, 2.0)
- expected_wkb_m = struct.pack("<BI3d", 1, 1 | EWKBM, 1.0, 2.0, 4.0)
- if shapely.geos_version < (3, 12, 0):
- # previous behavior was to ignore M, treat as 2D
- expected_wkb_m = expected_wkb
- assert shapely.to_wkb(point, byte_order=1) == expected_wkb_m
- assert shapely.to_wkb(point, output_dimension=2, byte_order=1) == expected_wkb
- assert shapely.to_wkb(point, output_dimension=3, byte_order=1) == expected_wkb_m
- if shapely.geos_version >= (3, 12, 0):
- assert shapely.to_wkb(point, output_dimension=4, byte_order=1) == expected_wkb_m
- def test_to_wkb_zm():
- # POINT ZM (1 2 3 4)
- point = shapely.from_wkb(struct.pack("<BI4d", 1, 1 | EWKBZM, 1.0, 2.0, 3.0, 4.0))
- expected_wkb = struct.pack("<BI2d", 1, 1, 1.0, 2.0)
- expected_wkb_z = struct.pack("<BI3d", 1, 1 | EWKBZ, 1.0, 2.0, 3.0)
- expected_wkb_zm = struct.pack("<BI4d", 1, 1 | EWKBZM, 1.0, 2.0, 3.0, 4.0)
- if shapely.geos_version < (3, 12, 0):
- # previous behavior was to ignore M, treat as XYZ
- expected_wkb_zm = expected_wkb_z
- assert shapely.to_wkb(point, byte_order=1) == expected_wkb_zm
- assert shapely.to_wkb(point, output_dimension=2, byte_order=1) == expected_wkb
- assert shapely.to_wkb(point, output_dimension=3, byte_order=1) == expected_wkb_z
- if shapely.geos_version >= (3, 12, 0):
- assert (
- shapely.to_wkb(point, output_dimension=4, byte_order=1) == expected_wkb_zm
- )
- def test_to_wkb_none():
- # None propagates
- assert shapely.to_wkb(None) is None
- def test_to_wkb_exceptions():
- with pytest.raises(TypeError):
- shapely.to_wkb(1)
- with pytest.raises(shapely.GEOSException):
- shapely.to_wkb(point, output_dimension=5)
- with pytest.raises(ValueError):
- shapely.to_wkb(point, flavor="other")
- def test_to_wkb_byte_order():
- point = shapely.points(1.0, 1.0)
- be = b"\x00"
- le = b"\x01"
- point_type = b"\x01\x00\x00\x00" # 1 as 32-bit uint (LE)
- coord = b"\x00\x00\x00\x00\x00\x00\xf0?" # 1.0 as double (LE)
- assert shapely.to_wkb(point, byte_order=1) == le + point_type + 2 * coord
- assert (
- shapely.to_wkb(point, byte_order=0) == be + point_type[::-1] + 2 * coord[::-1]
- )
- def test_to_wkb_srid():
- # hex representation of POINT (0 0) with SRID=4
- ewkb = "01010000200400000000000000000000000000000000000000"
- wkb = "010100000000000000000000000000000000000000"
- actual = shapely.from_wkb(ewkb)
- assert shapely.to_wkt(actual, trim=True) == "POINT (0 0)"
- assert shapely.to_wkb(actual, hex=True, byte_order=1) == wkb
- assert shapely.to_wkb(actual, hex=True, include_srid=True, byte_order=1) == ewkb
- point = shapely.points(1, 1)
- point_with_srid = shapely.set_srid(point, np.int32(4326))
- result = shapely.to_wkb(point_with_srid, include_srid=True, byte_order=1)
- assert np.frombuffer(result[5:9], "<u4").item() == 4326
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10.0")
- def test_to_wkb_flavor():
- # http://libgeos.org/specifications/wkb/#extended-wkb
- actual = shapely.to_wkb(point_z, byte_order=1) # default "extended"
- assert actual.hex()[2:10] == struct.pack("<I", 1 | EWKBZ).hex()
- actual = shapely.to_wkb(point_z, byte_order=1, flavor="extended")
- assert actual.hex()[2:10] == struct.pack("<I", 1 | EWKBZ).hex()
- actual = shapely.to_wkb(point_z, byte_order=1, flavor="iso")
- assert actual.hex()[2:10] == struct.pack("<I", 1 | ISOWKBZ).hex()
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- def test_to_wkb_m_flavor():
- # XYM
- actual = shapely.to_wkb(point_m, byte_order=1) # default "extended"
- assert actual.hex()[2:10] == struct.pack("<I", 1 | EWKBM).hex()
- actual = shapely.to_wkb(point_m, byte_order=1, flavor="iso")
- assert actual.hex()[2:10] == struct.pack("<I", 1 | ISOWKBM).hex()
- # XYZM
- actual = shapely.to_wkb(point_zm, byte_order=1) # default "extended"
- assert actual.hex()[2:10] == struct.pack("<I", 1 | EWKBZM).hex()
- actual = shapely.to_wkb(point_zm, byte_order=1, flavor="iso")
- assert actual.hex()[2:10] == struct.pack("<I", 1 | ISOWKBZM).hex()
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10.0")
- def test_to_wkb_flavor_srid():
- with pytest.raises(ValueError, match="cannot be used together"):
- shapely.to_wkb(point_z, include_srid=True, flavor="iso")
- @pytest.mark.skipif(shapely.geos_version >= (3, 10, 0), reason="GEOS < 3.10.0")
- def test_to_wkb_flavor_unsupported_geos():
- with pytest.raises(UnsupportedGEOSVersionError):
- shapely.to_wkb(point_z, flavor="iso")
- @pytest.mark.parametrize(
- "geom,expected",
- [
- pytest.param(empty_point, POINT_NAN_WKB, id="POINT EMPTY"),
- pytest.param(empty_point_z, POINT_NAN_WKB, id="POINT Z EMPTY"),
- pytest.param(empty_point_m, POINT_NAN_WKB, id="POINT M EMPTY"),
- pytest.param(empty_point_zm, POINT_NAN_WKB, id="POINT ZM EMPTY"),
- pytest.param(
- multi_point_empty,
- MULTIPOINT_NAN_WKB,
- id="MULTIPOINT EMPTY",
- ),
- pytest.param(
- multi_point_empty_z,
- MULTIPOINT_NAN_WKB,
- id="MULTIPOINT Z EMPTY",
- ),
- pytest.param(
- multi_point_empty_m,
- MULTIPOINT_NAN_WKB,
- id="MULTIPOINT M EMPTY",
- ),
- pytest.param(
- multi_point_empty_zm,
- MULTIPOINT_NAN_WKB,
- id="MULTIPOINT ZM EMPTY",
- ),
- pytest.param(
- shapely.geometrycollections([empty_point]),
- GEOMETRYCOLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([empty_point_z]),
- GEOMETRYCOLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT Z EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([empty_point_m]),
- GEOMETRYCOLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT M EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([empty_point_zm]),
- GEOMETRYCOLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT ZM EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty]),
- NESTED_COLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty_z]),
- NESTED_COLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT Z EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty_m]),
- NESTED_COLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT M EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty_zm]),
- NESTED_COLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT ZM EMPTY)",
- ),
- ],
- )
- def test_to_wkb_point_empty_2d(geom, expected):
- actual = shapely.to_wkb(geom, output_dimension=2, byte_order=1)
- # Split 'actual' into header and coordinates
- coordinate_length = 16
- header_length = len(expected) - coordinate_length
- # Check the total length (this checks the correct dimensionality)
- assert len(actual) == header_length + coordinate_length
- # Check the header
- assert actual[:header_length] == expected[:header_length]
- # Check the coordinates (using numpy.isnan; there are many byte representations for
- # NaN)
- assert np.isnan(struct.unpack("<2d", actual[header_length:])).all()
- @pytest.mark.parametrize(
- "geom,expected",
- [
- pytest.param(empty_point_z, POINTZ_NAN_WKB, id="POINT Z EMPTY"),
- pytest.param(empty_point_zm, POINTZ_NAN_WKB, id="POINT ZM EMPTY"),
- pytest.param(
- multi_point_empty_z,
- MULTIPOINTZ_NAN_WKB,
- id="MULTIPOINT Z EMPTY",
- ),
- pytest.param(
- multi_point_empty_zm,
- MULTIPOINTZ_NAN_WKB,
- id="MULTIPOINT ZM EMPTY",
- ),
- pytest.param(
- shapely.geometrycollections([empty_point_z]),
- GEOMETRYCOLLECTIONZ_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT Z EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([empty_point_zm]),
- GEOMETRYCOLLECTIONZ_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT ZM EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty_z]),
- NESTED_COLLECTIONZ_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT Z EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty_zm]),
- NESTED_COLLECTIONZ_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT ZM EMPTY)",
- ),
- ],
- )
- def test_to_wkb_point_empty_z(geom, expected):
- actual = shapely.to_wkb(geom, output_dimension=3, byte_order=1)
- # Split 'actual' into header and coordinates
- coordinate_length = 8 * 3
- header_length = len(expected) - coordinate_length
- # Check the total length (this checks the correct dimensionality)
- assert len(actual) == header_length + coordinate_length
- # Check the header
- assert actual[:header_length] == expected[:header_length]
- # Check the coordinates (using numpy.isnan; there are many byte representations for
- # NaN)
- assert np.isnan(struct.unpack("<3d", actual[header_length:])).all()
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- @pytest.mark.parametrize(
- "geom,expected",
- [
- pytest.param(empty_point_m, POINTM_NAN_WKB, id="POINT M EMPTY"),
- pytest.param(
- multi_point_empty_m,
- MULTIPOINTM_NAN_WKB,
- id="MULTIPOINT M EMPTY",
- ),
- pytest.param(
- shapely.geometrycollections([empty_point_m]),
- GEOMETRYCOLLECTIONM_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT M EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty_m]),
- NESTED_COLLECTIONM_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT M EMPTY)",
- ),
- ],
- )
- def test_to_wkb_point_empty_m(geom, expected):
- actual = shapely.to_wkb(geom, output_dimension=3, byte_order=1)
- # Split 'actual' into header and coordinates
- coordinate_length = 8 * 3
- header_length = len(expected) - coordinate_length
- assert len(actual) == header_length + coordinate_length
- assert actual[:header_length] == expected[:header_length]
- assert np.isnan(struct.unpack("<3d", actual[header_length:])).all()
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- @pytest.mark.parametrize(
- "geom,expected",
- [
- pytest.param(empty_point_zm, POINTZM_NAN_WKB, id="POINT ZM EMPTY"),
- pytest.param(
- multi_point_empty_zm,
- MULTIPOINTZM_NAN_WKB,
- id="MULTIPOINT ZM EMPTY",
- ),
- pytest.param(
- shapely.geometrycollections([empty_point_zm]),
- GEOMETRYCOLLECTIONZM_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT ZM EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty_zm]),
- NESTED_COLLECTIONZM_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT ZM EMPTY)",
- ),
- ],
- )
- def test_to_wkb_point_empty_zm(geom, expected):
- actual = shapely.to_wkb(geom, output_dimension=4, byte_order=1)
- # Split 'actual' into header and coordinates
- coordinate_length = 8 * 4
- header_length = len(expected) - coordinate_length
- assert len(actual) == header_length + coordinate_length
- assert actual[:header_length] == expected[:header_length]
- assert np.isnan(struct.unpack("<4d", actual[header_length:])).all()
- @pytest.mark.parametrize(
- "geom,expected",
- [
- pytest.param(empty_point, POINT_NAN_WKB, id="POINT EMPTY"),
- pytest.param(multi_point_empty, MULTIPOINT_NAN_WKB, id="MULTIPOINT EMPTY"),
- pytest.param(
- shapely.geometrycollections([empty_point]),
- GEOMETRYCOLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (POINT EMPTY)",
- ),
- pytest.param(
- shapely.geometrycollections([multi_point_empty]),
- NESTED_COLLECTION_NAN_WKB,
- id="GEOMETRYCOLLECTION (MULTIPOINT EMPTY)",
- ),
- ],
- )
- def test_to_wkb_point_empty_2d_output_dim_3(geom, expected):
- actual = shapely.to_wkb(geom, output_dimension=3, byte_order=1)
- # Split 'actual' into header and coordinates
- coordinate_length = 16
- header_length = len(expected) - coordinate_length
- # Check the total length (this checks the correct dimensionality)
- assert len(actual) == header_length + coordinate_length
- # Check the header
- assert actual[:header_length] == expected[:header_length]
- # Check the coordinates (using numpy.isnan; there are many byte representations for
- # NaN)
- assert np.isnan(struct.unpack("<2d", actual[header_length:])).all()
- @pytest.mark.parametrize(
- "wkb,expected_type,expected_dim",
- [
- pytest.param(POINT_NAN_WKB, 0, 2, id="POINT_NAN_WKB"),
- pytest.param(POINTZ_NAN_WKB, 0, 3, id="POINTZ_NAN_WKB"),
- pytest.param(MULTIPOINT_NAN_WKB, 4, 2, id="MULTIPOINT_NAN_WKB"),
- pytest.param(MULTIPOINTZ_NAN_WKB, 4, 3, id="MULTIPOINTZ_NAN_WKB"),
- pytest.param(GEOMETRYCOLLECTION_NAN_WKB, 7, 2, id="GEOMETRYCOLLECTION_NAN_WKB"),
- pytest.param(
- GEOMETRYCOLLECTIONZ_NAN_WKB, 7, 3, id="GEOMETRYCOLLECTIONZ_NAN_WKB"
- ),
- pytest.param(NESTED_COLLECTION_NAN_WKB, 7, 2, id="NESTED_COLLECTION_NAN_WKB"),
- pytest.param(NESTED_COLLECTIONZ_NAN_WKB, 7, 3, id="NESTED_COLLECTIONZ_NAN_WKB"),
- ],
- )
- def test_from_wkb_point_empty(wkb, expected_type, expected_dim):
- geom = shapely.from_wkb(wkb)
- # POINT (nan nan) transforms to an empty point
- assert shapely.is_empty(geom)
- assert shapely.get_type_id(geom) == expected_type
- assert shapely.get_coordinate_dimension(geom) == expected_dim
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- @pytest.mark.parametrize(
- "wkb,expected_type",
- [
- pytest.param(POINTM_NAN_WKB, 0, id="POINTM_NAN_WKB"),
- pytest.param(MULTIPOINTM_NAN_WKB, 4, id="MULTIPOINTM_NAN_WKB"),
- pytest.param(GEOMETRYCOLLECTIONM_NAN_WKB, 7, id="GEOMETRYCOLLECTIONM_NAN_WKB"),
- pytest.param(NESTED_COLLECTIONM_NAN_WKB, 7, id="NESTED_COLLECTIONM_NAN_WKB"),
- ],
- )
- def test_from_wkb_point_empty_m(wkb, expected_type):
- geom = shapely.from_wkb(wkb)
- assert shapely.is_empty(geom)
- assert shapely.get_type_id(geom) == expected_type
- assert shapely.get_coordinate_dimension(geom) == 3
- assert not shapely.has_z(geom)
- assert shapely.has_m(geom)
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- @pytest.mark.parametrize(
- "wkb,expected_type",
- [
- pytest.param(POINTZM_NAN_WKB, 0, id="POINTZM_NAN_WKB"),
- pytest.param(MULTIPOINTZM_NAN_WKB, 4, id="MULTIPOINTZM_NAN_WKB"),
- pytest.param(
- GEOMETRYCOLLECTIONZM_NAN_WKB, 7, id="GEOMETRYCOLLECTIONZM_NAN_WKB"
- ),
- pytest.param(NESTED_COLLECTIONZM_NAN_WKB, 7, id="NESTED_COLLECTIONZM_NAN_WKB"),
- ],
- )
- def test_from_wkb_point_empty_zm(wkb, expected_type):
- geom = shapely.from_wkb(wkb)
- assert shapely.is_empty(geom)
- assert shapely.get_type_id(geom) == expected_type
- assert shapely.get_coordinate_dimension(geom) == 4
- assert shapely.has_z(geom)
- assert shapely.has_m(geom)
- def test_to_wkb_point_empty_srid():
- expected = shapely.set_srid(empty_point, 4236)
- wkb = shapely.to_wkb(expected, include_srid=True)
- actual = shapely.from_wkb(wkb)
- assert shapely.get_srid(actual) == 4236
- @pytest.mark.parametrize("geom", all_types + (point_z, empty_point))
- def test_pickle(geom):
- pickled = pickle.dumps(geom)
- assert_geometries_equal(pickle.loads(pickled), geom, tolerance=0)
- @pytest.mark.parametrize("geom", all_types_z)
- def test_pickle_z(geom):
- pickled = pickle.dumps(geom)
- actual = pickle.loads(pickled)
- assert_geometries_equal(actual, geom, tolerance=0)
- if not actual.is_empty: # GEOSHasZ with EMPTY geometries is inconsistent
- assert actual.has_z
- if shapely.geos_version >= (3, 12, 0):
- assert not actual.has_m
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- @pytest.mark.parametrize("geom", all_types_m)
- def test_pickle_m(geom):
- pickled = pickle.dumps(geom)
- actual = pickle.loads(pickled)
- assert_geometries_equal(actual, geom, tolerance=0)
- assert not actual.has_z
- if not actual.is_empty: # GEOSHasM with EMPTY geometries is inconsistent
- assert actual.has_m
- @pytest.mark.skipif(
- shapely.geos_version < (3, 12, 0),
- reason="M coordinates not supported with GEOS < 3.12",
- )
- @pytest.mark.parametrize("geom", all_types_zm)
- def test_pickle_zm(geom):
- pickled = pickle.dumps(geom)
- actual = pickle.loads(pickled)
- assert_geometries_equal(actual, geom, tolerance=0)
- if not actual.is_empty: # GEOSHasZ with EMPTY geometries is inconsistent
- assert actual.has_z
- assert actual.has_m
- @pytest.mark.parametrize("geom", all_types + (point_z, empty_point))
- def test_pickle_with_srid(geom):
- geom = shapely.set_srid(geom, 4326)
- pickled = pickle.dumps(geom)
- assert shapely.get_srid(pickle.loads(pickled)) == 4326
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 1), reason="GEOS < 3.10.1")
- @pytest.mark.parametrize(
- "geojson,expected",
- [
- pytest.param(
- GEOJSON_GEOMETRY, GEOJSON_GEOMETRY_EXPECTED, id="GEOJSON_GEOMETRY"
- ),
- pytest.param(GEOJSON_FEATURE, GEOJSON_GEOMETRY_EXPECTED, id="GEOJSON_FEATURE"),
- pytest.param(
- GEOJSON_FEATURECOLECTION,
- shapely.geometrycollections(GEOJSON_COLLECTION_EXPECTED),
- id="GEOJSON_FEATURECOLECTION",
- ),
- pytest.param(
- [GEOJSON_GEOMETRY] * 2,
- [GEOJSON_GEOMETRY_EXPECTED] * 2,
- id="GEOJSON_GEOMETRYx2",
- ),
- pytest.param(None, None, id="None"),
- pytest.param(
- [GEOJSON_GEOMETRY, None],
- [GEOJSON_GEOMETRY_EXPECTED, None],
- id="GEOJSON_GEOMETRY_None",
- ),
- ],
- )
- def test_from_geojson(geojson, expected):
- actual = shapely.from_geojson(geojson)
- assert_geometries_equal(actual, expected)
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 1), reason="GEOS < 3.10.1")
- def test_from_geojson_exceptions():
- with pytest.raises(TypeError, match="Expected bytes or string, got int"):
- shapely.from_geojson(1)
- with pytest.raises(shapely.GEOSException, match="Error parsing JSON"):
- shapely.from_geojson("")
- with pytest.raises(shapely.GEOSException, match="Unknown geometry type"):
- shapely.from_geojson('{"type": "NoGeometry", "coordinates": []}')
- with pytest.raises(shapely.GEOSException, match="type must be array, but is null"):
- shapely.from_geojson('{"type": "LineString", "coordinates": null}')
- # Note: The two below tests are the reason that from_geojson is disabled for
- # GEOS 3.10.0 See https://trac.osgeo.org/geos/ticket/1138
- with pytest.raises(shapely.GEOSException, match="key 'type' not found"):
- shapely.from_geojson('{"geometry": null, "properties": []}')
- with pytest.raises(shapely.GEOSException, match="key 'type' not found"):
- shapely.from_geojson('{"no": "geojson"}')
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 1), reason="GEOS < 3.10.1")
- def test_from_geojson_warn_on_invalid():
- with pytest.warns(Warning, match="Invalid GeoJSON"):
- assert shapely.from_geojson("", on_invalid="warn") is None
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 1), reason="GEOS < 3.10.1")
- def test_from_geojson_ignore_on_invalid():
- with warnings.catch_warnings():
- warnings.simplefilter("error")
- assert shapely.from_geojson("", on_invalid="ignore") is None
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 1), reason="GEOS < 3.10.1")
- def test_from_geojson_on_invalid_unsupported_option():
- with pytest.raises(ValueError, match="not a valid option"):
- shapely.from_geojson(GEOJSON_GEOMETRY, on_invalid="unsupported_option")
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10")
- @pytest.mark.parametrize(
- "expected,geometry",
- [
- pytest.param(
- GEOJSON_GEOMETRY, GEOJSON_GEOMETRY_EXPECTED, id="GEOJSON_GEOMETRY"
- ),
- pytest.param(
- [GEOJSON_GEOMETRY] * 2,
- [GEOJSON_GEOMETRY_EXPECTED] * 2,
- id="GEOJSON_GEOMETRYx2",
- ),
- pytest.param(None, None, id="None"),
- pytest.param(
- [GEOJSON_GEOMETRY, None],
- [GEOJSON_GEOMETRY_EXPECTED, None],
- id="GEOJSON_GEOMETRY_None",
- ),
- ],
- )
- def test_to_geojson(geometry, expected):
- actual = shapely.to_geojson(geometry, indent=4)
- assert np.all(actual == np.asarray(expected))
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10")
- @pytest.mark.parametrize("indent", [None, 0, 4])
- def test_to_geojson_indent(indent):
- separators = (",", ":") if indent is None else (",", ": ")
- expected = json.dumps(
- json.loads(GEOJSON_GEOMETRY), indent=indent, separators=separators
- )
- actual = shapely.to_geojson(GEOJSON_GEOMETRY_EXPECTED, indent=indent)
- assert actual == expected
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10")
- def test_to_geojson_exceptions():
- with pytest.raises(TypeError):
- shapely.to_geojson(1)
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 2), reason="GEOS < 3.10.2")
- @pytest.mark.parametrize(
- "geom",
- [
- empty_point,
- shapely.multipoints([empty_point, point]),
- shapely.geometrycollections([empty_point, point]),
- shapely.geometrycollections(
- [shapely.geometrycollections([empty_point]), point]
- ),
- ],
- )
- def test_to_geojson_point_empty(geom):
- assert geom.equals(shapely.from_geojson(shapely.to_geojson(geom)))
- @pytest.mark.skipif(shapely.geos_version < (3, 10, 1), reason="GEOS < 3.10.1")
- @pytest.mark.parametrize("geom", all_types)
- def test_geojson_all_types(geom):
- type_id = shapely.get_type_id(geom)
- if type_id == shapely.GeometryType.LINEARRING:
- pytest.skip("Linearrings are not preserved in GeoJSON")
- elif (
- geom.is_empty
- and type_id == shapely.GeometryType.POINT
- and shapely.geos_version < (3, 10, 2)
- ):
- pytest.skip("GEOS < 3.10.2 with POINT EMPTY") # TRAC-1139
- geojson = shapely.to_geojson(geom)
- actual = shapely.from_geojson(geojson)
- assert not actual.has_z
- geoms_are_empty = shapely.is_empty([geom, actual])
- if geoms_are_empty.any():
- # Ensure both are EMPTY
- assert geoms_are_empty.all()
- else:
- assert_geometries_equal(actual, geom)
|