summaryrefslogtreecommitdiff
path: root/chimere/utils.py
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2018-07-20 08:49:24 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2018-07-20 08:49:24 +0200
commita35e06313dfb7e9f1760967101497dbe462535a5 (patch)
tree7b1e33d7ebb1f3244d27b90358acd9d309b86fd5 /chimere/utils.py
parent5a125c7b742130fb8dd87543fb42e8ffb9203762 (diff)
downloadChimère-a35e06313dfb7e9f1760967101497dbe462535a5.tar.bz2
Chimère-a35e06313dfb7e9f1760967101497dbe462535a5.zip
Change python binding for overpass API
Diffstat (limited to 'chimere/utils.py')
-rw-r--r--chimere/utils.py112
1 files changed, 96 insertions, 16 deletions
diff --git a/chimere/utils.py b/chimere/utils.py
index a5772d7..607ec36 100644
--- a/chimere/utils.py
+++ b/chimere/utils.py
@@ -39,7 +39,7 @@ import zipfile
from osgeo import ogr, osr
from osmapi import OsmApi
-import overpass
+import overpy
from lxml import etree
from django.conf import settings
@@ -964,7 +964,7 @@ RE_HOOK = re.compile('\[([^\]]*)\]')
# TODO: manage deleted item from OSM
-class OSMManager(JsonManager):
+class OSMManager(ImportManager):
"""
OSM importer/exporter
The source url is a path to an OSM file or a Overpass url
@@ -972,27 +972,107 @@ class OSMManager(JsonManager):
"""
default_source = settings.CHIMERE_OVERPASS_URL
+ def _get_attributes(self, item, filtr):
+ dct = {}
+ for k in filtr:
+ value = item.tags.get(filtr[k], None)
+ if value:
+ dct[k] = value
+ return dct
+
def parse_overpass(self):
- api = overpass.API(endpoint=self.default_source,
- timeout=600)
- response = api.get(self.importer_instance.source)
+ from chimere.models import Marker, Route, Polygon
+
+ new_item, updated_item, msg = 0, 0, ''
+
+ api = overpy.Overpass(url=self.default_source)
- if not response or "features" not in response:
+ if not self.importer_instance.source:
+ return (
+ new_item, updated_item,
+ _("Bad configuration: a source query must be defined"))
+
+ try:
+ result = api.query(self.importer_instance.source)
+ except overpy.exception.OverpassBadRequest as e:
+ return (
+ 0, 0,
+ str(
+ _("Bad overpass query: {}.")
+ ).format(e)
+ )
+ except overpy.exception.OverPyException as e:
return (
0, 0,
str(
- _("Bad response from OSM server: {}. Check your overpass "
- "string and that overpass servre is up.")
- ).format(self.default_source)
+ _("Request error from OSM Overpass server: {}.")
+ ).format(e)
)
- default_filtr = {
- 'coordinates': {'geometry': 'coordinates'},
- 'id': 'id',
- 'name': {'properties': 'name'},
- 'geom_type': {'geometry': 'type'}
- }
- return self._parse_json(response['features'], default_filtr)
+ filtr = {}
+ if self.importer_instance.filtr:
+ try:
+ filtr = json.JSONDecoder().decode(self.importer_instance.filtr)
+ except ValueError:
+ return (
+ new_item, updated_item,
+ _("Bad configuration: filter field must be a valid "
+ "JSON string"))
+
+ filtr['name'] = "name"
+
+ default_dct = {'origin': self.importer_instance.origin,
+ 'license': self.importer_instance.license,
+ 'description': ""}
+
+ if 'prefix_name' in filtr:
+ default_dct['name'] = filtr.pop('prefix_name')
+ if 'prefix_description' in filtr:
+ default_dct['description'] = filtr.pop('prefix_description')
+
+ for way in result.ways:
+ dct = deepcopy(default_dct)
+ dct.update(self._get_attributes(way, filtr))
+ pl_id = "OSM-way-{}".format(node.id)
+
+ if not way.nodes or len(way.nodes) == 1:
+ # not a real way
+ continue
+
+ if way.nodes[0].id == way.nodes[-1].id:
+ # is a closed way
+ if len(way.nodes) == 2:
+ # not a real way
+ continue
+ cls = Polygon
+ wkt_base = "SRID=4326;POLYGON((%s))"
+ else:
+ cls = Route
+ wkt_base = "SRID=4326;LINESTRING(%s)"
+
+ dct[cls.geom_attr] = wkt_base % ",".join(
+ ["{} {}".format(node.lon, node.lat)
+ for node in way.get_nodes(resolve_missing=True)]
+ )
+ it, updated, created = self.create_or_update_item(cls, dct, pl_id)
+ if updated:
+ updated_item += 1
+ if created:
+ new_item += 1
+
+ for node in result.nodes:
+ cls = Marker
+ dct = deepcopy(default_dct)
+ dct.update(self._get_attributes(node, filtr))
+ pl_id = "OSM-node-{}".format(node.id)
+ dct['point'] = 'SRID=4326;POINT({} {})'.format(node.lon, node.lat)
+ it, updated, created = self.create_or_update_item(cls, dct, pl_id)
+ if updated:
+ updated_item += 1
+ if created:
+ new_item += 1
+
+ return new_item, updated_item, msg
def get(self):
"""