Skip to content

Commit d9a71b7

Browse files
Merge pull request #66 from SheffieldSolar/63-add-response-check
Add some validation of the API response
2 parents ded8e94 + 70fce26 commit d9a71b7

3 files changed

Lines changed: 20 additions & 3 deletions

File tree

Tests/test_pvlive_api.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
"""
66

77
import unittest
8+
from unittest.mock import MagicMock
89
from datetime import datetime, date, time
910
import pytz
1011

1112
import pandas.api.types as ptypes
12-
from pvlive_api import PVLive
13+
from pvlive_api import PVLive, PVLiveException
1314

1415
class PVLiveTestCase(unittest.TestCase):
1516
"""Tests for `pvlive.py`."""
@@ -139,6 +140,9 @@ def test_latest(self):
139140
data = self.api.latest(entity_type="gsp", entity_id=103, dataframe=True)
140141
self.check_df_columns(data)
141142
self.check_df_dtypes(data)
143+
self.api._fetch_url = MagicMock(return_value={"notdata": [], "notmeta": []})
144+
with self.assertRaises(PVLiveException):
145+
data = self.api.latest(entity_type="gsp", entity_id=0, dataframe=True)
142146

143147
def test_day_peak(self):
144148
"""Tests the day_peak function."""

pvlive_api/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
from pvlive_api.pvlive import PVLive
1+
from pvlive_api.pvlive import PVLive, PVLiveException
22

3-
__all__ = ["PVLive"]
3+
__all__ = ["PVLive", "PVLiveException"]

pvlive_api/pvlive.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,14 @@ def _get_gsp_list(self):
9696
"""Fetch the GSP list from the API and convert to Pandas DataFrame."""
9797
url = f"{self.base_url}/gsp_list"
9898
response = self._fetch_url(url)
99+
self._validate_api_response(response, expected_keys=("data", "meta"))
99100
return pd.DataFrame(response["data"], columns=response["meta"])
100101

101102
def _get_pes_list(self):
102103
"""Fetch the PES list from the API and convert to Pandas DataFrame."""
103104
url = f"{self.base_url}/pes_list"
104105
response = self._fetch_url(url)
106+
self._validate_api_response(response, expected_keys=("data", "meta"))
105107
return pd.DataFrame(response["data"], columns=response["meta"])
106108

107109
def _get_deployment_releases(self):
@@ -230,6 +232,7 @@ def latest(self,
230232
extra_fields=extra_fields, period=period)
231233
params = self._compile_params(extra_fields, period=period)
232234
response = self._query_api(entity_type, entity_id, params)
235+
self._validate_api_response(response, expected_keys=("data", "meta"))
233236
if response["data"]:
234237
data, meta = response["data"], response["meta"]
235238
data = tuple(data[0])
@@ -446,12 +449,22 @@ def _between(self, start, end, entity_type="gsp", entity_id=0, extra_fields="",
446449
request_end = min(end, request_start + max_range)
447450
params = self._compile_params(extra_fields, request_start, request_end, period)
448451
response = self._query_api(entity_type, entity_id, params)
452+
self._validate_api_response(response, expected_keys=("data", "meta"))
449453
data += response["data"]
450454
request_start += max_range + timedelta(minutes=period)
451455
if dataframe:
452456
return self._convert_tuple_to_df(data, response["meta"]), response["meta"]
453457
return data, response["meta"]
454458

459+
@staticmethod
460+
def _validate_api_response(response, expected_keys):
461+
"""Check that a JSON API response contains the expected keys."""
462+
if any(key not in response.keys() for key in expected_keys):
463+
raise PVLiveException(
464+
"The API's JSON response did not contain the required fields. Expected keys: "
465+
f"{expected_keys} , available keys: {response.keys()}"
466+
)
467+
455468
def _compile_params(self, extra_fields="", start=None, end=None, period=30):
456469
"""Compile parameters into a Python dict, formatting where necessary."""
457470
params = {}

0 commit comments

Comments
 (0)