| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- import binascii
- import math
- import struct
- import sys
- import pytest
- from shapely import wkt
- from shapely.geometry import Point
- from shapely.tests.legacy.conftest import shapely20_todo
- from shapely.wkb import dump, dumps, load, loads
- @pytest.fixture(scope="module")
- def some_point():
- return Point(1.2, 3.4)
- def bin2hex(value):
- return binascii.b2a_hex(value).upper().decode("utf-8")
- def hex2bin(value):
- return binascii.a2b_hex(value)
- def hostorder(fmt, value):
- """Re-pack a hex WKB value to native endianness if needed
- This routine does not understand WKB format, so it must be provided a
- struct module format string, without initial indicator character ("@=<>!"),
- which will be interpreted as big- or little-endian with standard sizes
- depending on the endian flag in the first byte of the value.
- """
- if fmt and fmt[0] in "@=<>!":
- raise ValueError("Initial indicator character, one of @=<>!, in fmt")
- if not fmt or fmt[0] not in "cbB":
- raise ValueError("Missing endian flag in fmt")
- (hexendian,) = struct.unpack(fmt[0], hex2bin(value[:2]))
- hexorder = {0: ">", 1: "<"}[hexendian]
- sysorder = {"little": "<", "big": ">"}[sys.byteorder]
- if hexorder == sysorder:
- return value # Nothing to do
- return bin2hex(
- struct.pack(
- sysorder + fmt,
- {">": 0, "<": 1}[sysorder],
- *struct.unpack(hexorder + fmt, hex2bin(value))[1:],
- )
- )
- def test_dumps_srid(some_point):
- result = dumps(some_point)
- assert bin2hex(result) == hostorder(
- "BIdd", "0101000000333333333333F33F3333333333330B40"
- )
- result = dumps(some_point, srid=4326)
- assert bin2hex(result) == hostorder(
- "BIIdd", "0101000020E6100000333333333333F33F3333333333330B40"
- )
- def test_dumps_endianness(some_point):
- result = dumps(some_point)
- assert bin2hex(result) == hostorder(
- "BIdd", "0101000000333333333333F33F3333333333330B40"
- )
- result = dumps(some_point, big_endian=False)
- assert bin2hex(result) == "0101000000333333333333F33F3333333333330B40"
- result = dumps(some_point, big_endian=True)
- assert bin2hex(result) == "00000000013FF3333333333333400B333333333333"
- def test_dumps_hex(some_point):
- result = dumps(some_point, hex=True)
- assert result == hostorder("BIdd", "0101000000333333333333F33F3333333333330B40")
- def test_loads_srid():
- # load a geometry which includes an srid
- geom = loads(hex2bin("0101000020E6100000333333333333F33F3333333333330B40"))
- assert isinstance(geom, Point)
- assert geom.coords[:] == [(1.2, 3.4)]
- # by default srid is not exported
- result = dumps(geom)
- assert bin2hex(result) == hostorder(
- "BIdd", "0101000000333333333333F33F3333333333330B40"
- )
- # include the srid in the output
- result = dumps(geom, include_srid=True)
- assert bin2hex(result) == hostorder(
- "BIIdd", "0101000020E6100000333333333333F33F3333333333330B40"
- )
- # replace geometry srid with another
- result = dumps(geom, srid=27700)
- assert bin2hex(result) == hostorder(
- "BIIdd", "0101000020346C0000333333333333F33F3333333333330B40"
- )
- def test_loads_hex(some_point):
- assert loads(dumps(some_point, hex=True), hex=True) == some_point
- def test_dump_load_binary(some_point, tmpdir):
- file = tmpdir.join("test.wkb")
- with open(file, "wb") as file_pointer:
- dump(some_point, file_pointer)
- with open(file, "rb") as file_pointer:
- restored = load(file_pointer)
- assert some_point == restored
- def test_dump_load_hex(some_point, tmpdir):
- file = tmpdir.join("test.wkb")
- with open(file, "w") as file_pointer:
- dump(some_point, file_pointer, hex=True)
- with open(file) as file_pointer:
- restored = load(file_pointer, hex=True)
- assert some_point == restored
- # pygeos handles both bytes and str
- @shapely20_todo
- def test_dump_hex_load_binary(some_point, tmpdir):
- """Asserts that reading a binary file as text (hex mode) fails."""
- file = tmpdir.join("test.wkb")
- with open(file, "w") as file_pointer:
- dump(some_point, file_pointer, hex=True)
- with pytest.raises(TypeError):
- with open(file, "rb") as file_pointer:
- load(file_pointer)
- def test_dump_binary_load_hex(some_point, tmpdir):
- """Asserts that reading a text file (hex mode) as binary fails."""
- file = tmpdir.join("test.wkb")
- with open(file, "wb") as file_pointer:
- dump(some_point, file_pointer)
- # TODO(shapely-2.0) on windows this doesn't seem to error with pygeos,
- # but you get back a point with garbage coordinates
- if sys.platform == "win32":
- with open(file) as file_pointer:
- restored = load(file_pointer, hex=True)
- assert some_point != restored
- return
- with pytest.raises((UnicodeEncodeError, UnicodeDecodeError)):
- with open(file) as file_pointer:
- load(file_pointer, hex=True)
- def test_point_empty():
- g = wkt.loads("POINT EMPTY")
- result = dumps(g, big_endian=False)
- # Use math.isnan for second part of the WKB representation there are
- # many byte representations for NaN)
- assert result[: -2 * 8] == b"\x01\x01\x00\x00\x00"
- coords = struct.unpack("<2d", result[-2 * 8 :])
- assert len(coords) == 2
- assert all(math.isnan(val) for val in coords)
- def test_point_z_empty():
- g = wkt.loads("POINT Z EMPTY")
- assert g.wkb_hex == hostorder(
- "BIddd", "0101000080000000000000F87F000000000000F87F000000000000F87F"
- )
|