[py3] Fixed GEOS/GDAL tests

This commit is contained in:
Claude Paroz 2012-09-23 19:59:27 +02:00
parent 8cdc84726e
commit 5330cd50cd
19 changed files with 106 additions and 80 deletions

View File

@ -41,7 +41,7 @@ try:
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
from django.contrib.gis.gdal.geometries import OGRGeometry from django.contrib.gis.gdal.geometries import OGRGeometry
HAS_GDAL = True HAS_GDAL = True
except: except ImportError:
HAS_GDAL = False HAS_GDAL = False
try: try:

View File

@ -45,6 +45,7 @@ from django.contrib.gis.gdal.layer import Layer
# Getting the ctypes prototypes for the DataSource. # Getting the ctypes prototypes for the DataSource.
from django.contrib.gis.gdal.prototypes import ds as capi from django.contrib.gis.gdal.prototypes import ds as capi
from django.utils.encoding import force_bytes
from django.utils import six from django.utils import six
from django.utils.six.moves import xrange from django.utils.six.moves import xrange
@ -73,7 +74,7 @@ class DataSource(GDALBase):
ds_driver = Driver.ptr_type() ds_driver = Driver.ptr_type()
try: try:
# OGROpen will auto-detect the data source type. # OGROpen will auto-detect the data source type.
ds = capi.open_ds(ds_input, self._write, byref(ds_driver)) ds = capi.open_ds(force_bytes(ds_input), self._write, byref(ds_driver))
except OGRException: except OGRException:
# Making the error message more clear rather than something # Making the error message more clear rather than something
# like "Invalid pointer returned from OGROpen". # like "Invalid pointer returned from OGROpen".
@ -102,7 +103,7 @@ class DataSource(GDALBase):
def __getitem__(self, index): def __getitem__(self, index):
"Allows use of the index [] operator to get a layer at the index." "Allows use of the index [] operator to get a layer at the index."
if isinstance(index, six.string_types): if isinstance(index, six.string_types):
l = capi.get_layer_by_name(self.ptr, index) l = capi.get_layer_by_name(self.ptr, force_bytes(index))
if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index) if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
elif isinstance(index, int): elif isinstance(index, int):
if index < 0 or index >= self.layer_count: if index < 0 or index >= self.layer_count:

View File

@ -5,6 +5,7 @@ from django.contrib.gis.gdal.error import OGRException
from django.contrib.gis.gdal.prototypes import ds as capi from django.contrib.gis.gdal.prototypes import ds as capi
from django.utils import six from django.utils import six
from django.utils.encoding import force_bytes
# For more information, see the OGR C API source code: # For more information, see the OGR C API source code:
# http://www.gdal.org/ogr/ogr__api_8h.html # http://www.gdal.org/ogr/ogr__api_8h.html
@ -36,7 +37,7 @@ class Driver(GDALBase):
name = dr_input name = dr_input
# Attempting to get the OGR driver by the string name. # Attempting to get the OGR driver by the string name.
dr = capi.get_driver_by_name(name) dr = capi.get_driver_by_name(force_bytes(name))
elif isinstance(dr_input, int): elif isinstance(dr_input, int):
self._register() self._register()
dr = capi.get_driver(dr_input) dr = capi.get_driver(dr_input)

View File

@ -52,7 +52,7 @@ class Envelope(object):
elif len(args) == 4: elif len(args) == 4:
# Individual parameters passed in. # Individual parameters passed in.
# Thanks to ww for the help # Thanks to ww for the help
self._from_sequence(map(float, args)) self._from_sequence([float(a) for a in args])
else: else:
raise OGRException('Incorrect number (%d) of arguments.' % len(args)) raise OGRException('Incorrect number (%d) of arguments.' % len(args))

View File

@ -7,6 +7,7 @@ from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
# ctypes function prototypes # ctypes function prototypes
from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api
from django.utils.encoding import force_bytes
from django.utils import six from django.utils import six
from django.utils.six.moves import xrange from django.utils.six.moves import xrange
@ -107,6 +108,7 @@ class Feature(GDALBase):
def index(self, field_name): def index(self, field_name):
"Returns the index of the given field name." "Returns the index of the given field name."
i = capi.get_field_index(self.ptr, field_name) i = capi.get_field_index(self.ptr, force_bytes(field_name))
if i < 0: raise OGRIndexError('invalid OFT field name given: "%s"' % field_name) if i < 0:
raise OGRIndexError('invalid OFT field name given: "%s"' % field_name)
return i return i

View File

@ -78,16 +78,11 @@ class OGRGeometry(GDALBase):
# If HEX, unpack input to to a binary buffer. # If HEX, unpack input to to a binary buffer.
if str_instance and hex_regex.match(geom_input): if str_instance and hex_regex.match(geom_input):
geom_input = memoryview(a2b_hex(geom_input.upper())) geom_input = memoryview(a2b_hex(geom_input.upper().encode()))
str_instance = False str_instance = False
# Constructing the geometry, # Constructing the geometry,
if str_instance: if str_instance:
# Checking if unicode
if isinstance(geom_input, six.text_type):
# Encoding to ASCII, WKT or HEX doesn't need any more.
geom_input = geom_input.encode('ascii')
wkt_m = wkt_regex.match(geom_input) wkt_m = wkt_regex.match(geom_input)
json_m = json_regex.match(geom_input) json_m = json_regex.match(geom_input)
if wkt_m: if wkt_m:
@ -98,11 +93,11 @@ class OGRGeometry(GDALBase):
# OGR_G_CreateFromWkt doesn't work with LINEARRING WKT. # OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
# See http://trac.osgeo.org/gdal/ticket/1992. # See http://trac.osgeo.org/gdal/ticket/1992.
g = capi.create_geom(OGRGeomType(wkt_m.group('type')).num) g = capi.create_geom(OGRGeomType(wkt_m.group('type')).num)
capi.import_wkt(g, byref(c_char_p(wkt_m.group('wkt')))) capi.import_wkt(g, byref(c_char_p(wkt_m.group('wkt').encode())))
else: else:
g = capi.from_wkt(byref(c_char_p(wkt_m.group('wkt'))), None, byref(c_void_p())) g = capi.from_wkt(byref(c_char_p(wkt_m.group('wkt').encode())), None, byref(c_void_p()))
elif json_m: elif json_m:
g = capi.from_json(geom_input) g = capi.from_json(geom_input.encode())
else: else:
# Seeing if the input is a valid short-hand string # Seeing if the input is a valid short-hand string
# (e.g., 'Point', 'POLYGON'). # (e.g., 'Point', 'POLYGON').
@ -110,7 +105,7 @@ class OGRGeometry(GDALBase):
g = capi.create_geom(OGRGeomType(geom_input).num) g = capi.create_geom(OGRGeomType(geom_input).num)
elif isinstance(geom_input, memoryview): elif isinstance(geom_input, memoryview):
# WKB was passed in # WKB was passed in
g = capi.from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input)) g = capi.from_wkb(bytes(geom_input), None, byref(c_void_p()), len(geom_input))
elif isinstance(geom_input, OGRGeomType): elif isinstance(geom_input, OGRGeomType):
# OGRGeomType was passed in, an empty geometry will be created. # OGRGeomType was passed in, an empty geometry will be created.
g = capi.create_geom(geom_input.num) g = capi.create_geom(geom_input.num)
@ -143,7 +138,7 @@ class OGRGeometry(GDALBase):
srs = srs.wkt srs = srs.wkt
else: else:
srs = None srs = None
return str(self.wkb), srs return bytes(self.wkb), srs
def __setstate__(self, state): def __setstate__(self, state):
wkb, srs = state wkb, srs = state

View File

@ -14,6 +14,7 @@ from django.contrib.gis.gdal.srs import SpatialReference
# GDAL ctypes function prototypes. # GDAL ctypes function prototypes.
from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api, srs as srs_api from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api, srs as srs_api
from django.utils.encoding import force_bytes
from django.utils import six from django.utils import six
from django.utils.six.moves import xrange from django.utils.six.moves import xrange
@ -38,7 +39,7 @@ class Layer(GDALBase):
self._ds = ds self._ds = ds
self._ldefn = capi.get_layer_defn(self._ptr) self._ldefn = capi.get_layer_defn(self._ptr)
# Does the Layer support random reading? # Does the Layer support random reading?
self._random_read = self.test_capability('RandomRead') self._random_read = self.test_capability(b'RandomRead')
def __getitem__(self, index): def __getitem__(self, index):
"Gets the Feature at the specified index." "Gets the Feature at the specified index."
@ -212,4 +213,4 @@ class Layer(GDALBase):
'FastFeatureCount', 'FastGetExtent', 'CreateField', 'Transactions', 'FastFeatureCount', 'FastGetExtent', 'CreateField', 'Transactions',
'DeleteFeature', and 'FastSetNextByIndex'. 'DeleteFeature', and 'FastSetNextByIndex'.
""" """
return bool(capi.test_capability(self.ptr, capability)) return bool(capi.test_capability(self.ptr, force_bytes(capability)))

View File

@ -1,3 +1,5 @@
from __future__ import unicode_literals
import os import os
import re import re
from ctypes import c_char_p, CDLL from ctypes import c_char_p, CDLL
@ -65,7 +67,7 @@ _version_info.restype = c_char_p
def gdal_version(): def gdal_version():
"Returns only the GDAL version number information." "Returns only the GDAL version number information."
return _version_info('RELEASE_NAME') return _version_info(b'RELEASE_NAME')
def gdal_full_version(): def gdal_full_version():
"Returns the full GDAL version information." "Returns the full GDAL version information."
@ -86,7 +88,7 @@ def gdal_release_date(date=False):
version_regex = re.compile(r'^(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<subminor>\d+))?') version_regex = re.compile(r'^(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<subminor>\d+))?')
def gdal_version_info(): def gdal_version_info():
ver = gdal_version() ver = gdal_version().decode()
m = version_regex.match(ver) m = version_regex.match(ver)
if not m: raise OGRException('Could not parse GDAL version string "%s"' % ver) if not m: raise OGRException('Could not parse GDAL version string "%s"' % ver)
return dict([(key, m.group(key)) for key in ('major', 'minor', 'subminor')]) return dict([(key, m.group(key)) for key in ('major', 'minor', 'subminor')])

View File

@ -30,9 +30,10 @@ def check_const_string(result, func, cargs, offset=None):
if offset: if offset:
check_err(result) check_err(result)
ptr = ptr_byref(cargs, offset) ptr = ptr_byref(cargs, offset)
return ptr.value return ptr.value.decode()
else: else:
return result if result is not None:
return result.decode()
def check_string(result, func, cargs, offset=-1, str_result=False): def check_string(result, func, cargs, offset=-1, str_result=False):
""" """
@ -47,13 +48,13 @@ def check_string(result, func, cargs, offset=-1, str_result=False):
# For routines that return a string. # For routines that return a string.
ptr = result ptr = result
if not ptr: s = None if not ptr: s = None
else: s = string_at(result) else: s = string_at(result).decode()
else: else:
# Error-code return specified. # Error-code return specified.
check_err(result) check_err(result)
ptr = ptr_byref(cargs, offset) ptr = ptr_byref(cargs, offset)
# Getting the string value # Getting the string value
s = ptr.value s = ptr.value.decode()
# Correctly freeing the allocated memory beind GDAL pointer # Correctly freeing the allocated memory beind GDAL pointer
# w/the VSIFree routine. # w/the VSIFree routine.
if ptr: lgdal.VSIFree(ptr) if ptr: lgdal.VSIFree(ptr)
@ -125,4 +126,4 @@ def check_str_arg(result, func, cargs):
""" """
dbl = result dbl = result
ptr = cargs[-1]._obj ptr = cargs[-1]._obj
return dbl, ptr.value return dbl, ptr.value.decode()

View File

@ -34,6 +34,8 @@ from django.contrib.gis.gdal.error import SRSException
from django.contrib.gis.gdal.prototypes import srs as capi from django.contrib.gis.gdal.prototypes import srs as capi
from django.utils import six from django.utils import six
from django.utils.encoding import force_bytes, force_text
#### Spatial Reference class. #### #### Spatial Reference class. ####
class SpatialReference(GDALBase): class SpatialReference(GDALBase):
@ -51,7 +53,6 @@ class SpatialReference(GDALBase):
EPSG code, a PROJ.4 string, and/or a projection "well known" shorthand EPSG code, a PROJ.4 string, and/or a projection "well known" shorthand
string (one of 'WGS84', 'WGS72', 'NAD27', 'NAD83'). string (one of 'WGS84', 'WGS72', 'NAD27', 'NAD83').
""" """
buf = c_char_p('')
srs_type = 'user' srs_type = 'user'
if isinstance(srs_input, six.string_types): if isinstance(srs_input, six.string_types):
@ -79,6 +80,7 @@ class SpatialReference(GDALBase):
srs = srs_input srs = srs_input
else: else:
# Creating a new SRS pointer, using the string buffer. # Creating a new SRS pointer, using the string buffer.
buf = c_char_p(b'')
srs = capi.new_srs(buf) srs = capi.new_srs(buf)
# If the pointer is NULL, throw an exception. # If the pointer is NULL, throw an exception.
@ -137,15 +139,16 @@ class SpatialReference(GDALBase):
""" """
if not isinstance(target, six.string_types) or not isinstance(index, int): if not isinstance(target, six.string_types) or not isinstance(index, int):
raise TypeError raise TypeError
return capi.get_attr_value(self.ptr, target, index) value = capi.get_attr_value(self.ptr, force_bytes(target), index)
return force_text(value, 'ascii', strings_only=True)
def auth_name(self, target): def auth_name(self, target):
"Returns the authority name for the given string target node." "Returns the authority name for the given string target node."
return capi.get_auth_name(self.ptr, target) return capi.get_auth_name(self.ptr, force_bytes(target))
def auth_code(self, target): def auth_code(self, target):
"Returns the authority code for the given string target node." "Returns the authority code for the given string target node."
return capi.get_auth_code(self.ptr, target) return capi.get_auth_code(self.ptr, force_bytes(target))
def clone(self): def clone(self):
"Returns a clone of this SpatialReference object." "Returns a clone of this SpatialReference object."
@ -219,12 +222,14 @@ class SpatialReference(GDALBase):
and will automatically determines whether to return the linear and will automatically determines whether to return the linear
or angular units. or angular units.
""" """
units, name = None, None
if self.projected or self.local: if self.projected or self.local:
return capi.linear_units(self.ptr, byref(c_char_p())) units, name = capi.linear_units(self.ptr, byref(c_char_p()))
elif self.geographic: elif self.geographic:
return capi.angular_units(self.ptr, byref(c_char_p())) units, name = capi.angular_units(self.ptr, byref(c_char_p()))
else: if name is not None:
return (None, None) name.decode()
return (units, name)
#### Spheroid/Ellipsoid Properties #### #### Spheroid/Ellipsoid Properties ####
@property @property
@ -283,7 +288,7 @@ class SpatialReference(GDALBase):
def import_user_input(self, user_input): def import_user_input(self, user_input):
"Imports the Spatial Reference from the given user input string." "Imports the Spatial Reference from the given user input string."
capi.from_user_input(self.ptr, user_input) capi.from_user_input(self.ptr, force_bytes(user_input))
def import_wkt(self, wkt): def import_wkt(self, wkt):
"Imports the Spatial Reference from OGC WKT (string)" "Imports the Spatial Reference from OGC WKT (string)"

View File

@ -9,7 +9,7 @@ ds_list = (TestDS('test_point', nfeat=5, nfld=3, geom='POINT', gtype=1, driver='
fields={'dbl' : OFTReal, 'int' : OFTInteger, 'str' : OFTString,}, fields={'dbl' : OFTReal, 'int' : OFTInteger, 'str' : OFTString,},
extent=(-1.35011,0.166623,-0.524093,0.824508), # Got extent from QGIS extent=(-1.35011,0.166623,-0.524093,0.824508), # Got extent from QGIS
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]', srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]',
field_values={'dbl' : [float(i) for i in range(1, 6)], 'int' : range(1, 6), 'str' : [str(i) for i in range(1, 6)]}, field_values={'dbl' : [float(i) for i in range(1, 6)], 'int' : list(range(1, 6)), 'str' : [str(i) for i in range(1, 6)]},
fids=range(5)), fids=range(5)),
TestDS('test_vrt', ext='vrt', nfeat=3, nfld=3, geom='POINT', gtype='Point25D', driver='VRT', TestDS('test_vrt', ext='vrt', nfeat=3, nfld=3, geom='POINT', gtype='Point25D', driver='VRT',
fields={'POINT_X' : OFTString, 'POINT_Y' : OFTString, 'NUM' : OFTString}, # VRT uses CSV, which all types are OFTString. fields={'POINT_X' : OFTString, 'POINT_Y' : OFTString, 'NUM' : OFTString}, # VRT uses CSV, which all types are OFTString.
@ -200,7 +200,7 @@ class DataSourceTest(unittest.TestCase):
# Setting the spatial filter with a tuple/list with the extent of # Setting the spatial filter with a tuple/list with the extent of
# a buffer centering around Pueblo. # a buffer centering around Pueblo.
self.assertRaises(ValueError, lyr._set_spatial_filter, range(5)) self.assertRaises(ValueError, lyr._set_spatial_filter, list(range(5)))
filter_extent = (-105.609252, 37.255001, -103.609252, 39.255001) filter_extent = (-105.609252, 37.255001, -103.609252, 39.255001)
lyr.spatial_filter = (-105.609252, 37.255001, -103.609252, 39.255001) lyr.spatial_filter = (-105.609252, 37.255001, -103.609252, 39.255001)
self.assertEqual(OGRGeometry.from_bbox(filter_extent), lyr.spatial_filter) self.assertEqual(OGRGeometry.from_bbox(filter_extent), lyr.spatial_filter)

View File

@ -92,7 +92,7 @@ class OGRGeomTest(unittest.TestCase, TestDataMixin):
"Testing HEX input/output." "Testing HEX input/output."
for g in self.geometries.hex_wkt: for g in self.geometries.hex_wkt:
geom1 = OGRGeometry(g.wkt) geom1 = OGRGeometry(g.wkt)
self.assertEqual(g.hex, geom1.hex) self.assertEqual(g.hex.encode(), geom1.hex)
# Constructing w/HEX # Constructing w/HEX
geom2 = OGRGeometry(g.hex) geom2 = OGRGeometry(g.hex)
self.assertEqual(geom1, geom2) self.assertEqual(geom1, geom2)
@ -102,7 +102,7 @@ class OGRGeomTest(unittest.TestCase, TestDataMixin):
for g in self.geometries.hex_wkt: for g in self.geometries.hex_wkt:
geom1 = OGRGeometry(g.wkt) geom1 = OGRGeometry(g.wkt)
wkb = geom1.wkb wkb = geom1.wkb
self.assertEqual(b2a_hex(wkb).upper(), g.hex) self.assertEqual(b2a_hex(wkb).upper(), g.hex.encode())
# Constructing w/WKB. # Constructing w/WKB.
geom2 = OGRGeometry(wkb) geom2 = OGRGeometry(wkb)
self.assertEqual(geom1, geom2) self.assertEqual(geom1, geom2)

View File

@ -101,6 +101,6 @@ class TestDataMixin(object):
if GEOMETRIES is None: if GEOMETRIES is None:
# Load up the test geometry data from fixture into global. # Load up the test geometry data from fixture into global.
gzf = gzip.GzipFile(os.path.join(TEST_DATA, 'geometries.json.gz')) gzf = gzip.GzipFile(os.path.join(TEST_DATA, 'geometries.json.gz'))
geometries = json.loads(gzf.read()) geometries = json.loads(gzf.read().decode())
GEOMETRIES = TestGeomSet(**strconvert(geometries)) GEOMETRIES = TestGeomSet(**strconvert(geometries))
return GEOMETRIES return GEOMETRIES

View File

@ -3,6 +3,7 @@ from django.contrib.gis.geos.geometry import GEOSGeometry, wkt_regex, hex_regex
from django.utils import six from django.utils import six
def fromfile(file_h): def fromfile(file_h):
""" """
Given a string file name, returns a GEOSGeometry. The file may contain WKB, Given a string file name, returns a GEOSGeometry. The file may contain WKB,
@ -15,11 +16,19 @@ def fromfile(file_h):
else: else:
buf = file_h.read() buf = file_h.read()
# If we get WKB need to wrap in buffer(), so run through regexes. # If we get WKB need to wrap in memoryview(), so run through regexes.
if wkt_regex.match(buf) or hex_regex.match(buf): if isinstance(buf, bytes):
return GEOSGeometry(buf) try:
decoded = buf.decode()
if wkt_regex.match(decoded) or hex_regex.match(decoded):
return GEOSGeometry(decoded)
except UnicodeDecodeError:
pass
else: else:
return GEOSGeometry(memoryview(buf)) return GEOSGeometry(buf)
return GEOSGeometry(memoryview(buf))
def fromstr(string, **kwargs): def fromstr(string, **kwargs):
"Given a string value, returns a GEOSGeometry object." "Given a string value, returns a GEOSGeometry object."

View File

@ -2,6 +2,8 @@
This module contains the 'base' GEOSGeometry object -- all GEOS Geometries This module contains the 'base' GEOSGeometry object -- all GEOS Geometries
inherit from this object. inherit from this object.
""" """
from __future__ import unicode_literals
# Python, ctypes and types dependencies. # Python, ctypes and types dependencies.
from ctypes import addressof, byref, c_double from ctypes import addressof, byref, c_double
@ -29,6 +31,8 @@ from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ew
from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
from django.utils import six from django.utils import six
from django.utils.encoding import force_bytes, force_text
class GEOSGeometry(GEOSBase, ListMixin): class GEOSGeometry(GEOSBase, ListMixin):
"A class that, generally, encapsulates a GEOS geometry." "A class that, generally, encapsulates a GEOS geometry."
@ -55,19 +59,17 @@ class GEOSGeometry(GEOSBase, ListMixin):
The `srid` keyword is used to specify the Source Reference Identifier The `srid` keyword is used to specify the Source Reference Identifier
(SRID) number for this Geometry. If not set, the SRID will be None. (SRID) number for this Geometry. If not set, the SRID will be None.
""" """
if isinstance(geo_input, bytes):
geo_input = force_text(geo_input)
if isinstance(geo_input, six.string_types): if isinstance(geo_input, six.string_types):
if isinstance(geo_input, six.text_type):
# Encoding to ASCII, WKT or HEXEWKB doesn't need any more.
geo_input = geo_input.encode('ascii')
wkt_m = wkt_regex.match(geo_input) wkt_m = wkt_regex.match(geo_input)
if wkt_m: if wkt_m:
# Handling WKT input. # Handling WKT input.
if wkt_m.group('srid'): srid = int(wkt_m.group('srid')) if wkt_m.group('srid'): srid = int(wkt_m.group('srid'))
g = wkt_r().read(wkt_m.group('wkt')) g = wkt_r().read(force_bytes(wkt_m.group('wkt')))
elif hex_regex.match(geo_input): elif hex_regex.match(geo_input):
# Handling HEXEWKB input. # Handling HEXEWKB input.
g = wkb_r().read(geo_input) g = wkb_r().read(force_bytes(geo_input))
elif gdal.HAS_GDAL and json_regex.match(geo_input): elif gdal.HAS_GDAL and json_regex.match(geo_input):
# Handling GeoJSON input. # Handling GeoJSON input.
g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb) g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb)
@ -217,7 +219,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
@property @property
def geom_type(self): def geom_type(self):
"Returns a string representing the Geometry type, e.g. 'Polygon'" "Returns a string representing the Geometry type, e.g. 'Polygon'"
return capi.geos_type(self.ptr) return capi.geos_type(self.ptr).decode()
@property @property
def geom_typeid(self): def geom_typeid(self):
@ -284,7 +286,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
""" """
if not GEOS_PREPARE: if not GEOS_PREPARE:
raise GEOSException('Upgrade GEOS to 3.1 to get validity reason.') raise GEOSException('Upgrade GEOS to 3.1 to get validity reason.')
return capi.geos_isvalidreason(self.ptr) return capi.geos_isvalidreason(self.ptr).decode()
#### Binary predicates. #### #### Binary predicates. ####
def contains(self, other): def contains(self, other):
@ -338,7 +340,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
""" """
if not isinstance(pattern, six.string_types) or len(pattern) > 9: if not isinstance(pattern, six.string_types) or len(pattern) > 9:
raise GEOSException('invalid intersection matrix pattern') raise GEOSException('invalid intersection matrix pattern')
return capi.geos_relatepattern(self.ptr, other.ptr, pattern) return capi.geos_relatepattern(self.ptr, other.ptr, force_bytes(pattern))
def touches(self, other): def touches(self, other):
""" """
@ -380,7 +382,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().write(self) return wkt_w().write(self).decode()
@property @property
def hex(self): def hex(self):
@ -590,7 +592,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
def relate(self, other): def relate(self, other):
"Returns the DE-9IM intersection matrix for this Geometry and the other." "Returns the DE-9IM intersection matrix for this Geometry and the other."
return capi.geos_relate(self.ptr, other.ptr) return capi.geos_relate(self.ptr, other.ptr).decode()
def simplify(self, tolerance=0.0, preserve_topology=False): def simplify(self, tolerance=0.0, preserve_topology=False):
""" """

View File

@ -57,6 +57,7 @@ lgeos = CDLL(lib_path)
# typedef void (*GEOSMessageHandler)(const char *fmt, ...); # typedef void (*GEOSMessageHandler)(const char *fmt, ...);
NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p) NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
def notice_h(fmt, lst, output_h=sys.stdout): def notice_h(fmt, lst, output_h=sys.stdout):
fmt, lst = fmt.decode(), lst.decode()
try: try:
warn_msg = fmt % lst warn_msg = fmt % lst
except: except:
@ -66,6 +67,7 @@ notice_h = NOTICEFUNC(notice_h)
ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p) ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
def error_h(fmt, lst, output_h=sys.stderr): def error_h(fmt, lst, output_h=sys.stderr):
fmt, lst = fmt.decode(), lst.decode()
try: try:
err_msg = fmt % lst err_msg = fmt % lst
except: except:

View File

@ -8,6 +8,7 @@ from django.contrib.gis.geos.prototypes.geom import c_uchar_p, geos_char_p
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
from django.utils import six from django.utils import six
from django.utils.encoding import force_bytes
### The WKB/WKT Reader/Writer structures and pointers ### ### The WKB/WKT Reader/Writer structures and pointers ###
class WKTReader_st(Structure): pass class WKTReader_st(Structure): pass
@ -121,8 +122,9 @@ class _WKTReader(IOBase):
ptr_type = WKT_READ_PTR ptr_type = WKT_READ_PTR
def read(self, wkt): def read(self, wkt):
if not isinstance(wkt, six.string_types): raise TypeError if not isinstance(wkt, (bytes, six.string_types)):
return wkt_reader_read(self.ptr, wkt) raise TypeError
return wkt_reader_read(self.ptr, force_bytes(wkt))
class _WKBReader(IOBase): class _WKBReader(IOBase):
_constructor = wkb_reader_create _constructor = wkb_reader_create
@ -134,7 +136,7 @@ class _WKBReader(IOBase):
if isinstance(wkb, memoryview): if isinstance(wkb, memoryview):
wkb_s = bytes(wkb) wkb_s = bytes(wkb)
return wkb_reader_read(self.ptr, wkb_s, len(wkb_s)) return wkb_reader_read(self.ptr, wkb_s, len(wkb_s))
elif isinstance(wkb, six.string_types): elif isinstance(wkb, (bytes, six.string_types)):
return wkb_reader_read_hex(self.ptr, wkb, len(wkb)) return wkb_reader_read_hex(self.ptr, wkb, len(wkb))
else: else:
raise TypeError raise TypeError
@ -189,8 +191,8 @@ class WKBWriter(IOBase):
return bool(ord(wkb_writer_get_include_srid(self.ptr))) return bool(ord(wkb_writer_get_include_srid(self.ptr)))
def _set_include_srid(self, include): def _set_include_srid(self, include):
if bool(include): flag = chr(1) if bool(include): flag = b'\x01'
else: flag = chr(0) else: flag = b'\x00'
wkb_writer_set_include_srid(self.ptr, flag) wkb_writer_set_include_srid(self.ptr, flag)
srid = property(_get_include_srid, _set_include_srid) srid = property(_get_include_srid, _set_include_srid)

View File

@ -1,6 +1,10 @@
from __future__ import unicode_literals
import ctypes import ctypes
import json import json
import random import random
from binascii import a2b_hex, b2a_hex
from io import BytesIO
from django.contrib.gis import memoryview from django.contrib.gis import memoryview
from django.contrib.gis.geos import (GEOSException, GEOSIndexError, GEOSGeometry, from django.contrib.gis.geos import (GEOSException, GEOSIndexError, GEOSGeometry,
@ -10,6 +14,7 @@ from django.contrib.gis.geos.base import gdal, numpy, GEOSBase
from django.contrib.gis.geos.libgeos import GEOS_PREPARE from django.contrib.gis.geos.libgeos import GEOS_PREPARE
from django.contrib.gis.geometry.test_data import TestDataMixin from django.contrib.gis.geometry.test_data import TestDataMixin
from django.utils.encoding import force_bytes
from django.utils import six from django.utils import six
from django.utils.six.moves import xrange from django.utils.six.moves import xrange
from django.utils import unittest from django.utils import unittest
@ -65,7 +70,7 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
# result in a TypeError when trying to assign it to the `ptr` property. # result in a TypeError when trying to assign it to the `ptr` property.
# Thus, memmory addresses (integers) and pointers of the incorrect type # Thus, memmory addresses (integers) and pointers of the incorrect type
# (in `bad_ptrs`) will not be allowed. # (in `bad_ptrs`) will not be allowed.
bad_ptrs = (5, ctypes.c_char_p('foobar')) bad_ptrs = (5, ctypes.c_char_p(b'foobar'))
for bad_ptr in bad_ptrs: for bad_ptr in bad_ptrs:
# Equivalent to `fg.ptr = bad_ptr` # Equivalent to `fg.ptr = bad_ptr`
self.assertRaises(TypeError, fg1._set_ptr, bad_ptr) self.assertRaises(TypeError, fg1._set_ptr, bad_ptr)
@ -81,18 +86,16 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
"Testing HEX output." "Testing HEX output."
for g in self.geometries.hex_wkt: for g in self.geometries.hex_wkt:
geom = fromstr(g.wkt) geom = fromstr(g.wkt)
self.assertEqual(g.hex, geom.hex) self.assertEqual(g.hex, geom.hex.decode())
def test_hexewkb(self): def test_hexewkb(self):
"Testing (HEX)EWKB output." "Testing (HEX)EWKB output."
from binascii import a2b_hex
# For testing HEX(EWKB). # For testing HEX(EWKB).
ogc_hex = '01010000000000000000000000000000000000F03F' ogc_hex = b'01010000000000000000000000000000000000F03F'
# `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));` # `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));`
hexewkb_2d = '0101000020E61000000000000000000000000000000000F03F' hexewkb_2d = b'0101000020E61000000000000000000000000000000000F03F'
# `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));` # `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));`
hexewkb_3d = '01010000A0E61000000000000000000000000000000000F03F0000000000000040' hexewkb_3d = b'01010000A0E61000000000000000000000000000000000F03F0000000000000040'
pnt_2d = Point(0, 1, srid=4326) pnt_2d = Point(0, 1, srid=4326)
pnt_3d = Point(0, 1, 2, srid=4326) pnt_3d = Point(0, 1, 2, srid=4326)
@ -165,11 +168,10 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
def test_wkb(self): def test_wkb(self):
"Testing WKB output." "Testing WKB output."
from binascii import b2a_hex
for g in self.geometries.hex_wkt: for g in self.geometries.hex_wkt:
geom = fromstr(g.wkt) geom = fromstr(g.wkt)
wkb = geom.wkb wkb = geom.wkb
self.assertEqual(b2a_hex(wkb).upper(), g.hex) self.assertEqual(b2a_hex(wkb).decode().upper(), g.hex)
def test_create_hex(self): def test_create_hex(self):
"Testing creation from HEX." "Testing creation from HEX."
@ -181,9 +183,8 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
def test_create_wkb(self): def test_create_wkb(self):
"Testing creation from WKB." "Testing creation from WKB."
from binascii import a2b_hex
for g in self.geometries.hex_wkt: for g in self.geometries.hex_wkt:
wkb = memoryview(a2b_hex(g.hex)) wkb = memoryview(a2b_hex(g.hex.encode()))
geom_h = GEOSGeometry(wkb) geom_h = GEOSGeometry(wkb)
# we need to do this so decimal places get normalised # we need to do this so decimal places get normalised
geom_t = fromstr(g.wkt) geom_t = fromstr(g.wkt)
@ -213,13 +214,12 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
def test_fromfile(self): def test_fromfile(self):
"Testing the fromfile() factory." "Testing the fromfile() factory."
from io import BytesIO
ref_pnt = GEOSGeometry('POINT(5 23)') ref_pnt = GEOSGeometry('POINT(5 23)')
wkt_f = BytesIO() wkt_f = BytesIO()
wkt_f.write(ref_pnt.wkt) wkt_f.write(force_bytes(ref_pnt.wkt))
wkb_f = BytesIO() wkb_f = BytesIO()
wkb_f.write(str(ref_pnt.wkb)) wkb_f.write(bytes(ref_pnt.wkb))
# Other tests use `fromfile()` on string filenames so those # Other tests use `fromfile()` on string filenames so those
# aren't tested here. # aren't tested here.
@ -440,8 +440,8 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
self.assertEqual(r.geom_typeid, 2) self.assertEqual(r.geom_typeid, 2)
# Testing polygon construction. # Testing polygon construction.
self.assertRaises(TypeError, Polygon.__init__, 0, [1, 2, 3]) self.assertRaises(TypeError, Polygon, 0, [1, 2, 3])
self.assertRaises(TypeError, Polygon.__init__, 'foo') self.assertRaises(TypeError, Polygon, 'foo')
# Polygon(shell, (hole1, ... holeN)) # Polygon(shell, (hole1, ... holeN))
rings = tuple(r for r in poly) rings = tuple(r for r in poly)

View File

@ -1,3 +1,5 @@
from __future__ import unicode_literals
import binascii import binascii
import unittest import unittest
@ -5,6 +7,7 @@ from django.contrib.gis import memoryview
from django.contrib.gis.geos import GEOSGeometry, WKTReader, WKTWriter, WKBReader, WKBWriter, geos_version_info from django.contrib.gis.geos import GEOSGeometry, WKTReader, WKTWriter, WKBReader, WKBWriter, geos_version_info
from django.utils import six from django.utils import six
class GEOSIOTest(unittest.TestCase): class GEOSIOTest(unittest.TestCase):
def test01_wktreader(self): def test01_wktreader(self):
@ -14,8 +17,8 @@ class GEOSIOTest(unittest.TestCase):
# read() should return a GEOSGeometry # read() should return a GEOSGeometry
ref = GEOSGeometry(wkt) ref = GEOSGeometry(wkt)
g1 = wkt_r.read(wkt) g1 = wkt_r.read(wkt.encode())
g2 = wkt_r.read(six.text_type(wkt)) g2 = wkt_r.read(wkt)
for geom in (g1, g2): for geom in (g1, g2):
self.assertEqual(ref, geom) self.assertEqual(ref, geom)
@ -102,7 +105,7 @@ class GEOSIOTest(unittest.TestCase):
self.assertEqual(hex3d, wkb_w.write_hex(g)) self.assertEqual(hex3d, wkb_w.write_hex(g))
self.assertEqual(wkb3d, wkb_w.write(g)) self.assertEqual(wkb3d, wkb_w.write(g))
# Telling the WKBWriter to inlcude the srid in the representation. # Telling the WKBWriter to include the srid in the representation.
wkb_w.srid = True wkb_w.srid = True
self.assertEqual(hex3d_srid, wkb_w.write_hex(g)) self.assertEqual(hex3d_srid, wkb_w.write_hex(g))
self.assertEqual(wkb3d_srid, wkb_w.write(g)) self.assertEqual(wkb3d_srid, wkb_w.write(g))