Skip to content

Commit ddbd0b8

Browse files
authored
Merge pull request #94 from GIScience/development
Development
2 parents 317059d + 1d7904c commit ddbd0b8

11 files changed

Lines changed: 144 additions & 78 deletions

File tree

.github/workflows/ci-development.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name: Continous Integration for development
33
on:
44
pull_request:
55
branches: [ "**" ]
6+
workflow_dispatch:
67

78
jobs:
89
lint:
@@ -41,7 +42,7 @@ jobs:
4142
runs-on: ${{ matrix.os }}
4243
services:
4344
ohsome-api:
44-
image: julianpsotta/ohsome-api:1.3.2
45+
image: julianpsotta/ohsome-api:1.4.1
4546
ports:
4647
- 8080:8080
4748
steps:

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/ambv/black
3-
rev: stable
3+
rev: 22.3.0
44
hooks:
55
- id: black
66
language_version: python3

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ $ pip install ohsome --no-deps
3535

3636
### Dependencies for Jupyter Notebooks
3737

38-
If you want to run the Juypter Notebook [Tutorial](https://github.com/GIScience/ohsome-py/blob/master/notebooks/Tutorial.ipynb) you also need to install `jupyter` and `matplotlib` e.g.
38+
If you want to run the Jupyter Notebook [Tutorial](https://github.com/GIScience/ohsome-py/blob/master/notebooks/Tutorial.ipynb) you also need to install `jupyter` and `matplotlib` e.g.
3939

4040
```
4141
$ pip install jupyter matplotlib

ohsome/clients.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33

44
"""OhsomeClient classes to build and handle requests to ohsome API"""
5+
import json
56
import urllib
67

78
import requests
@@ -38,6 +39,7 @@ def __init__(
3839
:param log: Log failed queries, default:True
3940
:param log_dir: Directory for log files, default: ./ohsome_log
4041
:param cache: Cache for endpoint components
42+
:param user_agent: User agent passed with the request to the ohsome API
4143
"""
4244
self.log = log
4345
self.log_dir = log_dir
@@ -95,6 +97,7 @@ def __init__(
9597
:param log: Log failed queries, default:True
9698
:param log_dir: Directory for log files, default: ./ohsome_log
9799
:param cache: Cache for endpoint components
100+
:param user_agent: User agent passed with the request to the ohsome API
98101
"""
99102
super(_OhsomeInfoClient, self).__init__(
100103
base_api_url, log, log_dir, cache, user_agent
@@ -190,6 +193,7 @@ def __init__(
190193
:param log: Log failed queries, default:True
191194
:param log_dir: Directory for log files, default: ./ohsome_log
192195
:param cache: Cache for endpoint components
196+
:param user_agent: User agent passed with the request to the ohsome API
193197
"""
194198
super(_OhsomePostClient, self).__init__(
195199
base_api_url, log, log_dir, cache, user_agent
@@ -286,13 +290,18 @@ def _handle_request(self):
286290
response.raise_for_status()
287291
response.json()
288292
except requests.exceptions.HTTPError as e:
289-
ohsome_exception = OhsomeException(
290-
message=e.response.json()["message"],
291-
url=self._url,
292-
params=self._parameters,
293-
error_code=e.response.status_code,
294-
response=e.response,
295-
)
293+
try:
294+
error_message = e.response.json()["message"]
295+
except json.decoder.JSONDecodeError:
296+
error_message = f"Invalid URL: Is {self._url} valid?"
297+
finally:
298+
ohsome_exception = OhsomeException(
299+
message=error_message,
300+
url=self._url,
301+
params=self._parameters,
302+
error_code=e.response.status_code,
303+
response=e.response,
304+
)
296305
except requests.exceptions.ConnectionError as e:
297306
ohsome_exception = OhsomeException(
298307
message="Connection Error: Query could not be sent. Make sure there are no network "

ohsome/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
DEFAULT_LOG = True
77
DEFAULT_LOG_DIR = "./ohsome_log"
88
# update version in pyproject.toml as well
9-
OHSOME_VERSION = "0.1.0rc2"
9+
OHSOME_VERSION = "0.1.0"

ohsome/response.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ def as_dataframe(self, multi_index=True):
2323
"""
2424
Converts the ohsome response to a pandas.DataFrame or a geopandas.GeoDataFrame if the
2525
response contains geometries
26-
:param multi_index:
27-
:return:
26+
:param multi_index: If true returns the dataframe with a multi index
27+
:return: pandas.DataFrame or geopandas.GeoDataFrame
2828
"""
2929
if "features" not in self.data.keys():
3030
return self._as_dataframe(multi_index)
@@ -34,8 +34,10 @@ def as_dataframe(self, multi_index=True):
3434
def _as_dataframe(self, multi_index=True):
3535
"""
3636
Converts the ohsome response to a pandas.DataFrame
37-
:return: pandas dataframe
37+
:param multi_index: If true returns the dataframe with a multi index
38+
:return: pandas.DataFrame
3839
"""
40+
3941
groupby_names = []
4042
if "result" in self.data.keys():
4143
result_df = pd.DataFrame().from_records(self.data["result"])
@@ -65,13 +67,18 @@ def _as_dataframe(self, multi_index=True):
6567
def _as_geodataframe(self, multi_index=True):
6668
"""
6769
Converts the ohsome response to a geopandas.GeoDataFrame
68-
:return:
70+
:param multi_index: If true returns the dataframe with a multi index
71+
:return: geopandas.GeoDataFrame
6972
"""
73+
74+
if len(self.data["features"]) == 0:
75+
return gpd.GeoDataFrame(crs="epsg:4326", columns=["@osmId", "geometry"])
76+
7077
try:
7178
features = gpd.GeoDataFrame().from_features(self.data, crs="epsg:4326")
7279
except TypeError():
7380
raise TypeError(
74-
"This result type cannot be converted to a GeoPandas dataframe."
81+
"This result type cannot be converted to a GeoPandas GeoDataFrame object."
7582
)
7683

7784
if "@validFrom" in features.columns:
@@ -114,8 +121,8 @@ def to_json(self, outfile):
114121
:return:
115122
"""
116123
assert outfile.endswith("json"), "Output file must be json"
117-
with open(outfile, "w") as dst:
118-
json.dump(self.data, dst, indent=2)
124+
with open(outfile, "w", encoding="utf-8") as dst:
125+
json.dump(self.data, dst, indent=2, ensure_ascii=False)
119126

120127
def _set_index(self, result_df, groupby_names):
121128
"""

ohsome/test/data/points.geojson

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
"features": [
44
{
55
"type": "Feature",
6-
"properties": {"id": 1, "radius": 100},
6+
"properties": {
7+
"id": 1,
8+
"radius": 100
9+
},
710
"geometry": {
811
"type": "Point",
912
"coordinates": [
@@ -14,7 +17,10 @@
1417
},
1518
{
1619
"type": "Feature",
17-
"properties": {"id": 2, "radius": 150},
20+
"properties": {
21+
"id": 2,
22+
"radius": 150
23+
},
1824
"geometry": {
1925
"type": "Point",
2026
"coordinates": [

ohsome/test/test_exceptions.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,23 @@ def test_invalid_url():
5555
)
5656

5757

58+
def test_invalid_url2():
59+
"""
60+
Test whether an OhsomeException is raises if the ohsome API url is invalid, i.e.
61+
https://api.ohsome.org/ instead of https://api.ohsome.org/v1
62+
:return:
63+
"""
64+
base_api_url = "https://api.ohsome.org/"
65+
bboxes = "8.7137,49.4096,8.717,49.4119"
66+
time = "2018-01-01"
67+
fltr = "name=Krautturm and type:way"
68+
69+
client = ohsome.OhsomeClient(base_api_url=base_api_url, log=False)
70+
with pytest.raises(ohsome.OhsomeException) as e_info:
71+
client.elements.count.post(bboxes=bboxes, time=time, filter=fltr)
72+
assert "Invalid URL:" in e_info.value.message
73+
74+
5875
def test_invalid_endpoint():
5976
"""
6077
Test whether request can be sent to alternative url

ohsome/test/test_response.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import geopandas as gpd
66
import pandas as pd
7+
import pytest
78

89

910
def test_elements_count(custom_client):
@@ -323,3 +324,22 @@ def test_contributions_latest(custom_client):
323324

324325
assert isinstance(result, gpd.GeoDataFrame)
325326
assert len(result) == 1
327+
328+
329+
def test_empty_geodataframe(custom_client):
330+
"""
331+
Tests whether an empty GeoDataFrame is created without a warning if no features are returned from ohsome
332+
:return:
333+
"""
334+
bboxes = "8.7137,49.4096,8.717,49.4119"
335+
time = "2015-01-01,2016-01-01"
336+
filter = "name=Krautturm1 and type:way"
337+
338+
client = custom_client
339+
response = client.elements.bbox.post(bboxes=bboxes, time=time, filter=filter)
340+
with pytest.warns(None) as record:
341+
result = response.as_dataframe()
342+
343+
assert isinstance(result, gpd.GeoDataFrame)
344+
assert result.empty
345+
assert len(record) == 0

0 commit comments

Comments
 (0)