Skip to content

Commit 469a6ab

Browse files
author
Hugh Cutcher
committed
feat: response to mr comments
1 parent 11185b9 commit 469a6ab

File tree

9 files changed

+69
-36
lines changed

9 files changed

+69
-36
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ public
22
.idea
33
*.ipynb_checkpoints
44
.pytest_cache
5-
tests/__pycache__
5+
tests/__pycache__
6+
*.pyc

solcast/api.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import copy
12
import json
23
import os
34
from dataclasses import dataclass
45
from urllib.request import urlopen, Request
56
import urllib.parse
67
import urllib.error
7-
from typing import Dict, Optional
8+
from typing import Optional
89

910
import solcast
1011

@@ -24,10 +25,11 @@ class Response:
2425
url: str
2526
data: Optional[bytes]
2627
success: bool
28+
method: str
2729
exception: Optional[str] = None
2830

2931
def __repr__(self):
30-
return f"status code={self.code}, url={self.url}"
32+
return f"status code={self.code}, url={self.url}, method={self.method}"
3133

3234
def to_dict(self):
3335
if self.code != 200:
@@ -78,22 +80,26 @@ def __init__(self, base_url: str, endpoint: str):
7880
self.url = self.make_url()
7981

8082
@staticmethod
81-
def check_params(params: dict) -> (dict, str):
82-
"""runs some basic checks on the parameters that will be passed in the
83-
GET request."""
83+
def _check_params(params: dict) -> (dict, str):
84+
"""Run basic checks on the parameters that will be passed to the HTTP request."""
8485
assert isinstance(params, dict), "parameters needs to be a dict"
86+
params = copy.deepcopy(params)
8587

86-
if "api_key" not in params:
87-
params.update({"api_key": os.getenv("SOLCAST_API_KEY")})
88+
if "api_key" in params:
89+
# api key in the header for secrecy
90+
key = params["api_key"]
91+
del params["api_key"]
92+
else:
93+
key = os.getenv("SOLCAST_API_KEY")
8894

89-
if params["api_key"] is None:
95+
if key is None:
9096
raise ValueError(
9197
"no API key provided. Either set it as an environment "
9298
"variable SOLCAST_API_KEY, or provide `api_key` "
9399
"as an argument. Visit https://solcast.com to get an API key."
94100
)
95101

96-
if len(params["api_key"]) <= 1:
102+
if len(key) <= 1:
97103
raise ValueError("API key is too short.")
98104

99105
if "output_parameters" in params.keys() and isinstance(
@@ -109,18 +115,15 @@ def check_params(params: dict) -> (dict, str):
109115

110116
# only json supported
111117
if "format" in params.keys():
112-
assert (
113-
params["format"] == "json"
114-
), "only json response format is currently supported."
115-
116-
# api key in the header for secrecy
117-
key = params["api_key"]
118-
del params["api_key"]
118+
if params["format"] != "json":
119+
raise NotImplementedError(
120+
"Only json response format is currently supported."
121+
)
119122

120123
return params, key
121124

122125
def make_url(self) -> str:
123-
"""composes the full URL."""
126+
"""Compose the full URL."""
124127
return "/".join([self.base_url, self.endpoint])
125128

126129
def get(self, params: dict) -> Response:
@@ -183,7 +186,7 @@ def delete(self, params: dict) -> Response:
183186
"""
184187
return self._make_request(params, method="DELETE")
185188

186-
def _make_request(self, params: Dict, method: str) -> Response:
189+
def _make_request(self, params: dict, method: str) -> Response:
187190
"""Make a request using urllib with the HTTP method specified
188191
189192
Args:
@@ -194,7 +197,7 @@ def _make_request(self, params: Dict, method: str) -> Response:
194197
a Response object.
195198
"""
196199

197-
params, key = self.check_params(params)
200+
params, key = self._check_params(params)
198201
url = self.url + "?" + urllib.parse.urlencode(params)
199202
req = Request(
200203
url,
@@ -205,7 +208,12 @@ def _make_request(self, params: Dict, method: str) -> Response:
205208
with urlopen(req) as response:
206209
body = response.read()
207210
return Response(
208-
code=response.code, url=url, data=body, success=True, exception=None
211+
code=response.code,
212+
url=url,
213+
data=body,
214+
success=True,
215+
exception=None,
216+
method=method,
209217
)
210218
except urllib.error.HTTPError as e:
211219
try:
@@ -218,4 +226,5 @@ def _make_request(self, params: Dict, method: str) -> Response:
218226
data=None,
219227
exception=exception_message,
220228
success=False,
229+
method=method,
221230
)

solcast/forecast.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def radiation_and_weather(
2222
latitude: in decimal degrees, between -90 and 90, north is positive
2323
longitude: in decimal degrees, between -180 and 180, east is positive
2424
output_parameters: list of strings with the parameters to return
25+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
2526
2627
See https://docs.solcast.com.au/ for full list of parameters.
2728
"""
@@ -51,6 +52,7 @@ def rooftop_pv_power(
5152
latitude: in decimal degrees, between -90 and 90, north is positive
5253
longitude: in decimal degrees, between -180 and 180, east is positive
5354
output_parameters: list of strings with the parameters to return
55+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
5456
5557
See https://docs.solcast.com.au/ for full list of parameters.
5658
"""
@@ -76,6 +78,7 @@ def advanced_pv_power(resource_id: int, **kwargs) -> Response:
7678
7779
Args:
7880
resource_id: a Solcast resource id
81+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
7982
8083
See https://docs.solcast.com.au/ for full list of parameters.
8184
"""

solcast/historic.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def radiation_and_weather(
2323
end: optional, datetime-like, last day of the requested period
2424
duration: optional, ISO_8601 compliant duration for the historic data.
2525
Must be within 31 days of the start_date.
26+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
2627
2728
See https://docs.solcast.com.au/ for full list of parameters.
2829
"""
@@ -65,6 +66,7 @@ def rooftop_pv_power(
6566
end: optional, datetime-like, last day of the requested period
6667
duration: optional, ISO_8601 compliant duration for the historic data.
6768
Must be within 31 days of the start_date.
69+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
6870
6971
See https://docs.solcast.com.au/ for full list of parameters.
7072
"""

solcast/live.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def radiation_and_weather(
2020
latitude: in decimal degrees, between -90 and 90, north is positive
2121
longitude: in decimal degrees, between -180 and 180, east is positive
2222
output_parameters: list of strings with the parameters to return
23+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
2324
2425
See https://docs.solcast.com.au/ for full list of parameters.
2526
"""
@@ -47,6 +48,7 @@ def rooftop_pv_power(latitude: float, longitude: float, **kwargs) -> Response:
4748
Args:
4849
latitude: in decimal degrees, between -90 and 90, north is positive
4950
longitude: in decimal degrees, between -180 and 180, east is positive
51+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
5052
5153
See https://docs.solcast.com.au/ for full list of parameters.
5254
"""
@@ -66,6 +68,7 @@ def advanced_pv_power(resource_id: int, **kwargs) -> Response:
6668
6769
Args:
6870
resource_id: a Solcast resource id
71+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
6972
7073
See https://docs.solcast.com.au/ for full list of parameters.
7174
"""

solcast/pv_power_sites.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@
22
from .urls import base_url, pv_power_site, pv_power_sites
33

44

5-
def list_pv_power_site(**kwargs) -> Response:
6-
"""List available PV power sites"""
5+
def list_pv_power_sites(**kwargs) -> Response:
6+
"""
7+
List available PV power sites.
8+
9+
Args:
10+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
11+
12+
See https://docs.solcast.com.au/ for full list of parameters.
13+
"""
714
client = Client(base_url=base_url, endpoint=pv_power_sites)
815

916
params = {"format": "json", **kwargs}
@@ -15,11 +22,13 @@ def list_pv_power_site(**kwargs) -> Response:
1522

1623
def get_pv_power_site(resource_id: str, **kwargs) -> Response:
1724
"""
18-
Get an existing PV power site's specifications
25+
Get an existing PV power site's specifications.
1926
2027
Args:
2128
resource_id: unique string to identify the location that was generated when creating a site
29+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
2230
31+
See https://docs.solcast.com.au/ for full list of parameters.
2332
"""
2433
client = Client(base_url=base_url, endpoint=pv_power_site)
2534

@@ -37,15 +46,15 @@ def create_pv_power_site(
3746
**kwargs,
3847
) -> Response:
3948
"""
40-
Create PV power site to be used with Solcast's advanced PV power model
49+
Create PV power site to be used with Solcast's advanced PV power model.
4150
4251
Args:
4352
name: arbitrary string to identify the location, unique not required
4453
latitude: in decimal degrees, between -90 and 90, north is positive
4554
longitude: in decimal degrees, between -180 and 180, east is positive
55+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
4656
4757
See https://docs.solcast.com.au/ for more information and full list of parameters.
48-
4958
"""
5059
client = Client(base_url=base_url, endpoint=pv_power_site)
5160

@@ -64,13 +73,13 @@ def create_pv_power_site(
6473

6574
def patch_pv_power_site(resource_id: str, **kwargs) -> Response:
6675
"""
67-
Patch an existing PV power site to partially update the site's specifications
76+
Patch an existing PV power site to partially update the site's specifications.
6877
6978
Args:
7079
resource_id: unique string to identify the location that is generated when creating a site
80+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
7181
7282
See https://docs.solcast.com.au/ for full list of parameters.
73-
7483
"""
7584
client = Client(base_url=base_url, endpoint=pv_power_site)
7685

@@ -87,13 +96,13 @@ def patch_pv_power_site(resource_id: str, **kwargs) -> Response:
8796

8897
def update_pv_power_site(resource_id: str, **kwargs) -> Response:
8998
"""
90-
Update an existing PV power site's specifications
99+
Overwrite an existing PV power site's specifications.
91100
92101
Args:
93102
resource_id: unique string to identify the location that is generated when creating a site
103+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
94104
95105
See https://docs.solcast.com.au/ for full list of parameters.
96-
97106
"""
98107
client = Client(base_url=base_url, endpoint=pv_power_site)
99108

@@ -110,11 +119,13 @@ def update_pv_power_site(resource_id: str, **kwargs) -> Response:
110119

111120
def delete_pv_power_site(resource_id: str, **kwargs) -> Response:
112121
"""
113-
Delete an existing PV power site
122+
Delete an existing PV power site.
114123
115124
Args:
116125
resource_id: unique string to identify the location that is generated when creating a site
126+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
117127
128+
See https://docs.solcast.com.au/ for full list of parameters.
118129
"""
119130
client = Client(base_url=base_url, endpoint=pv_power_site)
120131

solcast/tmy.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def radiation_and_weather(latitude: float, longitude: float, **kwargs) -> Respon
1111
Args:
1212
latitude: in decimal degrees, between -90 and 90, north is positive
1313
longitude: in decimal degrees, between -180 and 180, east is positive
14+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
1415
1516
See https://docs.solcast.com.au/ for full list of parameters.
1617
"""
@@ -31,6 +32,7 @@ def rooftop_pv_power(latitude: float, longitude: float, **kwargs) -> Response:
3132
Args:
3233
latitude: in decimal degrees, between -90 and 90, north is positive
3334
longitude: in decimal degrees, between -180 and 180, east is positive
35+
**kwargs: additional keyword arguments to be passed through as URL parameters to the Solcast API
3436
3537
See https://docs.solcast.com.au/ for full list of parameters.
3638
"""

tests/test_client.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ def mock_short_key(monkeypatch):
1515
def test_fail_short_key(mock_short_key):
1616
with pytest.raises(ValueError, match="API key is too short."):
1717
cls = Client(base_url=base_url, endpoint=live_radiation_and_weather)
18-
cls.check_params({"a": None})
18+
cls._check_params({"a": None})
1919

2020

2121
def test_pass_key_in_params(mock_short_key):
2222
cls = Client(base_url=base_url, endpoint=live_radiation_and_weather)
23-
assert cls.check_params({"api_key": "dummy"})[1] == "dummy"
23+
assert cls._check_params({"api_key": "dummy"})[1] == "dummy"
2424

2525

2626
def test_client():
@@ -40,7 +40,7 @@ def test_client():
4040
assert res.code == 200
4141
assert len(res.to_dict()) == 1
4242

43-
params, _ = cli.check_params(
43+
params, _ = cli._check_params(
4444
{
4545
"latitude": -33.8567848776324,
4646
"longitude": 151.215297,
@@ -55,7 +55,9 @@ def test_client():
5555

5656
def test_response():
5757
raw_data = b'{"estimated_actuals":[{"ghi":54,"period_end":"2023-06-22T05:30:00.0000000Z","period":"PT30M"}]}'
58-
rsp = Response(data=raw_data, url="some_url", code=200, success=True)
58+
rsp = Response(
59+
data=raw_data, url="some_url", code=200, success=True, method="arbitrary_method"
60+
)
5961

6062
assert rsp.success is True
6163
assert rsp.to_pandas().shape[0] == 1

tests/test_pv_power_sites.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
def test_list_pv_power_sites():
5-
res = pv_power_sites.list_pv_power_site()
5+
res = pv_power_sites.list_pv_power_sites()
66

77
assert res.success
88
assert isinstance(res.to_dict(), list)

0 commit comments

Comments
 (0)