Fixed #26510 -- Allowed dim/trim/precision as WKTWriter init arguments

Thanks Tim Graham for the review.
This commit is contained in:
Claude Paroz 2016-04-16 10:50:24 +02:00
parent 05d08367d7
commit 10c53385f8
4 changed files with 56 additions and 14 deletions

View File

@ -408,7 +408,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
@property @property
def wkt(self): def wkt(self):
"Returns the WKT (Well-Known Text) representation of this Geometry." "Returns the WKT (Well-Known Text) representation of this Geometry."
return wkt_w(3 if self.hasz else 2).write(self).decode() return wkt_w(dim=3 if self.hasz else 2).write(self).decode()
@property @property
def hex(self): def hex(self):
@ -419,7 +419,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
""" """
# A possible faster, all-python, implementation: # A possible faster, all-python, implementation:
# str(self.wkb).encode('hex') # str(self.wkb).encode('hex')
return wkb_w(3 if self.hasz else 2).write_hex(self) return wkb_w(dim=3 if self.hasz else 2).write_hex(self)
@property @property
def hexewkb(self): def hexewkb(self):
@ -428,7 +428,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
extension of the WKB specification that includes SRID value that are extension of the WKB specification that includes SRID value that are
a part of this geometry. a part of this geometry.
""" """
return ewkb_w(3 if self.hasz else 2).write_hex(self) return ewkb_w(dim=3 if self.hasz else 2).write_hex(self)
@property @property
def json(self): def json(self):

View File

@ -170,6 +170,14 @@ class WKTWriter(IOBase):
_trim = False _trim = False
_precision = None _precision = None
def __init__(self, dim=2, trim=False, precision=None):
super(WKTWriter, self).__init__()
if bool(trim) != self._trim:
self.trim = trim
if precision is not None:
self.precision = precision
self.outdim = dim
def write(self, geom): def write(self, geom):
"Returns the WKT representation of the given geometry." "Returns the WKT representation of the given geometry."
return wkt_writer_write(self.ptr, geom.ptr) return wkt_writer_write(self.ptr, geom.ptr)
@ -212,6 +220,10 @@ class WKBWriter(IOBase):
_destructor = wkb_writer_destroy _destructor = wkb_writer_destroy
ptr_type = WKB_WRITE_PTR ptr_type = WKB_WRITE_PTR
def __init__(self, dim=2):
super(WKBWriter, self).__init__()
self.outdim = dim
def write(self, geom): def write(self, geom):
"Returns the WKB representation of the given geometry." "Returns the WKB representation of the given geometry."
return six.memoryview(wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t()))) return six.memoryview(wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t())))
@ -280,10 +292,13 @@ def wkt_r():
return thread_context.wkt_r return thread_context.wkt_r
def wkt_w(dim=2): def wkt_w(dim=2, trim=False, precision=None):
if not thread_context.wkt_w: if not thread_context.wkt_w:
thread_context.wkt_w = WKTWriter() thread_context.wkt_w = WKTWriter(dim=dim, trim=trim, precision=precision)
else:
thread_context.wkt_w.outdim = dim thread_context.wkt_w.outdim = dim
thread_context.wkt_w.trim = trim
thread_context.wkt_w.precision = precision
return thread_context.wkt_w return thread_context.wkt_w
@ -295,14 +310,16 @@ def wkb_r():
def wkb_w(dim=2): def wkb_w(dim=2):
if not thread_context.wkb_w: if not thread_context.wkb_w:
thread_context.wkb_w = WKBWriter() thread_context.wkb_w = WKBWriter(dim=dim)
else:
thread_context.wkb_w.outdim = dim thread_context.wkb_w.outdim = dim
return thread_context.wkb_w return thread_context.wkb_w
def ewkb_w(dim=2): def ewkb_w(dim=2):
if not thread_context.ewkb_w: if not thread_context.ewkb_w:
thread_context.ewkb_w = WKBWriter() thread_context.ewkb_w = WKBWriter(dim=dim)
thread_context.ewkb_w.srid = True thread_context.ewkb_w.srid = True
else:
thread_context.ewkb_w.outdim = dim thread_context.ewkb_w.outdim = dim
return thread_context.ewkb_w return thread_context.ewkb_w

View File

@ -957,12 +957,18 @@ WKB or WKT of the given geometry. In addition, :class:`WKBWriter` objects
also have properties that may be used to change the byte order, and or also have properties that may be used to change the byte order, and or
include the SRID value (in other words, EWKB). include the SRID value (in other words, EWKB).
.. class:: WKBWriter .. class:: WKBWriter(dim=2)
``WKBWriter`` provides the most control over its output. By default it ``WKBWriter`` provides the most control over its output. By default it
returns OGC-compliant WKB when its ``write`` method is called. However, returns OGC-compliant WKB when its ``write`` method is called. However,
it has properties that allow for the creation of EWKB, a superset of the it has properties that allow for the creation of EWKB, a superset of the
WKB standard that includes additional information. WKB standard that includes additional information. See the
:attr:`WKBWriter.outdim` documentation for more details about the ``dim``
argument.
.. versionchanged:: 1.10
The ability to pass the ``dim`` argument to the constructor was added.
.. method:: WKBWriter.write(geom) .. method:: WKBWriter.write(geom)
@ -1047,7 +1053,16 @@ geometry should be included with the WKB representation. Example::
>>> wkb_w.write_hex(pnt) >>> wkb_w.write_hex(pnt)
'0101000020E6100000000000000000F03F000000000000F03F' '0101000020E6100000000000000000F03F000000000000F03F'
.. class:: WKTWriter .. class:: WKTWriter(dim=2, trim=False, precision=None)
This class allows outputting the WKT representation of a geometry. See the
:attr:`WKBWriter.outdim`, :attr:`trim`, and :attr:`precision` attributes for
details about the constructor arguments.
.. versionchanged:: 1.10
The ability to pass the ``dim``, ``trim``, and ``precision`` arguments
to the constructor was added.
.. method:: WKTWriter.write(geom) .. method:: WKTWriter.write(geom)
@ -1059,6 +1074,10 @@ Returns the WKT of the given geometry. Example::
>>> wkt_w.write(pnt) >>> wkt_w.write(pnt)
'POINT (1.0000000000000000 1.0000000000000000)' 'POINT (1.0000000000000000 1.0000000000000000)'
.. attribute:: WKTWriter.outdim
See :attr:`WKBWriter.outdim`.
.. attribute:: WKTWriter.trim .. attribute:: WKTWriter.trim
.. versionadded:: 1.10 .. versionadded:: 1.10

View File

@ -42,6 +42,12 @@ class GEOSIOTest(SimpleTestCase):
ref_wkt = 'POINT (5.0000000000000000 23.0000000000000000)' ref_wkt = 'POINT (5.0000000000000000 23.0000000000000000)'
self.assertEqual(ref_wkt, wkt_w.write(ref).decode()) self.assertEqual(ref_wkt, wkt_w.write(ref).decode())
def test_wktwriter_constructor_arguments(self):
wkt_w = WKTWriter(dim=3, trim=True, precision=3)
ref = GEOSGeometry('POINT (5.34562 23 1.5)')
ref_wkt = 'POINT Z (5.35 23 1.5)'
self.assertEqual(ref_wkt, wkt_w.write(ref).decode())
def test03_wkbreader(self): def test03_wkbreader(self):
# Creating a WKBReader instance # Creating a WKBReader instance
wkb_r = WKBReader() wkb_r = WKBReader()
@ -101,7 +107,7 @@ class GEOSIOTest(SimpleTestCase):
# Ensuring bad output dimensions are not accepted # Ensuring bad output dimensions are not accepted
for bad_outdim in (-1, 0, 1, 4, 423, 'foo', None): for bad_outdim in (-1, 0, 1, 4, 423, 'foo', None):
with self.assertRaises(ValueError): with self.assertRaisesMessage(ValueError, 'WKB output dimension must be 2 or 3'):
wkb_w.outdim = bad_outdim wkb_w.outdim = bad_outdim
# Now setting the output dimensions to be 3 # Now setting the output dimensions to be 3