Skip to content

Commit 239cff1

Browse files
committed
Implement feedback from Meteonorm review
1 parent 83d00cb commit 239cff1

File tree

2 files changed

+27
-29
lines changed

2 files changed

+27
-29
lines changed

pvlib/iotools/meteonorm.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
4949
In decimal degrees, east is positive (ISO 19115).
5050
start : datetime like
5151
First timestamp of the requested period. If a timezone is not
52-
specified, UTC is assumed. Relative datetime strings are supported.
52+
specified, UTC is assumed.
5353
end : datetime like
5454
Last timestamp of the requested period. If a timezone is not
55-
specified, UTC is assumed. Relative datetime strings are supported.
55+
specified, UTC is assumed.
5656
api_key : str
5757
Meteonorm API key.
5858
endpoint : str
@@ -61,7 +61,8 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
6161
* ``'observation/training'`` - historical data with a 7-day delay
6262
* ``'observation/realtime'`` - near-real time (past 7-days)
6363
* ``'forecast/basic'`` - forecast with hourly resolution
64-
* ``'forecast/precision'`` - forecast with 15-min resolution
64+
* ``'forecast/precision'`` - forecast with 1-min, 15-min, or hourly
65+
resolution
6566
6667
parameters : list or 'all', default : 'all'
6768
List of parameters to request or `'all'` to get all parameters.
@@ -71,10 +72,9 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
7172
Orientation (azimuth angle) of the (fixed) plane. Clockwise from north
7273
(north=0, east=90, south=180, west=270).
7374
time_step : {'1min', '15min', '1h'}, default : '15min'
74-
Frequency of the time series. The parameter is ignored when requesting
75-
forcasting data.
75+
Frequency of the time series.
7676
horizon : str or list, default : 'auto'
77-
Specification of the horizon line. Can be either a 'flat', 'auto', or
77+
Specification of the horizon line. Can be either 'flat', 'auto', or
7878
a list of 360 integer horizon elevation angles.
7979
interval_index : bool, default : False
8080
Index is pd.DatetimeIndex when False, and pd.IntervalIndex when True.
@@ -103,7 +103,7 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
103103
Examples
104104
--------
105105
>>> # Retrieve historical time series data
106-
>>> df, meta = get_meteonorm( # doctest: +SKIP
106+
>>> df, meta = pvlib.iotools.get_meteonorm( # doctest: +SKIP
107107
... latitude=50, longitude=10, # doctest: +SKIP
108108
... start='2023-01-01', end='2025-01-01', # doctest: +SKIP
109109
... api_key='redacted', # doctest: +SKIP
@@ -122,6 +122,7 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
122122
.. [3] `Meteonorm API reference
123123
<https://docs.meteonorm.com/api>`_
124124
"""
125+
# Relative date strings are not yet supported
125126
start = pd.Timestamp(start)
126127
end = pd.Timestamp(end)
127128
start = start.tz_localize('UTC') if start.tzinfo is None else start
@@ -136,14 +137,12 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
136137
'surface_tilt': surface_tilt,
137138
'surface_azimuth': surface_azimuth,
138139
'horizon': horizon,
140+
'response_format': 'json',
139141
}
140142

141143
# Allow specifying single parameters as string
142144
if isinstance(parameters, str):
143-
parameter_list = \
144-
list(VARIABLE_MAP.keys()) + list(VARIABLE_MAP.values())
145-
if parameters in parameter_list:
146-
parameters = [parameters]
145+
parameters = [parameters]
147146

148147
# convert list to string with values separated by commas
149148
if not isinstance(parameters, (str, type(None))):
@@ -155,7 +154,7 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
155154
if not isinstance(horizon, str):
156155
params['horizon'] = ','.join(map(str, horizon))
157156

158-
if 'forecast' not in endpoint.lower():
157+
if 'basic' not in endpoint:
159158
params['frequency'] = TIME_STEP_MAP.get(time_step, time_step)
160159

161160
headers = {"Authorization": f"Bearer {api_key}"}
@@ -165,7 +164,8 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
165164

166165
if not response.ok:
167166
# response.raise_for_status() does not give a useful error message
168-
raise requests.HTTPError(response.json())
167+
raise requests.HTTPError("Meteonorm API returned an error: "
168+
+ response.json()['error']['message'])
169169

170170
data, meta = _parse_meteonorm(response, interval_index, map_variables)
171171

@@ -177,8 +177,8 @@ def get_meteonorm(latitude, longitude, start, end, api_key, endpoint,
177177

178178
def get_meteonorm_tmy(latitude, longitude, api_key,
179179
parameters='all', *, surface_tilt=0,
180-
surface_azimuth=180, time_step='15min', horizon='auto',
181-
terrain='open', albedo=0.2, turbidity='auto',
180+
surface_azimuth=180, time_step='1h', horizon='auto',
181+
terrain='open', albedo=None, turbidity='auto',
182182
random_seed=None, clear_sky_radiation_model='esra',
183183
data_version='latest', future_scenario=None,
184184
future_year=None, interval_index=False,
@@ -214,8 +214,10 @@ def get_meteonorm_tmy(latitude, longitude, api_key,
214214
Local terrain situation. Must be one of: ['open', 'depression',
215215
'cold_air_lake', 'sea_lake', 'city', 'slope_south',
216216
'slope_west_east'].
217-
albedo : float, default : 0.2
218-
Ground albedo. Albedo changes due to snow fall are modelled.
217+
albedo : float, optional
218+
Constant ground albedo. If no value is specified a baseline albedo of
219+
0.2 is used and albedo cahnges due to snow fall is modeled. If a value
220+
is specified, then snow fall is not modeled.
219221
turbidity : list or 'auto', optional
220222
List of 12 monthly mean atmospheric Linke turbidity values. The default
221223
is 'auto'.
@@ -272,7 +274,7 @@ def get_meteonorm_tmy(latitude, longitude, api_key,
272274
'lon': longitude,
273275
'surface_tilt': surface_tilt,
274276
'surface_azimuth': surface_azimuth,
275-
'frequency': time_step,
277+
'frequency': TIME_STEP_MAP.get(time_step, time_step),
276278
'parameters': parameters,
277279
'horizon': horizon,
278280
'situation': terrain,
@@ -282,14 +284,12 @@ def get_meteonorm_tmy(latitude, longitude, api_key,
282284
'random_seed': random_seed,
283285
'future_scenario': future_scenario,
284286
'future_year': future_year,
287+
'response_format': 'json',
285288
}
286289

287290
# Allow specifying single parameters as string
288291
if isinstance(parameters, str):
289-
parameter_list = \
290-
list(VARIABLE_MAP.keys()) + list(VARIABLE_MAP.values())
291-
if parameters in parameter_list:
292-
parameters = [parameters]
292+
parameters = [parameters]
293293

294294
# convert list to string with values separated by commas
295295
if not isinstance(parameters, (str, type(None))):
@@ -304,16 +304,15 @@ def get_meteonorm_tmy(latitude, longitude, api_key,
304304
if not isinstance(turbidity, str):
305305
params['turbidity'] = ','.join(map(str, turbidity))
306306

307-
params['frequency'] = TIME_STEP_MAP.get(time_step, time_step)
308-
309307
headers = {"Authorization": f"Bearer {api_key}"}
310308

311309
response = requests.get(
312310
urljoin(url, TMY_ENDPOINT.lstrip('/')), headers=headers, params=params)
313311

314312
if not response.ok:
315313
# response.raise_for_status() does not give a useful error message
316-
raise requests.HTTPError(response.json())
314+
raise requests.HTTPError("Meteonorm API returned an error: "
315+
+ response.json()['error']['message'])
317316

318317
data, meta = _parse_meteonorm(response, interval_index, map_variables)
319318

tests/iotools/test_meteonorm.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ def test_get_meteonorm_forecast_precision(demo_api_key, demo_url):
183183
api_key=demo_api_key,
184184
parameters='ghi',
185185
endpoint='forecast/precision',
186-
# test that the time_step parameter is ignored
187-
time_step='1h',
186+
time_step='15min',
188187
url=demo_url)
189188

190189
assert data.index[1] - data.index[0] == pd.Timedelta(minutes=15)
@@ -210,7 +209,7 @@ def test_get_meteonorm_custom_horizon(demo_api_key, demo_url):
210209
@pytest.mark.flaky(reruns=RERUNS, reruns_delay=RERUNS_DELAY)
211210
def test_get_meteonorm_HTTPError(demo_api_key, demo_url):
212211
with pytest.raises(
213-
HTTPError, match="unknown parameter: not_a_real_parameter'"):
212+
HTTPError, match="unknown parameter: not_a_real_parameter"):
214213
_ = pvlib.iotools.get_meteonorm(
215214
latitude=50, longitude=10,
216215
start=pd.Timestamp.now(tz='UTC'),
@@ -230,7 +229,7 @@ def test_get_meteonorm_tmy_HTTPError(demo_api_key, demo_url):
230229
latitude=50, longitude=10,
231230
api_key=demo_api_key,
232231
parameters='dhi',
233-
# Infeasible surface_titl
232+
# Infeasible surface_tilt
234233
surface_azimuth=400,
235234
url=demo_url)
236235

0 commit comments

Comments
 (0)