Skip to content

Commit

Permalink
Fix CAMS message error handler (#1905)
Browse files Browse the repository at this point in the history
* Fix CAMS message error handler - Issue#1799

* Fix CAMS message error handler - Issue#1799

* fix Python Flake8 Linter error

* Fix associated UT and add contribution in WhatsNews

* Fix line code length in test_sodapro.py

* Fix typo in contributor ghuser

* Update geographical coverage description

* correction in maximum longitude available for CAMS Radiation

* revert of last change

* Add doc string changes from adriesse

Co-authored-by: Anton Driesse <[email protected]>

* Flake8 correction

---------

Co-authored-by: Adam R. Jensen <[email protected]>
Co-authored-by: Anton Driesse <[email protected]>
  • Loading branch information
3 people authored Dec 12, 2023
1 parent c18a004 commit f430a74
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 12 deletions.
5 changes: 4 additions & 1 deletion docs/sphinx/source/whatsnew/v0.10.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Enhancements

Bug fixes
~~~~~~~~~
* Fixed CAMS error message handler in
:py:func:`pvlib.iotools.get_cams` (:issue:`1799`, :pull:`1905`)
* Fix mapping of the dew point column to ``temp_dew`` when ``map_variables``
is True in :py:func:`pvlib.iotools.get_psm3`. (:pull:`1920`)

Expand Down Expand Up @@ -45,7 +47,8 @@ Contributors
* Miguel Sánchez de León Peque (:ghuser:`Peque`)
* Will Hobbs (:ghuser:`williamhobbs`)
* Anton Driesse (:ghuser:`adriesse`)
* Gilles Fischer (:ghuser:`GillesFischerV`)
* Adam R. Jensen (:ghusuer:`AdamRJensen`)
* :ghuser:`matsuobasho`
* Harry Jack (:ghuser:`harry-solcast`)
* Adam R. Jensen (:ghuser:`AdamRJensen`)
* Kevin Anderson (:ghuser:`kandersolar`)
21 changes: 14 additions & 7 deletions pvlib/iotools/sodapro.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
Access: free, but requires registration, see [2]_
Requests: max. 100 per day
Geographical coverage: worldwide for CAMS McClear and approximately -66° to
66° in both latitude and longitude for CAMS Radiation.
66° in latitude and -66° to 180° in longitude for CAMS Radiation. See [3]_
for a map of the geographical coverage.
Parameters
----------
Expand Down Expand Up @@ -157,6 +159,9 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
<https://atmosphere.copernicus.eu/solar-radiation>`_
.. [2] `CAMS Radiation Automatic Access (SoDa)
<https://www.soda-pro.com/help/cams-services/cams-radiation-service/automatic-access>`_
.. [3] A. R. Jensen et al., pvlib iotools — Open-source Python functions
for seamless access to solar irradiance data. Solar Energy. 2023. Vol
266, pp. 112092. :doi:`10.1016/j.solener.2023.112092`
"""
try:
time_step_str = TIME_STEPS_MAP[time_step]
Expand Down Expand Up @@ -215,14 +220,16 @@ def get_cams(latitude, longitude, start, end, email, identifier='mcclear',
res = requests.get(base_url + '?DataInputs=' + data_inputs, params=params,
timeout=timeout)

# Invalid requests returns an XML error message and the HTTP staus code 200
# as if the request was successful. Therefore, errors cannot be handled
# automatic (e.g. res.raise_for_status()) and errors are handled manually
if res.headers['Content-Type'] == 'application/xml':
# Response from CAMS follows the status and reason format of PyWPS4
# If an error occurs on server side, it will return error 400 - bad request
# Additional information is available in the response text, so it is added
# to the error displayed to facilitate users effort to fix their request
if not res.ok:
errors = res.text.split('ows:ExceptionText')[1][1:-2]
raise requests.HTTPError(errors, response=res)
res.reason = "%s: <%s>" % (res.reason, errors)
res.raise_for_status()
# Successful requests returns a csv data file
elif res.headers['Content-Type'] == 'application/csv':
else:
fbuf = io.StringIO(res.content.decode('utf-8'))
data, metadata = parse_cams(fbuf, integrated=integrated, label=label,
map_variables=map_variables)
Expand Down
9 changes: 5 additions & 4 deletions pvlib/tests/iotools/test_sodapro.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,20 +248,21 @@ def test_get_cams_bad_request(requests_mock):
requests inputs. Also tests if the specified server url gets used"""

# Subset of an xml file returned for errornous requests
mock_response_bad = """<?xml version="1.0" encoding="utf-8"?>
mock_response_bad_text = """<?xml version="1.0" encoding="utf-8"?>
<ows:Exception exceptionCode="NoApplicableCode" locator="None">
<ows:ExceptionText>Failed to execute WPS process [get_mcclear]:
Please, register yourself at www.soda-pro.com
</ows:ExceptionText>"""

url_cams_bad_request = 'https://pro.soda-is.com/service/wps?DataInputs=latitude=55.7906;longitude=12.5251;altitude=-999;date_begin=2020-01-01;date_end=2020-05-04;time_ref=TST;summarization=PT01H;username=test%2540test.com;verbose=false&Service=WPS&Request=Execute&Identifier=get_mcclear&version=1.0.0&RawDataOutput=irradiation' # noqa: E501

requests_mock.get(url_cams_bad_request, text=mock_response_bad,
headers={'Content-Type': 'application/xml'})
requests_mock.get(url_cams_bad_request, status_code=400,
text=mock_response_bad_text)

# Test if HTTPError is raised if incorrect input is specified
# In the below example a non-registrered email is specified
with pytest.raises(requests.HTTPError, match='Failed to execute WPS'):
with pytest.raises(requests.exceptions.HTTPError,
match='Failed to execute WPS process'):
_ = sodapro.get_cams(
start=pd.Timestamp('2020-01-01'),
end=pd.Timestamp('2020-05-04'),
Expand Down

0 comments on commit f430a74

Please sign in to comment.