Skip to content

Commit 7100c6b

Browse files
make test_psm3.py robust to API overuse errors (#873)
* use NREL_API_KEY environment variable when available * remove try-except clause to ensure that azure env variable is used * set environment variable from Azure's secret variables * Update azure-pipelines.yml for Azure Pipelines * Update azure-pipelines.yml for Azure Pipelines within pytest call * Update azure-pipelines.yml for Azure Pipelines echo only * Update azure-pipelines.yml for Azure Pipelines with python * Update azure-pipelines.yml for Azure Pipelines all os.environ * Update azure-pipelines.yml for Azure Pipelines export variable * export Azure secret variable into environment to access from python * Update azure-pipelines.yml for Azure Pipelines fix displayName * Update azure-pipelines.yml for Azure Pipelines psm3 test only * Update azure-pipelines.yml for Azure Pipelines for real this time * Update azure-pipelines.yml for Azure Pipelines for really real this time * Update azure-pipelines.yml for Azure Pipelines single failing test * Update azure-pipelines.yml for Azure Pipelines test_get_psm3_tmy * Update azure-pipelines.yml for Azure Pipelines io_input * Update azure-pipelines.yml for Azure Pipelines test_parse_psm3 * Update azure-pipelines.yml for Azure Pipelines test_read_psm3 * Update azure-pipelines.yml for Azure Pipelines all test_psm3.py tests * Update azure-pipelines.yml for Azure Pipelines all python versions * use NREL_API_KEY environment variable when available * remove try-except clause to ensure that azure env variable is used * set environment variable from Azure's secret variables * Update azure-pipelines.yml for Azure Pipelines * Update azure-pipelines.yml for Azure Pipelines within pytest call * Update azure-pipelines.yml for Azure Pipelines echo only * Update azure-pipelines.yml for Azure Pipelines with python * Update azure-pipelines.yml for Azure Pipelines all os.environ * Update azure-pipelines.yml for Azure Pipelines export variable * export Azure secret variable into environment to access from python * temporary test_blah function and get_psm3 delayer * improve delay_get_psm3(), replace get_psm3() calls * set DEMO_KEY to environment variable if available * update azure-pipelines basic script for testing * match azure secret variable * return to full suite of testing on azure * return test_psm3() specific pytest call to general * add description to whatsnew * formatting fix * logger module implementation * more formatting * change while loop to for loop * use warnings instead of logging * fixturize DEMO_KEY * implement use of pytest-rerunfailures instead of custom loop * parametrize error tests into a signle test * fix windows environment import of NREL key * test to echo environment variable of NREL key * fix windows secret variable setting * add pytest-rerunfailures to ci requirements yml * use secret.nrelApiKey syntax * test new secret variable * try secret.api_key syntax * std syntax only psm3 * try to print other variables that arent secrets * confirm personal repo still works * bump * try all python versions * try everything * install pytest-rerunrailures in Azure * configure conda_35 tests to pull pytest_rerunfailures from pip instead of conda * add note for pytest-rerunfailures for conda_35 * change fixture from DEMO_KEY to nrel_api_key * remove debug variable echo commands * move pytest-rerunfailures to pip install * improve docstrings * use verbose name for caught error * readd leap year test
1 parent 160c32b commit 7100c6b

File tree

8 files changed

+80
-36
lines changed

8 files changed

+80
-36
lines changed

azure-pipelines.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@ jobs:
1919
Python37:
2020
python.version: '3.7'
2121

22+
2223
steps:
2324
- task: UsePythonVersion@0
2425
inputs:
2526
versionSpec: '$(python.version)'
2627

2728
- script: |
28-
pip install pytest pytest-cov pytest-mock pytest-timeout pytest-azurepipelines
29+
pip install pytest pytest-cov pytest-mock pytest-timeout pytest-azurepipelines pytest-rerunfailures
2930
pip install -e .
31+
export NREL_API_KEY=$(nrelApiKey)
3032
pytest pvlib --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
3133
displayName: 'Test with pytest'
3234
@@ -74,6 +76,7 @@ jobs:
7476
displayName: 'List installed dependencies'
7577
- script: |
7678
source activate test_env
79+
export NREL_API_KEY=$(nrelApiKey)
7780
pytest pvlib --junitxml=junit/test-results.xml --cov --cov-report=xml --cov-report=html
7881
displayName: 'pytest'
7982
# - script: |
@@ -126,6 +129,7 @@ jobs:
126129
displayName: 'List installed dependencies'
127130
- script: |
128131
call activate test_env
132+
set NREL_API_KEY=$(nrelApiKey)
129133
pytest pvlib --junitxml=junit/test-results.xml
130134
displayName: 'pytest'
131135
- task: PublishTestResults@2
@@ -153,8 +157,9 @@ jobs:
153157
versionSpec: '$(python.version)'
154158

155159
- script: |
156-
pip install pytest pytest-cov pytest-mock pytest-timeout pytest-azurepipelines
160+
pip install pytest pytest-cov pytest-mock pytest-timeout pytest-azurepipelines pytest-rerunfailures
157161
pip install -e .
162+
export NREL_API_KEY=$(nrelApiKey)
158163
pytest pvlib --junitxml=junit/test-results.xml --cov=pvlib --cov-report=xml --cov-report=html
159164
displayName: 'Test with pytest'
160165

ci/requirements-py35-min.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ dependencies:
1515
- pip:
1616
- numpy==1.12.0
1717
- pandas==0.18.1
18+
- pytest-rerunfailures # conda version is >3.6

ci/requirements-py35.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ dependencies:
2626
- pip:
2727
- nrel-pysam>=2.0
2828
- pvfactors==1.0.1
29+
- pytest-rerunfailures # conda version is >3.6

ci/requirements-py36.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies:
1616
- pytest
1717
- pytest-cov
1818
- pytest-mock
19+
- pytest-rerunfailures
1920
- pytest-timeout
2021
- python=3.6
2122
- pytz

ci/requirements-py37.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies:
1717
- pytest-cov
1818
- pytest-mock
1919
- pytest-timeout
20+
- pytest-rerunfailures
2021
- python=3.7
2122
- pytz
2223
- requests

docs/sphinx/source/whatsnew/v0.7.2.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Bug fixes
1313
~~~~~~~~~
1414
* Fix :py:func:`~pvlib.iotools.read_tmy3` parsing when February contains
1515
a leap year (:pull:`866`)
16+
* Implement NREL Developer Network API key for consistent success with API
17+
calls in :py:mod:`pvlib.tests.iotools.test_psm3` (:pull:`873`)
1618

1719
Documentation
1820
~~~~~~~~~~~~~
@@ -26,3 +28,4 @@ Contributors
2628
~~~~~~~~~~~~
2729
* Mark Mikofski (:ghuser:`mikofski`)
2830
* Cliff Hansen (:ghuser:`cwhanse`)
31+
* Cameron T. Stark (:ghuser:`camerontstark`)

pvlib/tests/iotools/test_psm3.py

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
test iotools for PSM3
33
"""
44

5+
import os
56
from pvlib.iotools import psm3
67
from conftest import needs_pandas_0_22, DATA_DIR
78
import numpy as np
89
import pandas as pd
910
import pytest
1011
from requests import HTTPError
1112
from io import StringIO
13+
import warnings
1214

1315
TMY_TEST_DATA = DATA_DIR / 'test_psm3_tmy-2017.csv'
1416
YEAR_TEST_DATA = DATA_DIR / 'test_psm3_2017.csv'
@@ -21,7 +23,26 @@
2123
'Temperature Units', 'Pressure Units', 'Wind Direction Units',
2224
'Wind Speed', 'Surface Albedo Units', 'Version']
2325
PVLIB_EMAIL = '[email protected]'
24-
DEMO_KEY = 'DEMO_KEY'
26+
27+
28+
@pytest.fixture(scope="module")
29+
def nrel_api_key():
30+
"""Supplies pvlib-python's NREL Developer Network API key.
31+
32+
Azure Pipelines CI utilizes a secret variable set to NREL_API_KEY
33+
to mitigate failures associated with using the default key of
34+
"DEMO_KEY". A user is capable of using their own key this way if
35+
desired however the default key should suffice for testing purposes.
36+
"""
37+
try:
38+
demo_key = os.environ["NREL_API_KEY"]
39+
except KeyError:
40+
warnings.warn(
41+
"WARNING: NREL API KEY environment variable not set! "
42+
"Using DEMO_KEY instead. Unexpected failures may occur."
43+
)
44+
demo_key = 'DEMO_KEY'
45+
return demo_key
2546

2647

2748
def assert_psm3_equal(header, data, expected):
@@ -50,47 +71,58 @@ def assert_psm3_equal(header, data, expected):
5071

5172

5273
@needs_pandas_0_22
53-
def test_get_psm3_tmy():
74+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
75+
def test_get_psm3_tmy(nrel_api_key):
5476
"""test get_psm3 with a TMY"""
55-
header, data = psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL,
56-
names='tmy-2017')
77+
header, data = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
78+
PVLIB_EMAIL, names='tmy-2017')
5779
expected = pd.read_csv(TMY_TEST_DATA)
5880
assert_psm3_equal(header, data, expected)
59-
# check errors
60-
with pytest.raises(HTTPError):
61-
# HTTP 403 forbidden because api_key is rejected
62-
psm3.get_psm3(LATITUDE, LONGITUDE, api_key='BAD', email=PVLIB_EMAIL)
63-
with pytest.raises(HTTPError):
64-
# coordinates were not found in the NSRDB
65-
psm3.get_psm3(51, -5, DEMO_KEY, PVLIB_EMAIL)
66-
with pytest.raises(HTTPError):
67-
# names is not one of the available options
68-
psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL, names='bad')
6981

7082

7183
@needs_pandas_0_22
72-
def test_get_psm3_singleyear():
84+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
85+
def test_get_psm3_singleyear(nrel_api_key):
7386
"""test get_psm3 with a single year"""
74-
header, data = psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL,
75-
names='2017', interval=30)
87+
header, data = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
88+
PVLIB_EMAIL, names='2017', interval=30)
7689
expected = pd.read_csv(YEAR_TEST_DATA)
7790
assert_psm3_equal(header, data, expected)
78-
# check leap day
79-
_, data_2012 = psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL,
80-
names='2012', interval=60, leap_day=True)
81-
assert len(data_2012) == (8760+24)
82-
# check errors
83-
with pytest.raises(HTTPError):
84-
# HTTP 403 forbidden because api_key is rejected
85-
psm3.get_psm3(LATITUDE, LONGITUDE, api_key='BAD', email=PVLIB_EMAIL,
86-
names='2017')
87-
with pytest.raises(HTTPError):
88-
# coordinates were not found in the NSRDB
89-
psm3.get_psm3(51, -5, DEMO_KEY, PVLIB_EMAIL, names='2017')
90-
with pytest.raises(HTTPError):
91-
# intervals can only be 30 or 60 minutes
92-
psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL, names='2017',
93-
interval=15)
91+
92+
93+
@needs_pandas_0_22
94+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
95+
def test_get_psm3_check_leap_day(nrel_api_key):
96+
_, data_2012 = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
97+
PVLIB_EMAIL, names="2012", interval=60,
98+
leap_day=True)
99+
assert len(data_2012) == (8760 + 24)
100+
101+
102+
@pytest.mark.parametrize('latitude, longitude, api_key, names, interval',
103+
[(LATITUDE, LONGITUDE, 'BAD', 'tmy-2017', 60),
104+
(51, -5, nrel_api_key, 'tmy-2017', 60),
105+
(LATITUDE, LONGITUDE, nrel_api_key, 'bad', 60),
106+
(LATITUDE, LONGITUDE, nrel_api_key, '2017', 15),
107+
])
108+
@needs_pandas_0_22
109+
@pytest.mark.flaky(reruns=5, reruns_delay=2)
110+
def test_get_psm3_tmy_errors(
111+
latitude, longitude, api_key, names, interval
112+
):
113+
"""Test get_psm3() for multiple erroneous input scenarios.
114+
115+
These scenarios include:
116+
* Bad API key -> HTTP 403 forbidden because api_key is rejected
117+
* Bad latitude/longitude -> Coordinates were not found in the NSRDB.
118+
* Bad name -> Name is not one of the available options.
119+
* Bad interval, single year -> Intervals can only be 30 or 60 minutes.
120+
"""
121+
with pytest.raises(HTTPError) as excinfo:
122+
psm3.get_psm3(latitude, longitude, api_key, PVLIB_EMAIL,
123+
names=names, interval=interval)
124+
# ensure the HTTPError caught isn't due to overuse of the API key
125+
assert "OVER_RATE_LIMIT" not in str(excinfo.value)
94126

95127

96128
@pytest.fixture

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
'pytz',
4343
'requests']
4444
TESTS_REQUIRE = ['nose', 'pytest', 'pytest-cov', 'pytest-mock',
45-
'pytest-timeout']
45+
'pytest-timeout', 'pytest-rerunfailures']
4646
EXTRAS_REQUIRE = {
4747
'optional': ['ephem', 'cython', 'netcdf4', 'nrel-pysam', 'numba',
4848
'pvfactors', 'scipy', 'siphon', 'tables'],

0 commit comments

Comments
 (0)