diff options
Diffstat (limited to 'chimere/utils.py')
-rw-r--r-- | chimere/utils.py | 138 |
1 files changed, 131 insertions, 7 deletions
diff --git a/chimere/utils.py b/chimere/utils.py index 268ec3b..3266548 100644 --- a/chimere/utils.py +++ b/chimere/utils.py @@ -21,19 +21,25 @@ Utilitaries """ +import os import tempfile -import urllib2, re +import re +import urllib2 import unicodedata import zipfile import StringIO -from external_utils import OsmApi + from lxml import etree -from chimere import get_version +from osgeo import osr from django.conf import settings +from django.contrib.gis.gdal import DataSource from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import ugettext_lazy as _ +from chimere import get_version +from external_utils import OsmApi + def unicode_normalize(string): return ''.join( (c for c in unicodedata.normalize('NFD', string) @@ -53,7 +59,7 @@ class ImportManager: pass @classmethod - def get_files_inside_zip(cls, zippedfile, suffixes): + def get_files_inside_zip(cls, zippedfile, suffixes, dest_dir=None): try: flz = zipfile.ZipFile(zippedfile) except zipfile.BadZipfile: @@ -71,12 +77,16 @@ class ImportManager: files = [] for filename in filenames: if filename: - files.append(flz.open(filename)) + if dest_dir: + files.append(filename) + flz.extract(filename, dest_dir) + else: + files.append(flz.open(filename)) else: files.append(None) return files - def get_source_file(self, source, suffixes): + def get_source_file(self, source, suffixes, dest_dir=None): if not source: try: remotehandle = urllib2.urlopen(self.importer_instance.source) @@ -92,7 +102,7 @@ class ImportManager: return (None, error.message) if self.importer_instance.zipped: try: - files = self.get_files_inside_zip(source, suffixes) + files = self.get_files_inside_zip(source, suffixes, dest_dir) except zipfile.BadZipfile: return (None, _(u"Bad zip file")) if not files or None in files: @@ -182,6 +192,120 @@ class KMLManager(ImportManager): m.categories.add(cat) return (new_item, updated_item, msg) +class ShapefileManager(ImportManager): + u""" + Shapefile importer + """ + def __init__(self, importer_instance): + self.importer_instance = importer_instance + + def get(self, source=None): + u""" + Get data from the source + Args: + - source (None): input file if not provided get it from the distant + source provided in the importer instance. + + Return a tuple with: + - number of new item ; + - number of item updated ; + - error detail on error + """ + from models import Marker + new_item, updated_item, msg = 0, 0, '' + tmpdir = tempfile.mkdtemp() + sources, msg = self.get_source_file(source, + ['.shp', '.dbf', '.prj', '.shx'], + dest_dir=tmpdir) + if msg: + return (0, 0, msg) + if not sources: + return (0, 0, _(u"Error while reading the data source.")) + # get the srid + srid = self.importer_instance.srid + if not srid: + prjfilename = tmpdir + os.sep + sources[2] + with open(prjfilename, 'r') as prj_file: + prj_txt = prj_file.read() + srs = osr.SpatialReference() + srs.ImportFromESRI([prj_txt]) + srs.AutoIdentifyEPSG() + srid = srs.GetAuthorityCode(None) + if not srid: + # try with the default projection + srid = settings.CHIMERE_EPSG_DISPLAY_PROJECTION + shapefilename = tmpdir + os.sep + sources[0] + ds = DataSource(shapefilename) + lyr = ds[0] + if lyr.geom_type not in ('Point',): + return (0, 0, _(u"Type of geographic item of this shapefile " + u"is not managed by Chimère.")) + # for this first version it is assumed that the first field is a + # id name and the second field is the name + id_name = lyr.fields[0] if len(lyr.fields) > 0 else None + # test if id_name is well guess + if id_name: + ids = lyr.get_fields(id_name) + if len(ids) != len(set(ids)): + id_name = None + lbl_name = None + if len(lyr.fields) > 1: + lbl_name = lyr.fields[1] + elif id_name: + lbl_name = id_name + indexes = [] + for idx, feat in enumerate(lyr): + name = unicode(idx) + if lbl_name: + name = feat.get(lbl_name) + try: + name = unicode(name) + except UnicodeDecodeError: + try: + name = unicode( + name.decode(settings.CHIMERE_SHAPEFILE_ENCODING)) + except: + continue + geom = feat.geom.wkt + dct = {'point':'SRID=%s;%s' % (srid, feat.geom.wkt), + 'name':name + } + m = None + if id_name: + c_id = feat.get(id_name) + dct_import = { + 'import_key__icontains':'%s:%s;' % (id_name, c_id), + 'import_source':self.importer_instance.source} + try: + m = Marker.objects.get(**dct_import) + for k in dct: + setattr(m, k, dct[k]) + m.save() + updated_item += 1 + except ObjectDoesNotExist: + m = None + dct.update({ + 'import_source':self.importer_instance.source}) + if not m: + dct['status'] = 'I' + m = Marker.objects.create(**dct) + new_item += 1 + if id_name: + m.set_key(id_name, c_id) + m.categories.clear() + for cat in self.importer_instance.categories.all(): + m.categories.add(cat) + # clean up + tmpdirs = set() + for src in sources: + dirs = os.sep.join(src.split(os.sep)[:-1]) + if dirs: + tmpdirs.add(tmpdir + os.sep + dirs) + os.remove(tmpdir + os.sep + src) + for dr in tmpdirs: + os.removedirs(dr) + return (new_item, updated_item, msg) + RE_NODE = re.compile('node\[([^\]]*)\]') |