summaryrefslogtreecommitdiff
path: root/chimere/utils.py
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@peacefrogs.net>2012-05-04 20:29:41 +0200
committerÉtienne Loks <etienne.loks@peacefrogs.net>2012-05-04 20:29:41 +0200
commit4c22ae3b7b939a2d7a036e93939c22c3c27f82c2 (patch)
tree383df9430ec2d2ce7aaf5d5ce7e458d33853524a /chimere/utils.py
parentd203d7581c847c86b68ff51eeb923d92f9ce0f13 (diff)
downloadChimère-4c22ae3b7b939a2d7a036e93939c22c3c27f82c2.tar.bz2
Chimère-4c22ae3b7b939a2d7a036e93939c22c3c27f82c2.zip
Shapefile import
Diffstat (limited to 'chimere/utils.py')
-rw-r--r--chimere/utils.py138
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\[([^\]]*)\]')