Skip to content

remove needs_pandas decorator #885

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 9 commits into from
Feb 13, 2020
10 changes: 10 additions & 0 deletions docs/sphinx/source/whatsnew/v0.7.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
v0.7.2 (Month day, year)
-------------------------

API Changes
~~~~~~~~~~~
* :py:class:`pvlib.forecast.ForecastModel` now requires ``start`` and ``end``
arguments to be tz-localized. (:issue:`877`, :pull:`879`)

Enhancements
~~~~~~~~~~~~
* TMY3 dataframe returned by :py:func:`~pvlib.iotools.read_tmy3` now contains
Expand All @@ -15,6 +20,8 @@ Bug fixes
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`)
* Fix issue with :py:class:`pvlib.location.Location` creation when
passing ``tz=datetime.timezone.utc`` (:pull:`879`)

Documentation
~~~~~~~~~~~~~
Expand All @@ -29,3 +36,6 @@ Contributors
* Mark Mikofski (:ghuser:`mikofski`)
* Cliff Hansen (:ghuser:`cwhanse`)
* Cameron T. Stark (:ghuser:`camerontstark`)
* Will Holmgren (:ghuser:`wholmgren`)
* Kevin Anderson (:ghuser:`kanderso-nrel`)
* Karthikeyan Singaravelan (:ghuser:`tirkarthi`)
51 changes: 34 additions & 17 deletions pvlib/forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,25 @@ def set_dataset(self):
self.ncss = NCSS(self.access_url)
self.query = self.ncss.query()

def set_query_time_range(self, start, end):
"""
Parameters
----------
start : datetime.datetime, pandas.Timestamp
Must be tz-localized.
end : datetime.datetime, pandas.Timestamp
Must be tz-localized.

Notes
-----
Assigns ``self.start``, ``self.end``. Modifies ``self.query``
"""
self.start = pd.Timestamp(start)
self.end = pd.Timestamp(end)
if self.start.tz is None or self.end.tz is None:
raise TypeError('start and end must be tz-localized')
self.query.time_range(self.start, self.end)

def set_query_latlon(self):
'''
Sets the NCSS query location latitude and longitude.
Expand All @@ -180,24 +199,24 @@ def set_query_latlon(self):
self.lbox = False
self.query.lonlat_point(self.longitude, self.latitude)

def set_location(self, time, latitude, longitude):
def set_location(self, tz, latitude, longitude):
'''
Sets the location for the query.

Parameters
----------
time: datetime or DatetimeIndex
Time range of the query.
'''
if isinstance(time, datetime.datetime):
tzinfo = time.tzinfo
else:
tzinfo = time.tz
tz: tzinfo
Timezone of the query
latitude: float
Latitude of the query
longitude: float
Longitude of the query

if tzinfo is None:
self.location = Location(latitude, longitude)
else:
self.location = Location(latitude, longitude, tz=tzinfo)
Notes
-----
Assigns ``self.location``.
'''
self.location = Location(latitude, longitude, tz=tz)

def get_data(self, latitude, longitude, start, end,
vert_level=None, query_variables=None,
Expand Down Expand Up @@ -243,14 +262,12 @@ def get_data(self, latitude, longitude, start, end,
else:
self.query_variables = query_variables

self.set_query_time_range(start, end)

self.latitude = latitude
self.longitude = longitude
self.set_query_latlon() # modifies self.query
self.set_location(start, latitude, longitude)

self.start = start
self.end = end
self.query.time_range(self.start, self.end)
self.set_location(self.start.tz, latitude, longitude)

if self.vert_level is not None:
self.query.vertical_level(self.vert_level)
Expand Down
2 changes: 1 addition & 1 deletion pvlib/iotools/ecmwf_macc.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def get_ecmwf_macc(filename, params, startdate, stopdate, lookup_params=True,
key. Please read the documentation in `Access ECMWF Public Datasets
<https://confluence.ecmwf.int/display/WEBAPI/Access+ECMWF+Public+Datasets>`_.
Follow the instructions in step 4 and save the ECMWF registration key
as `$HOME\.ecmwfapirc` or set `ECMWF_API_KEY` as the path to the key.
as `$HOME/.ecmwfapirc` or set `ECMWF_API_KEY` as the path to the key.

This function returns a daemon thread that runs in the background. Exiting
Python will kill this thread, however this thread will not block the main
Expand Down
3 changes: 3 additions & 0 deletions pvlib/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ def __init__(self, latitude, longitude, tz='UTC', altitude=0,
if isinstance(tz, str):
self.tz = tz
self.pytz = pytz.timezone(tz)
elif isinstance(tz, datetime.timezone):
self.tz = 'UTC'
self.pytz = pytz.UTC
elif isinstance(tz, datetime.tzinfo):
self.tz = tz.zone
self.pytz = tz
Expand Down
8 changes: 0 additions & 8 deletions pvlib/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,6 @@ def inner():
requires_ephem = pytest.mark.skipif(not has_ephem, reason='requires ephem')


def pandas_0_17():
return parse_version(pd.__version__) >= parse_version('0.17.0')


needs_pandas_0_17 = pytest.mark.skipif(
not pandas_0_17(), reason='requires pandas 0.17 or greater')


def numpy_1_10():
return parse_version(np.__version__) >= parse_version('1.10.0')

Expand Down
8 changes: 1 addition & 7 deletions pvlib/tests/iotools/test_psm3.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import os
from pvlib.iotools import psm3
from conftest import needs_pandas_0_22, DATA_DIR
from conftest import DATA_DIR
import numpy as np
import pandas as pd
import pytest
Expand Down Expand Up @@ -70,7 +70,6 @@ def assert_psm3_equal(header, data, expected):
assert (data.index.tzinfo.zone == 'Etc/GMT%+d' % -header['Time Zone'])


@needs_pandas_0_22
@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_get_psm3_tmy(nrel_api_key):
"""test get_psm3 with a TMY"""
Expand All @@ -80,7 +79,6 @@ def test_get_psm3_tmy(nrel_api_key):
assert_psm3_equal(header, data, expected)


@needs_pandas_0_22
@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_get_psm3_singleyear(nrel_api_key):
"""test get_psm3 with a single year"""
Expand All @@ -90,7 +88,6 @@ def test_get_psm3_singleyear(nrel_api_key):
assert_psm3_equal(header, data, expected)


@needs_pandas_0_22
@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_get_psm3_check_leap_day(nrel_api_key):
_, data_2012 = psm3.get_psm3(LATITUDE, LONGITUDE, nrel_api_key,
Expand All @@ -105,7 +102,6 @@ def test_get_psm3_check_leap_day(nrel_api_key):
(LATITUDE, LONGITUDE, nrel_api_key, 'bad', 60),
(LATITUDE, LONGITUDE, nrel_api_key, '2017', 15),
])
@needs_pandas_0_22
@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_get_psm3_tmy_errors(
latitude, longitude, api_key, names, interval
Expand Down Expand Up @@ -134,15 +130,13 @@ def io_input(request):
return obj


@needs_pandas_0_22
def test_parse_psm3(io_input):
"""test parse_psm3"""
header, data = psm3.parse_psm3(io_input)
expected = pd.read_csv(YEAR_TEST_DATA)
assert_psm3_equal(header, data, expected)


@needs_pandas_0_22
def test_read_psm3():
"""test read_psm3"""
header, data = psm3.read_psm3(MANUAL_TEST_DATA)
Expand Down
15 changes: 9 additions & 6 deletions pvlib/tests/test_forecast.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from datetime import datetime, timedelta
from pytz import timezone
from datetime import datetime, timedelta, timezone
import warnings

import pandas as pd
Expand Down Expand Up @@ -114,7 +113,7 @@ def test_vert_level():
@requires_siphon
def test_datetime():
amodel = NAM()
start = datetime.now()
start = datetime.now(tz=timezone.utc)
end = start + timedelta(days=1)
amodel.get_processed_data(_latitude, _longitude, start, end)

Expand All @@ -138,7 +137,6 @@ def test_full():
GFS(set_type='full')


@requires_siphon
def test_temp_convert():
amodel = GFS()
data = pd.DataFrame({'temp_air': [273.15]})
Expand All @@ -157,14 +155,19 @@ def test_temp_convert():
# variables=new_variables)


@requires_siphon
def test_set_location():
amodel = GFS()
latitude, longitude = 32.2, -110.9
time = datetime.now(timezone('UTC'))
time = 'UTC'
amodel.set_location(time, latitude, longitude)


def test_set_query_time_range_tzfail():
amodel = GFS()
with pytest.raises(TypeError):
amodel.set_query_time_range(datetime.now(), datetime.now())


def test_cloud_cover_to_transmittance_linear():
amodel = GFS()
assert_allclose(amodel.cloud_cover_to_transmittance_linear(0), 0.75)
Expand Down
1 change: 1 addition & 0 deletions pvlib/tests/test_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def test_location_all():

@pytest.mark.parametrize('tz', [
pytz.timezone('US/Arizona'), 'America/Phoenix', -7, -7.0,
datetime.timezone.utc
])
def test_location_tz(tz):
Location(32.2, -111, tz)
Expand Down
4 changes: 1 addition & 3 deletions pvlib/tests/test_solarposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
from pvlib.location import Location
from pvlib import solarposition, spa

from conftest import (requires_ephem, needs_pandas_0_17,
requires_spa_c, requires_numba)
from conftest import requires_ephem, requires_spa_c, requires_numba


# setup times and locations to be tested.
Expand Down Expand Up @@ -164,7 +163,6 @@ def test_spa_python_numpy_physical_dst(expected_solpos, golden):
assert_frame_equal(expected_solpos, ephem_data[expected_solpos.columns])


@needs_pandas_0_17
def test_sun_rise_set_transit_spa(expected_rise_set_spa, golden):
# solution from NREL SAP web calculator
south = Location(-35.0, 0.0, tz='UTC')
Expand Down