Commit 9a2bceed authored by Claude Paroz's avatar Claude Paroz
Browse files

Use smarter string decoding in GeoDjango

The first try to solve the Python 3 GIS encoding/decoding issue
was too naive. Using decode() on all read strings is bound to fail
as soon as a non-ascii string is concerned.
This patch is a little more clever, leaving ascii decoding when
plain ascii strings are expected, and allowing to specify a custom
encoding in DataSource hierarchy.
parent a62d53c0
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ from django.contrib.gis.gdal.layer import Layer
# Getting the ctypes prototypes for the DataSource.
from django.contrib.gis.gdal.prototypes import ds as capi

from django.utils.encoding import force_bytes
from django.utils.encoding import force_bytes, force_text
from django.utils import six
from django.utils.six.moves import xrange

@@ -57,12 +57,14 @@ class DataSource(GDALBase):
    "Wraps an OGR Data Source object."

    #### Python 'magic' routines ####
    def __init__(self, ds_input, ds_driver=False, write=False):
    def __init__(self, ds_input, ds_driver=False, write=False, encoding='utf-8'):
        # The write flag.
        if write:
            self._write = 1
        else:
            self._write = 0
        # See also http://trac.osgeo.org/gdal/wiki/rfc23_ogr_unicode
        self.encoding = encoding

        # Registering all the drivers, this needs to be done
        #  _before_ we try to open up a data source.
@@ -129,4 +131,5 @@ class DataSource(GDALBase):
    @property
    def name(self):
        "Returns the name of the data source."
        return capi.get_ds_name(self._ptr)
        name = capi.get_ds_name(self._ptr)
        return force_text(name, self.encoding, strings_only=True)
+7 −2
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
# ctypes function prototypes
from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api

from django.utils.encoding import force_bytes
from django.utils.encoding import force_bytes, force_text
from django.utils import six
from django.utils.six.moves import xrange

@@ -68,6 +68,10 @@ class Feature(GDALBase):
        return bool(capi.feature_equal(self.ptr, other._ptr))

    #### Feature Properties ####
    @property
    def encoding(self):
        return self._layer._ds.encoding

    @property
    def fid(self):
        "Returns the feature identifier."
@@ -76,7 +80,8 @@ class Feature(GDALBase):
    @property
    def layer_name(self):
        "Returns the name of the layer for the feature."
        return capi.get_feat_name(self._layer._ldefn)
        name = capi.get_feat_name(self._layer._ldefn)
        return force_text(name, self.encoding, strings_only=True)

    @property
    def num_fields(self):
+6 −2
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ from datetime import date, datetime, time
from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import OGRException
from django.contrib.gis.gdal.prototypes import ds as capi
from django.utils.encoding import force_text


# For more information, see the OGR C API source code:
#  http://www.gdal.org/ogr/ogr__api_8h.html
@@ -53,7 +55,8 @@ class Field(GDALBase):

    def as_string(self):
        "Retrieves the Field's value as a string."
        return capi.get_field_as_string(self._feat.ptr, self._index)
        string = capi.get_field_as_string(self._feat.ptr, self._index)
        return force_text(string, encoding=self._feat.encoding, strings_only=True)

    def as_datetime(self):
        "Retrieves the Field's value as a tuple of date & time components."
@@ -70,7 +73,8 @@ class Field(GDALBase):
    @property
    def name(self):
        "Returns the name of this Field."
        return capi.get_field_name(self.ptr)
        name = capi.get_field_name(self.ptr)
        return force_text(name, encoding=self._feat.encoding, strings_only=True)

    @property
    def precision(self):
+6 −4
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ from django.contrib.gis.gdal.srs import SpatialReference
# GDAL ctypes function prototypes.
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.encoding import force_bytes, force_text
from django.utils import six
from django.utils.six.moves import xrange

@@ -103,7 +103,8 @@ class Layer(GDALBase):
    @property
    def name(self):
        "Returns the name of this layer in the Data Source."
        return capi.get_fd_name(self._ldefn)
        name = capi.get_fd_name(self._ldefn)
        return force_text(name, self._ds.encoding, strings_only=True)

    @property
    def num_feat(self, force=1):
@@ -135,7 +136,8 @@ class Layer(GDALBase):
        Returns a list of string names corresponding to each of the Fields
        available in this Layer.
        """
        return [capi.get_field_name(capi.get_field_defn(self._ldefn, i))
        return [force_text(capi.get_field_name(capi.get_field_defn(self._ldefn, i)),
                           self._ds.encoding, strings_only=True)
                for i in xrange(self.num_fields)]

    @property
+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ cleanup_all = void_output(lgdal.OGRCleanupAll, [], errcheck=False)
get_driver = voidptr_output(lgdal.OGRGetDriver, [c_int])
get_driver_by_name = voidptr_output(lgdal.OGRGetDriverByName, [c_char_p])
get_driver_count = int_output(lgdal.OGRGetDriverCount, [])
get_driver_name = const_string_output(lgdal.OGR_Dr_GetName, [c_void_p])
get_driver_name = const_string_output(lgdal.OGR_Dr_GetName, [c_void_p], decoding='ascii')

### DataSource ###
open_ds = voidptr_output(lgdal.OGROpen, [c_char_p, c_int, POINTER(c_void_p)])
Loading