11import requests
22import json
3+ import csv
34import geojson
45import logging
5-
6+ from io import StringIO
67from .errors import (OverpassSyntaxError , TimeoutError , MultipleRequestsError ,
78 ServerLoadError , UnknownOverpassError , ServerRuntimeError )
89
910
1011class API (object ):
1112 """A simple Python wrapper for the OpenStreetMap Overpass API."""
1213
13- SUPPORTED_FORMATS = ["geojson" , "json" , "xml" ]
14+ SUPPORTED_FORMATS = ["geojson" , "json" , "xml" , "csv" ]
1415
1516 # defaults for the API class
1617 _timeout = 25 # second
@@ -43,30 +44,40 @@ def __init__(self, *args, **kwargs):
4344 requests_log .setLevel (logging .DEBUG )
4445 requests_log .propagate = True
4546
46- def Get (self ,
47+ def get (self ,
4748 query ,
4849 responseformat = "geojson" ,
4950 verbosity = "body" ,
5051 build = True ):
5152 """Pass in an Overpass query in Overpass QL."""
5253 # Construct full Overpass query
5354 if build :
54- full_query = self ._ConstructQLQuery (query ,
55- responseformat = responseformat ,
56- verbosity = verbosity )
55+ full_query = self ._construct_ql_query (
56+ query ,
57+ responseformat = responseformat ,
58+ verbosity = verbosity )
5759 else :
5860 full_query = query
5961
6062 if self .debug :
6163 logging .getLogger ().info (query )
6264
6365 # Get the response from Overpass
64- raw_response = self ._GetFromOverpass (full_query )
66+ r = self ._get_from_overpass (full_query )
67+ content_type = r .headers .get ('content-type' )
6568
66- if responseformat == "xml" or responseformat .startswith ("csv" ):
67- return raw_response
69+ if self .debug :
70+ print (content_type )
71+ if content_type == "text/csv" :
72+ result = []
73+ reader = csv .reader (StringIO (r .text ), delimiter = '\t ' )
74+ for row in reader :
75+ result .append (row )
76+ return result
77+ elif content_type == "text/xml" or content_type == "application/xml" :
78+ return r .text
6879
69- response = json .loads (raw_response )
80+ response = json .loads (r )
7081
7182 # Check for valid answer from Overpass.
7283 # A valid answer contains an 'elements' key at the root level.
@@ -83,13 +94,17 @@ def Get(self,
8394 return response
8495
8596 # construct geojson
86- return self ._asGeoJSON (response ["elements" ])
97+ return self ._as_geojson (response ["elements" ])
8798
88- def Search (self , feature_type , regex = False ):
99+ def search (self , feature_type , regex = False ):
89100 """Search for something."""
90101 raise NotImplementedError ()
91102
92- def _ConstructQLQuery (self , userquery , responseformat , verbosity ):
103+ # deprecation of upper case functions
104+ Get = get
105+ Search = search
106+
107+ def _construct_ql_query (self , userquery , responseformat , verbosity ):
93108 raw_query = str (userquery )
94109 if not raw_query .endswith (";" ):
95110 raw_query += ";"
@@ -110,10 +125,7 @@ def _ConstructQLQuery(self, userquery, responseformat, verbosity):
110125 print (complete_query )
111126 return complete_query
112127
113- def _GetFromOverpass (self , query ):
114- """This sends the API request to the Overpass instance and
115- returns the raw result, or an error."""
116-
128+ def _get_from_overpass (self , query ):
117129 payload = {"data" : query }
118130
119131 try :
@@ -141,20 +153,22 @@ def _GetFromOverpass(self, query):
141153 code = self ._status ))
142154 else :
143155 r .encoding = 'utf-8'
144- return r . text
156+ return r
145157
146- def _asGeoJSON (self , elements ):
158+ def _as_geojson (self , elements ):
147159
148160 features = []
149161 for elem in elements :
150- elem_type = elem [ "type" ]
151- if elem_type == "node" :
152- geometry = geojson .Point ((elem [ "lon" ] , elem [ "lat" ] ))
153- elif elem_type == "way" :
162+ elem_type = elem . get ( "type" )
163+ if elem_type and elem_type == "node" :
164+ geometry = geojson .Point ((elem . get ( "lon" ) , elem . get ( "lat" ) ))
165+ elif elem_type and elem_type == "way" :
154166 points = []
155- for coords in elem ["geometry" ]:
156- points .append ((coords ["lon" ], coords ["lat" ]))
157- geometry = geojson .LineString (points )
167+ geom = elem .get ("geometry" )
168+ if geom :
169+ for coords in elem .get ("geometry" ):
170+ points .append ((coords ["lon" ], coords ["lat" ]))
171+ geometry = geojson .LineString (points )
158172 else :
159173 continue
160174
0 commit comments