diff --git a/django/contrib/gis/geos/base.py b/django/contrib/gis/geos/base.py index e36db67ae0..b431ef15bf 100644 --- a/django/contrib/gis/geos/base.py +++ b/django/contrib/gis/geos/base.py @@ -6,7 +6,7 @@ from ctypes import \ byref, string_at, create_string_buffer, pointer, \ c_char_p, c_double, c_int, c_size_t -from types import StringType, UnicodeType, IntType, FloatType +from types import StringType, UnicodeType, IntType, FloatType, BufferType # Python and GEOS-related dependencies. import re @@ -30,9 +30,13 @@ class GEOSGeometry(object): #### Python 'magic' routines #### def __init__(self, geo_input, srid=None): """ - The base constructor for GEOS geometry objects, and may take the following - string inputs: WKT and HEXEWKB (a PostGIS-specific canonical form). - + The base constructor for GEOS geometry objects, and may take the + following inputs: + + * string: WKT + * string: HEXEWKB (a PostGIS-specific canonical form) + * buffer: WKB + The `srid` keyword is used to specify the Source Reference Identifier (SRID) number for this Geometry. If not set, the SRID will be None. """ @@ -55,6 +59,11 @@ class GEOSGeometry(object): # When the input is either a memory address (an integer), or a # GEOSPointer object. g = geo_input + elif isinstance(geo_input, BufferType): + # When the input is a buffer (WKB). + wkb_input = str(geo_input) + sz = c_size_t(len(wkb_input)) + g = lgeos.GEOSGeomFromWKB_buf(c_char_p(wkb_input), sz) else: # Invalid geometry type. raise TypeError, 'Improper geometry input type: %s' % str(type(geo_input)) @@ -413,6 +422,13 @@ class GEOSGeometry(object): h = lgeos.GEOSGeomToHEX_buf(self._ptr(), byref(sz)) return string_at(h, sz.value) + @property + def wkb(self): + "Returns the WKB of the Geometry as a buffer." + sz = c_size_t() + h = lgeos.GEOSGeomToWKB_buf(self._ptr(), byref(sz)) + return buffer(string_at(h, sz.value)) + @property def kml(self): "Returns the KML representation of this Geometry." diff --git a/django/contrib/gis/geos/libgeos.py b/django/contrib/gis/geos/libgeos.py index 65e80b40de..4dcdb16d66 100644 --- a/django/contrib/gis/geos/libgeos.py +++ b/django/contrib/gis/geos/libgeos.py @@ -52,8 +52,12 @@ lgeos = CDLL(lib_name) # Supposed to mimic the GEOS message handler (C below): # "typedef void (*GEOSMessageHandler)(const char *fmt, ...);" NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p) -def notice_h(fmt, list, output_h=sys.stdout): - output_h.write('GEOS_NOTICE: %s\n' % (fmt % list)) +def notice_h(fmt, lst, output_h=sys.stdout): + try: + warn_msg = fmt % lst + except: + warn_msg = fmt + output_h.write('GEOS_NOTICE: %s\n' % warn_msg) notice_h = NOTICEFUNC(notice_h) ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p) diff --git a/django/contrib/gis/tests/geometries.py b/django/contrib/gis/tests/geometries.py index b2602c1b24..564630d161 100644 --- a/django/contrib/gis/tests/geometries.py +++ b/django/contrib/gis/tests/geometries.py @@ -49,6 +49,7 @@ errors = (TestGeom('GEOMETR##!@#%#............a32515', bad=True, hex=False), TestGeom('POINT (5, 23)', bad=True, hex=False), TestGeom('AAABBBDDDAAD##@#1113511111-098111111111111111533333333333333', bad=True, hex=True), TestGeom('FFFFFFFFFFFFFFFFF1355555555555555555565111', bad=True, hex=True), + TestGeom('', bad=True, hex=False), ) # Polygons diff --git a/django/contrib/gis/tests/test_geos.py b/django/contrib/gis/tests/test_geos.py index be0da42e5a..062da04098 100644 --- a/django/contrib/gis/tests/test_geos.py +++ b/django/contrib/gis/tests/test_geos.py @@ -31,14 +31,48 @@ class GEOSTest(unittest.TestCase): def test01d_errors(self): "Testing the Error handlers." + # string-based print "\nBEGIN - expecting GEOS_ERROR; safe to ignore.\n" for err in errors: - if err.hex: - self.assertRaises(GEOSException, fromstr, err.wkt) - else: - self.assertRaises(GEOSException, fromstr, err.wkt) + self.assertRaises(GEOSException, fromstr, err.wkt) print "\nEND - expecting GEOS_ERROR; safe to ignore.\n" + + class NotAGeometry(object): + pass + + # Some other object + self.assertRaises(TypeError, GEOSGeometry, NotAGeometry()) + # None + self.assertRaises(TypeError, GEOSGeometry, None) + # Bad WKB + self.assertRaises(GEOSException, GEOSGeometry, buffer('0')) + def test01e_wkb(self): + "Testing WKB output." + from binascii import b2a_hex + for g in hex_wkt: + geom = fromstr(g.wkt) + wkb = geom.wkb + self.assertEqual(b2a_hex(wkb).upper(), g.hex) + + def test01f_create_hex(self): + "Testing creation from HEX." + for g in hex_wkt: + geom_h = GEOSGeometry(g.hex) + # we need to do this so decimal places get normalised + geom_t = fromstr(g.wkt) + self.assertEqual(geom_t.wkt, geom_h.wkt) + + def test01g_create_wkb(self): + "Testing creation from WKB." + from binascii import a2b_hex + for g in hex_wkt: + wkb = buffer(a2b_hex(g.hex)) + geom_h = GEOSGeometry(wkb) + # we need to do this so decimal places get normalised + geom_t = fromstr(g.wkt) + self.assertEqual(geom_t.wkt, geom_h.wkt) + def test02a_points(self): "Testing Point objects." prev = fromstr('POINT(0 0)')