Skip to content

make test_psm3.py robust to API overuse errors #873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 71 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
e81e941
use NREL_API_KEY environment variable when available
Jan 27, 2020
63c489d
remove try-except clause to ensure that azure env variable is used
Jan 27, 2020
3ef167e
set environment variable from Azure's secret variables
Jan 27, 2020
ecb8f79
Update azure-pipelines.yml for Azure Pipelines
CameronTStark Jan 27, 2020
0f13335
Update azure-pipelines.yml for Azure Pipelines within pytest call
CameronTStark Jan 27, 2020
31896ca
Update azure-pipelines.yml for Azure Pipelines echo only
CameronTStark Jan 27, 2020
5c69773
Update azure-pipelines.yml for Azure Pipelines with python
CameronTStark Jan 27, 2020
c348fad
Update azure-pipelines.yml for Azure Pipelines all os.environ
CameronTStark Jan 27, 2020
6a48631
Update azure-pipelines.yml for Azure Pipelines export variable
CameronTStark Jan 27, 2020
c56f8ea
export Azure secret variable into environment to access from python
Jan 27, 2020
60323df
Update azure-pipelines.yml for Azure Pipelines fix displayName
CameronTStark Jan 27, 2020
83e35d3
Update azure-pipelines.yml for Azure Pipelines psm3 test only
CameronTStark Jan 27, 2020
ae825be
Update azure-pipelines.yml for Azure Pipelines for real this time
CameronTStark Jan 27, 2020
5ce5f8f
Update azure-pipelines.yml for Azure Pipelines for really real this time
CameronTStark Jan 27, 2020
6d33c6c
Update azure-pipelines.yml for Azure Pipelines single failing test
CameronTStark Jan 27, 2020
2596c4f
Update azure-pipelines.yml for Azure Pipelines test_get_psm3_tmy
CameronTStark Jan 27, 2020
b16d036
Update azure-pipelines.yml for Azure Pipelines io_input
CameronTStark Jan 27, 2020
edb303c
Update azure-pipelines.yml for Azure Pipelines test_parse_psm3
CameronTStark Jan 27, 2020
8a8013c
Update azure-pipelines.yml for Azure Pipelines test_read_psm3
CameronTStark Jan 27, 2020
aacb1d6
Update azure-pipelines.yml for Azure Pipelines all test_psm3.py tests
CameronTStark Jan 27, 2020
1a7ac11
Update azure-pipelines.yml for Azure Pipelines all python versions
CameronTStark Jan 27, 2020
bc37f2f
use NREL_API_KEY environment variable when available
Jan 27, 2020
8736f62
remove try-except clause to ensure that azure env variable is used
Jan 27, 2020
4f11bb5
set environment variable from Azure's secret variables
Jan 27, 2020
f7620b6
Update azure-pipelines.yml for Azure Pipelines
CameronTStark Jan 27, 2020
937f050
Update azure-pipelines.yml for Azure Pipelines within pytest call
CameronTStark Jan 27, 2020
27b370c
Update azure-pipelines.yml for Azure Pipelines echo only
CameronTStark Jan 27, 2020
6068d83
Update azure-pipelines.yml for Azure Pipelines with python
CameronTStark Jan 27, 2020
672ec66
Update azure-pipelines.yml for Azure Pipelines all os.environ
CameronTStark Jan 27, 2020
572a861
Update azure-pipelines.yml for Azure Pipelines export variable
CameronTStark Jan 27, 2020
cea3eda
export Azure secret variable into environment to access from python
Jan 27, 2020
2c8370d
temporary test_blah function and get_psm3 delayer
Jan 29, 2020
1ef3af6
improve delay_get_psm3(), replace get_psm3() calls
Jan 29, 2020
e764bfa
set DEMO_KEY to environment variable if available
Jan 29, 2020
78ea6a6
update azure-pipelines basic script for testing
Jan 29, 2020
b57732a
Merge branch 'nrel_api' of github.com:CameronTStark/pvlib-python into…
Jan 29, 2020
7a1b5a1
match azure secret variable
Jan 29, 2020
5380567
return to full suite of testing on azure
Jan 29, 2020
ea8acd5
return test_psm3() specific pytest call to general
Jan 29, 2020
4f59d27
add description to whatsnew
Jan 29, 2020
51965e2
formatting fix
Jan 29, 2020
13045fb
logger module implementation
Jan 29, 2020
6358642
more formatting
Jan 29, 2020
efe0f1c
change while loop to for loop
Jan 29, 2020
65c2d75
use warnings instead of logging
Jan 29, 2020
b9981c4
fixturize DEMO_KEY
Jan 30, 2020
5d7c587
implement use of pytest-rerunfailures instead of custom loop
Jan 30, 2020
0963441
parametrize error tests into a signle test
Jan 30, 2020
ef56cce
fix windows environment import of NREL key
Jan 30, 2020
09b0af6
test to echo environment variable of NREL key
Jan 30, 2020
8db513d
fix windows secret variable setting
Jan 30, 2020
89c5af3
add pytest-rerunfailures to ci requirements yml
Feb 3, 2020
9aeabf8
use secret.nrelApiKey syntax
Feb 4, 2020
6646a2e
test new secret variable
Feb 4, 2020
075de57
try secret.api_key syntax
Feb 4, 2020
15a980d
std syntax only psm3
Feb 4, 2020
e49cba1
try to print other variables that arent secrets
Feb 4, 2020
76c9a5b
confirm personal repo still works
Feb 4, 2020
4468bcb
bump
Feb 4, 2020
9927ef5
try all python versions
Feb 4, 2020
e1b0959
try everything
Feb 4, 2020
3237f8e
install pytest-rerunrailures in Azure
Feb 4, 2020
5c68358
configure conda_35 tests to pull pytest_rerunfailures from pip instea…
Feb 5, 2020
b8d536c
add note for pytest-rerunfailures for conda_35
Feb 5, 2020
72e3880
change fixture from DEMO_KEY to nrel_api_key
Feb 5, 2020
6cdc186
remove debug variable echo commands
Feb 5, 2020
be8eca0
move pytest-rerunfailures to pip install
Feb 5, 2020
33fe42e
improve docstrings
Feb 6, 2020
6d9230e
use verbose name for caught error
Feb 6, 2020
07cbcc7
Merge branch 'master' into nrel_api
CameronTStark Feb 6, 2020
cdff1af
readd leap year test
Feb 10, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ jobs:
Python37:
python.version: '3.7'


steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'

- script: |
pip install pytest pytest-cov pytest-mock pytest-timeout pytest-azurepipelines
pip install pytest pytest-cov pytest-mock pytest-timeout pytest-azurepipelines pytest-rerunfailures
pip install -e .
export NREL_API_KEY=$(nrelApiKey)
pytest pvlib --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
displayName: 'Test with pytest'

Expand Down Expand Up @@ -74,6 +76,7 @@ jobs:
displayName: 'List installed dependencies'
- script: |
source activate test_env
export NREL_API_KEY=$(nrelApiKey)
pytest pvlib --junitxml=junit/test-results.xml --cov --cov-report=xml --cov-report=html
displayName: 'pytest'
# - script: |
Expand Down Expand Up @@ -126,6 +129,7 @@ jobs:
displayName: 'List installed dependencies'
- script: |
call activate test_env
set NREL_API_KEY=$(nrelApiKey)
pytest pvlib --junitxml=junit/test-results.xml
displayName: 'pytest'
- task: PublishTestResults@2
Expand Down Expand Up @@ -153,8 +157,9 @@ jobs:
versionSpec: '$(python.version)'

- script: |
pip install pytest pytest-cov pytest-mock pytest-timeout pytest-azurepipelines
pip install pytest pytest-cov pytest-mock pytest-timeout pytest-azurepipelines pytest-rerunfailures
pip install -e .
export NREL_API_KEY=$(nrelApiKey)
pytest pvlib --junitxml=junit/test-results.xml --cov=pvlib --cov-report=xml --cov-report=html
displayName: 'Test with pytest'

Expand Down
1 change: 1 addition & 0 deletions ci/requirements-py35-min.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ dependencies:
- pip:
- numpy==1.12.0
- pandas==0.18.1
- pytest-rerunfailures # conda version is >3.6
1 change: 1 addition & 0 deletions ci/requirements-py35.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ dependencies:
- pip:
- nrel-pysam>=2.0
- pvfactors==1.0.1
- pytest-rerunfailures # conda version is >3.6
1 change: 1 addition & 0 deletions ci/requirements-py36.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies:
- pytest
- pytest-cov
- pytest-mock
- pytest-rerunfailures
- pytest-timeout
- python=3.6
- pytz
Expand Down
1 change: 1 addition & 0 deletions ci/requirements-py37.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies:
- pytest-cov
- pytest-mock
- pytest-timeout
- pytest-rerunfailures
- python=3.7
- pytz
- requests
Expand Down
3 changes: 3 additions & 0 deletions docs/sphinx/source/whatsnew/v0.7.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Bug fixes
~~~~~~~~~
* Fix :py:func:`~pvlib.iotools.read_tmy3` parsing when February contains
a leap year (:pull:`866`)
* Implement NREL Developer Network API key for consistent success with API
calls in :py:mod:`pvlib.tests.iotools.test_psm3` (:pull:`873`)

Documentation
~~~~~~~~~~~~~
Expand All @@ -26,3 +28,4 @@ Contributors
~~~~~~~~~~~~
* Mark Mikofski (:ghuser:`mikofski`)
* Cliff Hansen (:ghuser:`cwhanse`)
* Cameron T. Stark (:ghuser:`camerontstark`)
89 changes: 56 additions & 33 deletions pvlib/tests/iotools/test_psm3.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
test iotools for PSM3
"""

import os
from pvlib.iotools import psm3
from conftest import needs_pandas_0_22, DATA_DIR
import numpy as np
import pandas as pd
import pytest
from requests import HTTPError
from io import StringIO
import warnings

TMY_TEST_DATA = DATA_DIR / 'test_psm3_tmy-2017.csv'
YEAR_TEST_DATA = DATA_DIR / 'test_psm3_2017.csv'
Expand All @@ -21,7 +23,26 @@
'Temperature Units', 'Pressure Units', 'Wind Direction Units',
'Wind Speed', 'Surface Albedo Units', 'Version']
PVLIB_EMAIL = '[email protected]'
DEMO_KEY = 'DEMO_KEY'


@pytest.fixture(scope="module")
def nrel_api_key():
"""Supplies pvlib-python's NREL Developer Network API key.

Azure Pipelines CI utilizes a secret variable set to NREL_API_KEY
to mitigate failures associated with using the default key of
"DEMO_KEY". A user is capable of using their own key this way if
desired however the default key should suffice for testing purposes.
"""
try:
demo_key = os.environ["NREL_API_KEY"]
except KeyError:
warnings.warn(
"WARNING: NREL API KEY environment variable not set! "
"Using DEMO_KEY instead. Unexpected failures may occur."
)
demo_key = 'DEMO_KEY'
return demo_key


def assert_psm3_equal(header, data, expected):
Expand Down Expand Up @@ -50,47 +71,49 @@ def assert_psm3_equal(header, data, expected):


@needs_pandas_0_22
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@needs_pandas_0_22
@needs_pandas_0_22
@pytest.mark.remote_data

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you remind me why all of these tests need pandas 0.22?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping you could tell me =)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try taking them off locally and see what errors pop out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CameronTStark see this comment in #694

Bummer, I think the pandas.to_datetime() API changed after pandas-0.16 so the python-27-min build fails. I'll try to decorate test_psm3 with @needs_pandas_0_22

So since we've dropped Python-2.7 support, we just need to check if it's still valid for Python-3.5, otherwise we can remove these.

Also since we bumped pandas to v0.18.1 in pvlib-0.7.0 we can probably definitely drop these now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the ability to assemble a datetimes from a sequence (year, month, ...) was new in pandas-0.18

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for researching this. I took off the decorators locally to run the tests and didn't have an issue with my pandas==1.0.1 environment. I tried setting up an environment with 0.18.1 and couldn't get it to install so I can't confirm for that scenario.

Like the pytest-remotedata I think this should be addressed in another issue so we can get this across the finishline.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CameronTStark please make follow up issues for these infrastructure topics.

def test_get_psm3_tmy():
@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_get_psm3_tmy(nrel_api_key):
"""test get_psm3 with a TMY"""
header, data = psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL,
names='tmy-2017')
header, data = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
PVLIB_EMAIL, names='tmy-2017')
expected = pd.read_csv(TMY_TEST_DATA)
assert_psm3_equal(header, data, expected)
# check errors
with pytest.raises(HTTPError):
# HTTP 403 forbidden because api_key is rejected
psm3.get_psm3(LATITUDE, LONGITUDE, api_key='BAD', email=PVLIB_EMAIL)
with pytest.raises(HTTPError):
# coordinates were not found in the NSRDB
psm3.get_psm3(51, -5, DEMO_KEY, PVLIB_EMAIL)
with pytest.raises(HTTPError):
# names is not one of the available options
psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL, names='bad')


@needs_pandas_0_22
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@needs_pandas_0_22
@needs_pandas_0_22
@pytest.mark.remote_data

def test_get_psm3_singleyear():
@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_get_psm3_singleyear(nrel_api_key):
"""test get_psm3 with a single year"""
header, data = psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL,
names='2017', interval=30)
header, data = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
PVLIB_EMAIL, names='2017', interval=30)
expected = pd.read_csv(YEAR_TEST_DATA)
assert_psm3_equal(header, data, expected)
# check leap day
_, data_2012 = psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL,
names='2012', interval=60, leap_day=True)
assert len(data_2012) == (8760+24)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to keep this leap day behavior check? I'm ok getting rid of it but thought it was worth double checking. It's less redundant than the other tests that I questioned earlier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kanderso-nrel ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A colleague of mine reached out the other day asking if I knew why his homemade PSM3 API wrapper didn't work anymore and it turned out that the API rejects the default urllib user-agent string now. Between that and the 30-minute timestamp shift from several months back, I'd have a preference for "over-testing" here, especially if #882 gets implemented. That said, it's not pvlib's job to act as the API's test suite so I don't mind getting rid of it if other folks feel it's unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kanderso-nrel Is there a way to increase communication with the folks that create the API?

If people are creating their own homemade API wrappers it seems like pvlib-python's could be announced in an official capacity by the NREL team as an official way of interacting with the API. This would not only draw more users to the API and pvlib-python but hopefully spur direct communication from the API team about changes and potentially prompt their developers to maintain pvlib-python's code in direct support of the API. Could be a win-win-win for pvlib-python, NREL developers and the industry.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the verdict here? add this two lines back or not? your call @CameronTStark. I think this is the only thing preventing a merge.

Copy link
Member

@kandersolar kandersolar Feb 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kanderso-nrel Is there a way to increase communication with the folks that create the API?

Sorry for not responding -- I did send a note over to the NREL API team asking about this but haven't heard back yet. I'll share anything that comes out of that conversation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wholmgren I added it back in. I didn't mean to take it out but it got lost in the shuffle. It's already been committed so please let me know if it's good to merge. Thanks!

Thanks @kanderso-nrel for sending a note over to the NREL API team.

# check errors
with pytest.raises(HTTPError):
# HTTP 403 forbidden because api_key is rejected
psm3.get_psm3(LATITUDE, LONGITUDE, api_key='BAD', email=PVLIB_EMAIL,
names='2017')
with pytest.raises(HTTPError):
# coordinates were not found in the NSRDB
psm3.get_psm3(51, -5, DEMO_KEY, PVLIB_EMAIL, names='2017')
with pytest.raises(HTTPError):
# intervals can only be 30 or 60 minutes
psm3.get_psm3(LATITUDE, LONGITUDE, DEMO_KEY, PVLIB_EMAIL, names='2017',
interval=15)


@pytest.mark.parametrize('latitude, longitude, api_key, names, interval',
[(LATITUDE, LONGITUDE, 'BAD', 'tmy-2017', 60),
(51, -5, nrel_api_key, 'tmy-2017', 60),
(LATITUDE, LONGITUDE, nrel_api_key, 'bad', 60),
(LATITUDE, LONGITUDE, nrel_api_key, '2017', 15),
])
@needs_pandas_0_22
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@needs_pandas_0_22
@needs_pandas_0_22
@pytest.mark.remote_data

@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_get_psm3_tmy_errors(
latitude, longitude, api_key, names, interval
):
"""Test get_psm3() for multiple erroneous input scenarios.

These scenarios include:
* Bad API key -> HTTP 403 forbidden because api_key is rejected
* Bad latitude/longitude -> Coordinates were not found in the NSRDB.
* Bad name -> Name is not one of the available options.
* Bad interval, single year -> Intervals can only be 30 or 60 minutes.
"""
with pytest.raises(HTTPError) as excinfo:
psm3.get_psm3(latitude, longitude, api_key, PVLIB_EMAIL,
names=names, interval=interval)
# ensure the HTTPError caught isn't due to overuse of the API key
assert "OVER_RATE_LIMIT" not in str(excinfo.value)


@pytest.fixture
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
'pytz',
'requests']
TESTS_REQUIRE = ['nose', 'pytest', 'pytest-cov', 'pytest-mock',
'pytest-timeout']
'pytest-timeout', 'pytest-rerunfailures']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'pytest-timeout', 'pytest-rerunfailures']
'pytest-timeout', 'pytest-rerunfailures', 'pytest-remotedata']

EXTRAS_REQUIRE = {
'optional': ['ephem', 'cython', 'netcdf4', 'nrel-pysam', 'numba',
'pvfactors', 'scipy', 'siphon', 'tables'],
Expand Down