def _query_metadata(self): """ Send ohsome GET request :param params: parameters of the request as in ohsome documentation :return: """ self._url = self._base_api_url + "/metadata" try: response = self._session().get(self._url) response.raise_for_status() except requests.exceptions.ConnectionError: raise OhsomeException( message= "Connection Error: Query could not be sent. Make sure there are no network " f"problems and that the ohsome API URL {self._url} is valid.", url=self._url, params=self._parameters, ) except requests.exceptions.HTTPError as e: raise OhsomeException( message=e.response.json()["message"], url=self._url, params=self._parameters, error_code=e.response.status_code, ) else: self._metadata = response.json()
def format_bcircles(bcircles): """ Formats bcircles parameter to comply with ohsome API :param bcircles: Centroids and radius of the circles given as string (lon,lat,radius|lon,lat,radius|… or id1:lon,lat,radius|id2:lon,lat,radius|…) list ([[id1:lon1,lat1,radius],[id2:lon1,lat1,radius],...] pandas.DataFrame with columns 'lon', 'lat' and 'radius' or geopandas.GeoDataFrame with geometry column with Point geometries only and a column 'radius'. :return: """ if isinstance(bcircles, str): return bcircles elif isinstance(bcircles, list) or isinstance(bcircles, tuple): if isinstance(bcircles[0], list): return "|".join( [",".join([str(x) for x in box]) for box in bcircles]) elif isinstance(bcircles[1], float) or isinstance(bcircles[1], int): return ",".join([str(x) for x in bcircles]) elif isinstance(bcircles[0], str) and (bcircles[0].find(",") != -1): return "|".join([str(c) for c in bcircles]) else: raise OhsomeException("'bcircles' parameter has invalid format.") elif isinstance(bcircles, dict): return "|".join([ f"{id}:" + ",".join([str(c) for c in coords]) for id, coords in bcircles.items() ]) elif isinstance(bcircles, gpd.GeoDataFrame): if bcircles.geometry.geom_type.unique() != ["Point"]: raise OhsomeException( message= "The geometry of the 'bcircles' GeoDataFrame may only include 'Point' geometry types." ) formatted = bcircles.apply( lambda r: f"{int(r.name)}:{r.geometry.x},{r.geometry.y},{r['radius']}", axis=1, ) return "|".join(formatted.to_list()) elif isinstance(bcircles, pd.DataFrame): try: formatted = bcircles.apply( lambda r: f"{int(r.name)}:{r['lon']},{r['lat']},{r['radius']}", axis=1, ) return "|".join(formatted.to_list()) except KeyError as e: raise OhsomeException( message= f"Column {e} is missing in the dataframe provided as 'bboxes'." ) else: raise OhsomeException( message="'bcircles' parameter has invalid format.")
def format_bboxes(bboxes): """ Formats bboxes parameter to comply with ohsome API :param bboxes: Bounding boxes given as string: lon1,lat1,lon2,lat2|lon1,lat1,lon2,lat2|… or id1:lon1,lat1,lon2,lat2|id2:lon1,lat1,lon2,lat2|… list: [[id1,lon1,lat1,lon2,lat2],[id2,lon1,lat1,lon2,lat2],...] or [lon1,lat1,lon2,lat2] if it's just one box pandas.DataFrame: with columns minx, miny, maxx, maxy. These columns can be created from a GeoDataFrame using the 'GeoDataFrame.bounds' method. :return: Bounding boxes formatted as a string compliant with ohsome API """ if isinstance(bboxes, list) or isinstance(bboxes, tuple): if isinstance(bboxes[0], list): return "|".join( [",".join([str(x) for x in box]) for box in bboxes]) elif isinstance(bboxes[1], float) or isinstance(bboxes[1], int): return ",".join([str(x) for x in bboxes]) elif isinstance(bboxes[0], str) and (bboxes[0].find(",") != -1): return "|".join([str(c) for c in bboxes]) else: raise OhsomeException( message="'bboxes' parameter has invalid format.") elif isinstance(bboxes, dict): return "|".join([ f"{id}:" + ",".join([str(c) for c in coords]) for id, coords in bboxes.items() ]) elif isinstance(bboxes, str): return bboxes elif isinstance(bboxes, gpd.GeoDataFrame): raise OhsomeException( message= "Use the 'bpolys' parameter to specify the boundaries using a geopandas.GeoDataFrame." ) elif isinstance(bboxes, pd.DataFrame): try: formatted = bboxes.apply( lambda r: f"{r.name}:{r['minx']},{r['miny']},{r['maxx']},{r['maxy']}", axis=1, ) return "|".join(formatted.to_list()) except KeyError as e: raise OhsomeException( message= f"Column {e} is missing in the dataframe provided as 'bboxes'." ) else: raise OhsomeException( message= "'bboxes' must be given as string, list or pandas.DataFrame.")
def get(self, **params): """ Send ohsome get request :param params: parameters of the request as in ohsome documentation :return: """ url = self.construct_resource_url() self.formatted_parameters = self.format_parameters(params) try: response = requests.get(url, data=self.formatted_parameters) except requests.RequestException as e: raise OhsomeException(message=e, params=self.formatted_parameters) return self.handle_response(response)
def handle_response(self, response): """ Converts the ohsome response to an OhsomeResponse Object if query was successfull. Otherwise throws OhsomeException. :param response: :return: """ if response.status_code == 200: return OhsomeResponse(response, url=self.url, params=self.formatted_parameters) else: raise OhsomeException(response=response, url=self.url, params=self.formatted_parameters)
def _format_parameters(self, params): """ Check and format parameters of the query :param params: Parameters for request :return: """ self._parameters = params.copy() try: format_boundary(self._parameters) except OhsomeException as e: raise OhsomeException( message=str(e), error_code=440, params=self._parameters, url=self._url, ) format_time(self._parameters)
def format_boundary(params): """ Formats the boundary parameters 'bboxes', 'bcircles' and 'bpolys' :param params: :return: """ if params["bboxes"] is not None: params["bboxes"] = format_bboxes(params["bboxes"]) elif params["bpolys"] is not None: params["bpolys"] = format_bpolys(params["bpolys"]) elif params["bcircles"] is not None: params["bcircles"] = format_bcircles(params["bcircles"]) else: raise OhsomeException( message= "No valid boundary parameter is given. Specify one of the parameters 'bboxes', 'bpolys' or 'bcircles'.", error_code=440, )
def _handle_request(self): """ Handles request to ohsome API :return: """ ohsome_exception = None try: response = self._session().post(url=self._url, data=self._parameters) response.raise_for_status() response.json() except requests.exceptions.HTTPError as e: ohsome_exception = OhsomeException( message=e.response.json()["message"], url=self._url, params=self._parameters, error_code=e.response.status_code, response=e.response, ) except requests.exceptions.ConnectionError as e: ohsome_exception = OhsomeException( message= "Connection Error: Query could not be sent. Make sure there are no network " f"problems and that the ohsome API URL {self._url} is valid.", url=self._url, params=self._parameters, response=e.response, ) except requests.exceptions.RequestException as e: ohsome_exception = OhsomeException( message=str(e), url=self._url, params=self._parameters, response=e.response, ) except KeyboardInterrupt: ohsome_exception = OhsomeException( message= "Keyboard Interrupt: Query was interrupted by the user.", url=self._url, params=self._parameters, error_code=440, ) except ValueError: error_code, message = extract_error_message_from_invalid_json( response.text) ohsome_exception = OhsomeException( message=message, url=self._url, error_code=error_code, params=self._parameters, response=response, ) except AttributeError: ohsome_exception = OhsomeException( message=f"Seems like {self._url} is not a valid endpoint.", url=self._url, error_code=404, params=self._parameters, ) finally: # If there has been an error and logging is enabled, write it to file if ohsome_exception: if self.log: ohsome_exception.log(self.log_dir) raise ohsome_exception else: return OhsomeResponse(response, url=self._url, params=self._parameters)