Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: accept shapely polygonal for bpolys input #133

Merged
merged 8 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- support for python 3.12
- custom [retry](https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html#urllib3.util.Retry) configuration
- start and end timestamp meta information of the client are now datetime objects
- accept shapely Polygon and MultiPolygon for `bpolys` input parameter
- if a request fails a bash script containing the respective `curl` command is logged (if possible). This allows for easier debugging and sharing of failed requests.

### Removed
Expand Down
70 changes: 52 additions & 18 deletions ohsome/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
import datetime as dt
import json
from pathlib import Path
from typing import Union, Optional
from typing import Union, Optional, List
from urllib.parse import urljoin

import geopandas as gpd
import pandas as pd
import requests
import shapely
from requests import Session
from requests.adapters import HTTPAdapter
from requests.exceptions import RetryError
Expand Down Expand Up @@ -234,22 +237,53 @@ def __init__(

def post(
self,
bboxes=None,
bcircles=None,
bpolys=None,
time=None,
filter=None,
filter2=None,
format=None,
showMetadata=None,
timeout=None,
groupByKey=None,
groupByKeys=None,
groupByValues=None,
properties=None,
clipGeometry=None,
endpoint=None,
):
bboxes: Optional[
Union[
str,
dict,
pd.DataFrame,
List[str],
List[float],
List[List[str]],
List[List[float]],
]
] = None,
bcircles: Optional[
Union[
str,
List[str],
List[float],
List[List[str]],
List[List[float]],
dict,
gpd.GeoDataFrame,
pd.DataFrame,
]
] = None,
bpolys: Optional[
Union[
gpd.GeoDataFrame,
gpd.GeoSeries,
shapely.Polygon,
shapely.MultiPolygon,
str,
]
] = None,
time: Optional[
Union[str, dt.datetime, dt.date, list, pd.DatetimeIndex, pd.Series]
] = None,
filter: Optional[str] = None,
filter2: Optional[str] = None,
format: Optional[str] = None,
showMetadata: Optional[bool] = None,
timeout: Optional[int] = None,
groupByKey: Optional[str] = None,
groupByKeys: Optional[Union[str, List[str]]] = None,
groupByValues: Optional[Union[str, List[str]]] = None,
properties: Optional[Union[str, List[str]]] = None,
clipGeometry: Optional[bool] = None,
endpoint: Optional[str] = None,
) -> OhsomeResponse:
"""
Sends request to ohsome API

Expand All @@ -266,7 +300,7 @@ def post(
- pandas.DataFrame with columns 'lon', 'lat' and 'radius'
- geopandas.GeoDataFrame with geometry column with Point geometries only and a column 'radius'.

:param bpolys: Polygons given as geopandas.GeoDataFrame, GeoJSON FeatureCollection or str
:param bpolys: Polygons given as geopandas.GeoDataFrame, geopandas.GeoSeries, shapely.Polygon, shapely.MultiPolygon, GeoJSON FeatureCollection or str
e.g. "8.65821,49.41129,8.65821,49.41825,8.70053,8.65821|8.67817,49.42147,8.67817,49.4342,8.67817"

:param time: One or more ISO-8601 conform timestring(s) given as str, list, pandas.Series, pandas.DateTimeIndex,
Expand Down
56 changes: 48 additions & 8 deletions ohsome/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
"""Ohsome utility functions"""

import datetime
import json
import re
from typing import Tuple
from typing import Tuple, Union, List

import geopandas as gpd
import numpy as np
import pandas as pd
import shapely

from ohsome import OhsomeException

Expand Down Expand Up @@ -73,7 +75,18 @@ def format_boundary(params: dict) -> dict:
return params


def format_bcircles(bcircles):
def format_bcircles(
bcircles: Union[
str,
List[str],
List[float],
List[List[str]],
List[List[float]],
dict,
gpd.GeoDataFrame,
pd.DataFrame,
]
) -> str:
"""
Formats bcircles parameter to comply with ohsome API
:param
Expand Down Expand Up @@ -103,9 +116,12 @@ def format_bcircles(bcircles):
]
)
elif isinstance(bcircles, gpd.GeoDataFrame):
if bcircles.geometry.geom_type.unique() != ["Point"]:
if (bcircles.geometry.geom_type.unique() != ["Point"]) or (
"radius" not in bcircles.columns
):
raise OhsomeException(
message="The geometry of the 'bcircles' GeoDataFrame may only include 'Point' geometry types."
message="The geometry of the 'bcircles' GeoDataFrame may only include 'Point' geometry types and "
"requires a 'radius' column."
)
formatted = bcircles.apply(
lambda r: f"{int(r.name)}:{r.geometry.x},{r.geometry.y},{r['radius']}",
Expand All @@ -127,7 +143,17 @@ def format_bcircles(bcircles):
raise OhsomeException(message="'bcircles' parameter has invalid format.")


def format_bboxes(bboxes):
def format_bboxes(
bboxes: Union[
str,
dict,
pd.DataFrame,
List[str],
List[float],
List[List[str]],
List[List[float]],
]
) -> str:
"""
Formats bboxes parameter to comply with ohsome API
:param
Expand Down Expand Up @@ -177,17 +203,31 @@ def format_bboxes(bboxes):
)


def format_bpolys(bpolys):
def format_bpolys(
bpolys: Union[gpd.GeoDataFrame, shapely.Polygon, shapely.MultiPolygon, str]
) -> str:
"""
Formats bpolys parameter to comply with ohsome API
:param
bpolys: Polygons given as geopandas.GeoDataFrame or string formatted as GeoJSON FeatureCollection.
:return:
"""
if isinstance(bpolys, gpd.GeoDataFrame):
if isinstance(bpolys, gpd.GeoDataFrame) or isinstance(bpolys, gpd.GeoSeries):
return bpolys.to_json(na="drop")
elif isinstance(bpolys, shapely.Polygon) or isinstance(
bpolys, shapely.MultiPolygon
):
return format_bpolys(gpd.GeoDataFrame(geometry=[bpolys]))
elif isinstance(bpolys, str):
try:
return format_bpolys(gpd.GeoDataFrame.from_features(json.loads(bpolys)))
except Exception as e:
raise OhsomeException(message="Invalid geojson.") from e
else:
return bpolys
raise OhsomeException(
message="bpolys must be a geojson string, a shapely polygonal object or a geopandas "
"object"
)


def format_list_parameters(parameters: dict) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:23 GMT
- Fri, 17 Nov 2023 15:37:04 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:23 GMT
- Fri, 17 Nov 2023 15:37:04 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:26 GMT
- Fri, 17 Nov 2023 15:37:06 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:32 GMT
- Fri, 17 Nov 2023 15:37:13 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
10 changes: 5 additions & 5 deletions ohsome/test/cassettes/test_client/test_format_bboxes_list.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:32 GMT
- Fri, 17 Nov 2023 15:37:13 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down Expand Up @@ -99,7 +99,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:34 GMT
- Fri, 17 Nov 2023 15:37:14 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down Expand Up @@ -156,7 +156,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:34 GMT
- Fri, 17 Nov 2023 15:37:14 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down Expand Up @@ -213,7 +213,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:36 GMT
- Fri, 17 Nov 2023 15:37:16 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down Expand Up @@ -270,7 +270,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:36 GMT
- Fri, 17 Nov 2023 15:37:16 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:26 GMT
- Fri, 17 Nov 2023 15:37:06 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:27 GMT
- Fri, 17 Nov 2023 15:37:08 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down Expand Up @@ -102,7 +102,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:27 GMT
- Fri, 17 Nov 2023 15:37:08 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down Expand Up @@ -159,7 +159,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:29 GMT
- Fri, 17 Nov 2023 15:37:09 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down Expand Up @@ -216,7 +216,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:29 GMT
- Fri, 17 Nov 2023 15:37:09 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:31 GMT
- Fri, 17 Nov 2023 15:37:11 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
6 changes: 3 additions & 3 deletions ohsome/test/cassettes/test_client/test_format_bpolys.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
interactions:
- request:
body: bpolys=%7B%22type%22%3A+%22FeatureCollection%22%2C+%22features%22%3A+%5B%7B%22id%22%3A+%220%22%2C+%22type%22%3A+%22Feature%22%2C+%22properties%22%3A+%7B%7D%2C+%22geometry%22%3A+%7B%22type%22%3A+%22Polygon%22%2C+%22coordinates%22%3A+%5B%5B%5B8.695077896118164%2C+49.408711468953854%5D%2C+%5B8.699712753295898%2C+49.408711468953854%5D%2C+%5B8.699712753295898%2C+49.41155955732304%5D%2C+%5B8.695077896118164%2C+49.41155955732304%5D%2C+%5B8.695077896118164%2C+49.408711468953854%5D%5D%5D%7D%7D%2C+%7B%22id%22%3A+%221%22%2C+%22type%22%3A+%22Feature%22%2C+%22properties%22%3A+%7B%7D%2C+%22geometry%22%3A+%7B%22type%22%3A+%22Polygon%22%2C+%22coordinates%22%3A+%5B%5B%5B8.677010536193848%2C+49.41370947536709%5D%2C+%5B8.682074546813965%2C+49.41370947536709%5D%2C+%5B8.682074546813965%2C+49.416641030041134%5D%2C+%5B8.677010536193848%2C+49.416641030041134%5D%2C+%5B8.677010536193848%2C+49.41370947536709%5D%5D%5D%7D%7D%5D%7D&time=2018-01-01&filter=amenity%3Drestaurant+and+type%3Anode
body: bpolys=%7B%22type%22%3A+%22FeatureCollection%22%2C+%22features%22%3A+%5B%7B%22id%22%3A+%220%22%2C+%22type%22%3A+%22Feature%22%2C+%22properties%22%3A+%7B%22id%22%3A+%220%22%7D%2C+%22geometry%22%3A+%7B%22type%22%3A+%22Polygon%22%2C+%22coordinates%22%3A+%5B%5B%5B8.695077896118164%2C+49.408711468953854%5D%2C+%5B8.699712753295898%2C+49.408711468953854%5D%2C+%5B8.699712753295898%2C+49.41155955732304%5D%2C+%5B8.695077896118164%2C+49.41155955732304%5D%2C+%5B8.695077896118164%2C+49.408711468953854%5D%5D%5D%7D%7D%2C+%7B%22id%22%3A+%221%22%2C+%22type%22%3A+%22Feature%22%2C+%22properties%22%3A+%7B%22id%22%3A+%221%22%7D%2C+%22geometry%22%3A+%7B%22type%22%3A+%22Polygon%22%2C+%22coordinates%22%3A+%5B%5B%5B8.677010536193848%2C+49.41370947536709%5D%2C+%5B8.682074546813965%2C+49.41370947536709%5D%2C+%5B8.682074546813965%2C+49.416641030041134%5D%2C+%5B8.677010536193848%2C+49.416641030041134%5D%2C+%5B8.677010536193848%2C+49.41370947536709%5D%5D%5D%7D%7D%5D%7D&time=2018-01-01&filter=amenity%3Drestaurant+and+type%3Anode
headers:
Accept:
- '*/*'
Expand All @@ -9,7 +9,7 @@ interactions:
Connection:
- keep-alive
Content-Length:
- '975'
- '1013'
Content-Type:
- application/x-www-form-urlencoded
user-agent:
Expand Down Expand Up @@ -42,7 +42,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:31 GMT
- Fri, 17 Nov 2023 15:37:11 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ interactions:
Content-disposition:
- attachment;filename=ohsome.geojson
Date:
- Fri, 17 Nov 2023 11:28:37 GMT
- Fri, 17 Nov 2023 15:37:17 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down Expand Up @@ -115,7 +115,7 @@ interactions:
Content-disposition:
- attachment;filename=ohsome.geojson
Date:
- Fri, 17 Nov 2023 11:28:37 GMT
- Fri, 17 Nov 2023 15:37:17 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
2 changes: 1 addition & 1 deletion ohsome/test/cassettes/test_client/test_user_agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 17 Nov 2023 11:28:22 GMT
- Fri, 17 Nov 2023 15:37:03 GMT
Keep-Alive:
- timeout=5, max=100
Server:
Expand Down
Loading
Loading