Loading django/contrib/gis/geos/base.py +1 −3 Original line number Diff line number Diff line Loading @@ -41,9 +41,7 @@ class GEOSBase(object): def _set_ptr(self, ptr): # Only allow the pointer to be set with pointers of the # compatible type or None (NULL). if isinstance(ptr, int): self._ptr = self.ptr_type(ptr) elif isinstance(ptr, (self.ptr_type, NoneType)): if isinstance(ptr, (self.ptr_type, NoneType)): self._ptr = ptr else: raise TypeError('Incompatible pointer type') Loading django/contrib/gis/geos/geometry.py +11 −9 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ from django.contrib.gis.geos.mutable_list import ListMixin # prototypes module -- which handles all interaction with # the underlying GEOS library. from django.contrib.gis.geos import prototypes as capi from django.contrib.gis.geos import io # Regular expression for recognizing HEXEWKB and WKT. A prophylactic measure # to prevent potentially malicious input from reaching the underlying C Loading Loading @@ -62,13 +61,13 @@ class GEOSGeometry(GEOSBase, ListMixin): if wkt_m: # Handling WKT input. if wkt_m.group('srid'): srid = int(wkt_m.group('srid')) g = io.wkt_r.read(wkt_m.group('wkt')) g = wkt_r.read(wkt_m.group('wkt')) elif hex_regex.match(geo_input): # Handling HEXEWKB input. g = io.wkb_r.read(geo_input) g = wkb_r.read(geo_input) elif gdal.GEOJSON and gdal.geometries.json_regex.match(geo_input): # Handling GeoJSON input. g = io.wkb_r.read(gdal.OGRGeometry(geo_input).wkb) g = wkb_r.read(gdal.OGRGeometry(geo_input).wkb) else: raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.') elif isinstance(geo_input, GEOM_PTR): Loading @@ -76,7 +75,7 @@ class GEOSGeometry(GEOSBase, ListMixin): g = geo_input elif isinstance(geo_input, buffer): # When the input is a buffer (WKB). g = io.wkb_r.read(geo_input) g = wkb_r.read(geo_input) elif isinstance(geo_input, GEOSGeometry): g = capi.geom_clone(geo_input.ptr) else: Loading Loading @@ -366,7 +365,7 @@ class GEOSGeometry(GEOSBase, ListMixin): @property def wkt(self): "Returns the WKT (Well-Known Text) of the Geometry." return io.wkt_w.write(self.ptr) return wkt_w.write(self) @property def hex(self): Loading @@ -377,7 +376,7 @@ class GEOSGeometry(GEOSBase, ListMixin): """ # A possible faster, all-python, implementation: # str(self.wkb).encode('hex') return io.wkb_w.write_hex(self.ptr) return wkb_w.write_hex(self) @property def json(self): Loading @@ -394,7 +393,7 @@ class GEOSGeometry(GEOSBase, ListMixin): @property def wkb(self): "Returns the WKB of the Geometry as a buffer." return io.wkb_w.write(self.ptr) return wkb_w.write(self) @property def kml(self): Loading Loading @@ -456,7 +455,7 @@ class GEOSGeometry(GEOSBase, ListMixin): g = gdal.OGRGeometry(self.wkb, srid) g.transform(ct) # Getting a new GEOS pointer ptr = io.wkb_r.read(g.wkb) ptr = wkb_r.read(g.wkb) if clone: # User wants a cloned transformed geometry returned. return GEOSGeometry(ptr, srid=g.srid) Loading Loading @@ -618,6 +617,9 @@ GEOS_CLASSES = {0 : Point, 7 : GeometryCollection, } # Similarly, import the GEOS I/O instances here to avoid conflicts. from django.contrib.gis.geos.io import wkt_r, wkt_w, wkb_r, wkb_w # If supported, import the PreparedGeometry class. if GEOS_PREPARE: from django.contrib.gis.geos.prepared import PreparedGeometry django/contrib/gis/geos/io.py +30 −16 Original line number Diff line number Diff line Loading @@ -6,11 +6,12 @@ reader and writer classes. from ctypes import byref, c_size_t from django.contrib.gis.geos.base import GEOSBase from django.contrib.gis.geos.error import GEOSException from django.contrib.gis.geos.geometry import GEOSGeometry from django.contrib.gis.geos.libgeos import GEOM_PTR from django.contrib.gis.geos.prototypes import io as capi class IOBase(GEOSBase): "Base class for IO objects that that have `destroy` method." "Base class for GEOS I/O objects." def __init__(self): # Getting the pointer with the constructor. self.ptr = self.constructor() Loading @@ -19,36 +20,43 @@ class IOBase(GEOSBase): # Cleaning up with the appropriate destructor. if self._ptr: self.destructor(self._ptr) def _get_geom_ptr(self, geom): if hasattr(geom, 'ptr'): geom = geom.ptr if not isinstance(geom, GEOM_PTR): raise TypeError return geom ### WKT Reading and Writing objects ### class WKTReader(IOBase): # Non-public class for internal use because its `read` method returns # _pointers_ instead of a GEOSGeometry object. class _WKTReader(IOBase): constructor = capi.wkt_reader_create destructor = capi.wkt_reader_destroy ptr_type = capi.WKT_READ_PTR def read(self, wkt, ptr=False): def read(self, wkt): if not isinstance(wkt, basestring): raise TypeError return capi.wkt_reader_read(self.ptr, wkt) class WKTReader(_WKTReader): def read(self, wkt): "Returns a GEOSGeometry for the given WKT string." return GEOSGeometry(super(WKTReader, self).read(wkt)) class WKTWriter(IOBase): constructor = capi.wkt_writer_create destructor = capi.wkt_writer_destroy ptr_type = capi.WKT_WRITE_PTR def write(self, geom): return capi.wkt_writer_write(self.ptr, self._get_geom_ptr(geom)) "Returns the WKT representation of the given geometry." return capi.wkt_writer_write(self.ptr, geom.ptr) ### WKB Reading and Writing objects ### class WKBReader(IOBase): # Non-public class for the same reason as _WKTReader above. class _WKBReader(IOBase): constructor = capi.wkb_reader_create destructor = capi.wkb_reader_destroy ptr_type = capi.WKB_READ_PTR def read(self, wkb): "Returns a _pointer_ to C GEOS Geometry object from the given WKB." if isinstance(wkb, buffer): wkb_s = str(wkb) return capi.wkb_reader_read(self.ptr, wkb_s, len(wkb_s)) Loading @@ -57,16 +65,23 @@ class WKBReader(IOBase): else: raise TypeError class WKBReader(_WKBReader): def read(self, wkb): "Returns a GEOSGeometry for the given WKB buffer." return GEOSGeometry(super(WKBReader, self).read(wkb)) class WKBWriter(IOBase): constructor = capi.wkb_writer_create destructor = capi.wkb_writer_destroy ptr_type = capi.WKB_READ_PTR ptr_type = capi.WKB_WRITE_PTR def write(self, geom): return buffer(capi.wkb_writer_write(self.ptr, self._get_geom_ptr(geom), byref(c_size_t()))) "Returns the WKB representation of the given geometry." return buffer(capi.wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t()))) def write_hex(self, geom): return capi.wkb_writer_write_hex(self.ptr, self._get_geom_ptr(geom), byref(c_size_t())) "Returns the HEXEWKB representation of the given geometry." return capi.wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t())) ### WKBWriter Properties ### Loading Loading @@ -102,8 +117,7 @@ class WKBWriter(IOBase): srid = property(_get_include_srid, _set_include_srid) # Instances of the WKT and WKB reader/writer objects. wkt_r = WKTReader() wkt_r = _WKTReader() wkt_w = WKTWriter() wkb_r = WKBReader() wkb_r = _WKBReader() wkb_w = WKBWriter() django/contrib/gis/geos/tests/__init__.py +2 −1 Original line number Diff line number Diff line Loading @@ -2,10 +2,11 @@ GEOS Testing module. """ from unittest import TestSuite, TextTestRunner import test_geos, test_geos_mutation, test_mutable_list import test_geos, test_io, test_geos_mutation, test_mutable_list test_suites = [ test_geos.suite(), test_io.suite(), test_geos_mutation.suite(), test_mutable_list.suite(), ] Loading django/contrib/gis/geos/tests/test_geos.py +47 −6 Original line number Diff line number Diff line import random, unittest, sys from ctypes import ArgumentError import ctypes, random, unittest, sys from django.contrib.gis.geos import * from django.contrib.gis.geos.base import gdal, numpy from django.contrib.gis.geos.base import gdal, numpy, GEOSBase from django.contrib.gis.tests.geometries import * class GEOSTest(unittest.TestCase): Loading @@ -18,6 +17,48 @@ class GEOSTest(unittest.TestCase): else: return None def test00_base(self): "Tests out the GEOSBase class." # Testing out GEOSBase class, which provides a `ptr` property # that abstracts out access to underlying C pointers. class FakeGeom1(GEOSBase): pass # This one only accepts pointers to floats c_float_p = ctypes.POINTER(ctypes.c_float) class FakeGeom2(GEOSBase): ptr_type = c_float_p # Default ptr_type is `c_void_p`. fg1 = FakeGeom1() # Default ptr_type is C float pointer fg2 = FakeGeom2() # These assignments are OK -- None is allowed because # it's equivalent to the NULL pointer. fg1.ptr = ctypes.c_void_p() fg1.ptr = None fg2.ptr = c_float_p(ctypes.c_float(5.23)) fg2.ptr = None # Because pointers have been set to NULL, an exception should be # raised when we try to access it. Raising an exception is # preferrable to a segmentation fault that commonly occurs when # a C method is given a NULL memory reference. for fg in (fg1, fg2): # Equivalent to `fg.ptr` self.assertRaises(GEOSException, fg._get_ptr) # Anything that is either not None or the acceptable pointer type will # result in a TypeError when trying to assign it to the `ptr` property. # Thus, memmory addresses (integers) and pointers of the incorrect type # (in `bad_ptrs`) will not be allowed. bad_ptrs = (5, ctypes.c_char_p('foobar')) for bad_ptr in bad_ptrs: # Equivalent to `fg.ptr = bad_ptr` self.assertRaises(TypeError, fg1._set_ptr, bad_ptr) self.assertRaises(TypeError, fg2._set_ptr, bad_ptr) def test01a_wkt(self): "Testing WKT output." for g in wkt_out: Loading Loading @@ -494,7 +535,7 @@ class GEOSTest(unittest.TestCase): exp_buf = fromstr(g_tup[1].wkt) # Can't use a floating-point for the number of quadsegs. self.assertRaises(ArgumentError, g.buffer, g_tup[2], float(g_tup[3])) self.assertRaises(ctypes.ArgumentError, g.buffer, g_tup[2], float(g_tup[3])) # Constructing our buffer buf = g.buffer(g_tup[2], g_tup[3]) Loading @@ -518,7 +559,7 @@ class GEOSTest(unittest.TestCase): self.assertEqual(4326, pnt.srid) pnt.srid = 3084 self.assertEqual(3084, pnt.srid) self.assertRaises(ArgumentError, pnt.set_srid, '4326') self.assertRaises(ctypes.ArgumentError, pnt.set_srid, '4326') # Testing SRID keyword on fromstr(), and on Polygon rings. poly = fromstr(polygons[1].wkt, srid=4269) Loading Loading
django/contrib/gis/geos/base.py +1 −3 Original line number Diff line number Diff line Loading @@ -41,9 +41,7 @@ class GEOSBase(object): def _set_ptr(self, ptr): # Only allow the pointer to be set with pointers of the # compatible type or None (NULL). if isinstance(ptr, int): self._ptr = self.ptr_type(ptr) elif isinstance(ptr, (self.ptr_type, NoneType)): if isinstance(ptr, (self.ptr_type, NoneType)): self._ptr = ptr else: raise TypeError('Incompatible pointer type') Loading
django/contrib/gis/geos/geometry.py +11 −9 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ from django.contrib.gis.geos.mutable_list import ListMixin # prototypes module -- which handles all interaction with # the underlying GEOS library. from django.contrib.gis.geos import prototypes as capi from django.contrib.gis.geos import io # Regular expression for recognizing HEXEWKB and WKT. A prophylactic measure # to prevent potentially malicious input from reaching the underlying C Loading Loading @@ -62,13 +61,13 @@ class GEOSGeometry(GEOSBase, ListMixin): if wkt_m: # Handling WKT input. if wkt_m.group('srid'): srid = int(wkt_m.group('srid')) g = io.wkt_r.read(wkt_m.group('wkt')) g = wkt_r.read(wkt_m.group('wkt')) elif hex_regex.match(geo_input): # Handling HEXEWKB input. g = io.wkb_r.read(geo_input) g = wkb_r.read(geo_input) elif gdal.GEOJSON and gdal.geometries.json_regex.match(geo_input): # Handling GeoJSON input. g = io.wkb_r.read(gdal.OGRGeometry(geo_input).wkb) g = wkb_r.read(gdal.OGRGeometry(geo_input).wkb) else: raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.') elif isinstance(geo_input, GEOM_PTR): Loading @@ -76,7 +75,7 @@ class GEOSGeometry(GEOSBase, ListMixin): g = geo_input elif isinstance(geo_input, buffer): # When the input is a buffer (WKB). g = io.wkb_r.read(geo_input) g = wkb_r.read(geo_input) elif isinstance(geo_input, GEOSGeometry): g = capi.geom_clone(geo_input.ptr) else: Loading Loading @@ -366,7 +365,7 @@ class GEOSGeometry(GEOSBase, ListMixin): @property def wkt(self): "Returns the WKT (Well-Known Text) of the Geometry." return io.wkt_w.write(self.ptr) return wkt_w.write(self) @property def hex(self): Loading @@ -377,7 +376,7 @@ class GEOSGeometry(GEOSBase, ListMixin): """ # A possible faster, all-python, implementation: # str(self.wkb).encode('hex') return io.wkb_w.write_hex(self.ptr) return wkb_w.write_hex(self) @property def json(self): Loading @@ -394,7 +393,7 @@ class GEOSGeometry(GEOSBase, ListMixin): @property def wkb(self): "Returns the WKB of the Geometry as a buffer." return io.wkb_w.write(self.ptr) return wkb_w.write(self) @property def kml(self): Loading Loading @@ -456,7 +455,7 @@ class GEOSGeometry(GEOSBase, ListMixin): g = gdal.OGRGeometry(self.wkb, srid) g.transform(ct) # Getting a new GEOS pointer ptr = io.wkb_r.read(g.wkb) ptr = wkb_r.read(g.wkb) if clone: # User wants a cloned transformed geometry returned. return GEOSGeometry(ptr, srid=g.srid) Loading Loading @@ -618,6 +617,9 @@ GEOS_CLASSES = {0 : Point, 7 : GeometryCollection, } # Similarly, import the GEOS I/O instances here to avoid conflicts. from django.contrib.gis.geos.io import wkt_r, wkt_w, wkb_r, wkb_w # If supported, import the PreparedGeometry class. if GEOS_PREPARE: from django.contrib.gis.geos.prepared import PreparedGeometry
django/contrib/gis/geos/io.py +30 −16 Original line number Diff line number Diff line Loading @@ -6,11 +6,12 @@ reader and writer classes. from ctypes import byref, c_size_t from django.contrib.gis.geos.base import GEOSBase from django.contrib.gis.geos.error import GEOSException from django.contrib.gis.geos.geometry import GEOSGeometry from django.contrib.gis.geos.libgeos import GEOM_PTR from django.contrib.gis.geos.prototypes import io as capi class IOBase(GEOSBase): "Base class for IO objects that that have `destroy` method." "Base class for GEOS I/O objects." def __init__(self): # Getting the pointer with the constructor. self.ptr = self.constructor() Loading @@ -19,36 +20,43 @@ class IOBase(GEOSBase): # Cleaning up with the appropriate destructor. if self._ptr: self.destructor(self._ptr) def _get_geom_ptr(self, geom): if hasattr(geom, 'ptr'): geom = geom.ptr if not isinstance(geom, GEOM_PTR): raise TypeError return geom ### WKT Reading and Writing objects ### class WKTReader(IOBase): # Non-public class for internal use because its `read` method returns # _pointers_ instead of a GEOSGeometry object. class _WKTReader(IOBase): constructor = capi.wkt_reader_create destructor = capi.wkt_reader_destroy ptr_type = capi.WKT_READ_PTR def read(self, wkt, ptr=False): def read(self, wkt): if not isinstance(wkt, basestring): raise TypeError return capi.wkt_reader_read(self.ptr, wkt) class WKTReader(_WKTReader): def read(self, wkt): "Returns a GEOSGeometry for the given WKT string." return GEOSGeometry(super(WKTReader, self).read(wkt)) class WKTWriter(IOBase): constructor = capi.wkt_writer_create destructor = capi.wkt_writer_destroy ptr_type = capi.WKT_WRITE_PTR def write(self, geom): return capi.wkt_writer_write(self.ptr, self._get_geom_ptr(geom)) "Returns the WKT representation of the given geometry." return capi.wkt_writer_write(self.ptr, geom.ptr) ### WKB Reading and Writing objects ### class WKBReader(IOBase): # Non-public class for the same reason as _WKTReader above. class _WKBReader(IOBase): constructor = capi.wkb_reader_create destructor = capi.wkb_reader_destroy ptr_type = capi.WKB_READ_PTR def read(self, wkb): "Returns a _pointer_ to C GEOS Geometry object from the given WKB." if isinstance(wkb, buffer): wkb_s = str(wkb) return capi.wkb_reader_read(self.ptr, wkb_s, len(wkb_s)) Loading @@ -57,16 +65,23 @@ class WKBReader(IOBase): else: raise TypeError class WKBReader(_WKBReader): def read(self, wkb): "Returns a GEOSGeometry for the given WKB buffer." return GEOSGeometry(super(WKBReader, self).read(wkb)) class WKBWriter(IOBase): constructor = capi.wkb_writer_create destructor = capi.wkb_writer_destroy ptr_type = capi.WKB_READ_PTR ptr_type = capi.WKB_WRITE_PTR def write(self, geom): return buffer(capi.wkb_writer_write(self.ptr, self._get_geom_ptr(geom), byref(c_size_t()))) "Returns the WKB representation of the given geometry." return buffer(capi.wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t()))) def write_hex(self, geom): return capi.wkb_writer_write_hex(self.ptr, self._get_geom_ptr(geom), byref(c_size_t())) "Returns the HEXEWKB representation of the given geometry." return capi.wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t())) ### WKBWriter Properties ### Loading Loading @@ -102,8 +117,7 @@ class WKBWriter(IOBase): srid = property(_get_include_srid, _set_include_srid) # Instances of the WKT and WKB reader/writer objects. wkt_r = WKTReader() wkt_r = _WKTReader() wkt_w = WKTWriter() wkb_r = WKBReader() wkb_r = _WKBReader() wkb_w = WKBWriter()
django/contrib/gis/geos/tests/__init__.py +2 −1 Original line number Diff line number Diff line Loading @@ -2,10 +2,11 @@ GEOS Testing module. """ from unittest import TestSuite, TextTestRunner import test_geos, test_geos_mutation, test_mutable_list import test_geos, test_io, test_geos_mutation, test_mutable_list test_suites = [ test_geos.suite(), test_io.suite(), test_geos_mutation.suite(), test_mutable_list.suite(), ] Loading
django/contrib/gis/geos/tests/test_geos.py +47 −6 Original line number Diff line number Diff line import random, unittest, sys from ctypes import ArgumentError import ctypes, random, unittest, sys from django.contrib.gis.geos import * from django.contrib.gis.geos.base import gdal, numpy from django.contrib.gis.geos.base import gdal, numpy, GEOSBase from django.contrib.gis.tests.geometries import * class GEOSTest(unittest.TestCase): Loading @@ -18,6 +17,48 @@ class GEOSTest(unittest.TestCase): else: return None def test00_base(self): "Tests out the GEOSBase class." # Testing out GEOSBase class, which provides a `ptr` property # that abstracts out access to underlying C pointers. class FakeGeom1(GEOSBase): pass # This one only accepts pointers to floats c_float_p = ctypes.POINTER(ctypes.c_float) class FakeGeom2(GEOSBase): ptr_type = c_float_p # Default ptr_type is `c_void_p`. fg1 = FakeGeom1() # Default ptr_type is C float pointer fg2 = FakeGeom2() # These assignments are OK -- None is allowed because # it's equivalent to the NULL pointer. fg1.ptr = ctypes.c_void_p() fg1.ptr = None fg2.ptr = c_float_p(ctypes.c_float(5.23)) fg2.ptr = None # Because pointers have been set to NULL, an exception should be # raised when we try to access it. Raising an exception is # preferrable to a segmentation fault that commonly occurs when # a C method is given a NULL memory reference. for fg in (fg1, fg2): # Equivalent to `fg.ptr` self.assertRaises(GEOSException, fg._get_ptr) # Anything that is either not None or the acceptable pointer type will # result in a TypeError when trying to assign it to the `ptr` property. # Thus, memmory addresses (integers) and pointers of the incorrect type # (in `bad_ptrs`) will not be allowed. bad_ptrs = (5, ctypes.c_char_p('foobar')) for bad_ptr in bad_ptrs: # Equivalent to `fg.ptr = bad_ptr` self.assertRaises(TypeError, fg1._set_ptr, bad_ptr) self.assertRaises(TypeError, fg2._set_ptr, bad_ptr) def test01a_wkt(self): "Testing WKT output." for g in wkt_out: Loading Loading @@ -494,7 +535,7 @@ class GEOSTest(unittest.TestCase): exp_buf = fromstr(g_tup[1].wkt) # Can't use a floating-point for the number of quadsegs. self.assertRaises(ArgumentError, g.buffer, g_tup[2], float(g_tup[3])) self.assertRaises(ctypes.ArgumentError, g.buffer, g_tup[2], float(g_tup[3])) # Constructing our buffer buf = g.buffer(g_tup[2], g_tup[3]) Loading @@ -518,7 +559,7 @@ class GEOSTest(unittest.TestCase): self.assertEqual(4326, pnt.srid) pnt.srid = 3084 self.assertEqual(3084, pnt.srid) self.assertRaises(ArgumentError, pnt.set_srid, '4326') self.assertRaises(ctypes.ArgumentError, pnt.set_srid, '4326') # Testing SRID keyword on fromstr(), and on Polygon rings. poly = fromstr(polygons[1].wkt, srid=4269) Loading