Skip to content

Commit 83e379a

Browse files
Bump pandas to 0.25.0; test updates (#1448)
* bump pandas min from 0.22.0 to 0.25.0 * fix buggy test__check_pandas_assert_kwargs don't use monkeypatch and mocker in the same test function. pytest-dev/pytest-mock#289 * fix psm3 test (apparent_zenith -> solar_zenith) * whatsnew * better UTC conversion in sun_rise_set_transit_ephem * helpful comments * more whatsnew * '3.0' -> '3' in read_crn test? * apply dtypes during parsing in read_crn * move dropna() post-processing into read_fwf call * fix read_crn for pandas<1.2.0 * Update pvlib/solarposition.py Co-authored-by: Will Holmgren <[email protected]> * nix pytz * UTC -> utc * address simd arccos issue in tracking.singleaxis Co-authored-by: Will Holmgren <[email protected]>
1 parent 8d0f863 commit 83e379a

14 files changed

+50
-26
lines changed

benchmarks/asv.conf.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@
116116
{
117117
"python": "3.6",
118118
"numpy": "1.16.0",
119-
"pandas": "0.22.0",
119+
"pandas": "0.25.0",
120120
"scipy": "1.2.0",
121121
// Note: these don't have a minimum in setup.py
122122
"h5py": "2.10.0",

ci/requirements-py36-min.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dependencies:
1616
- dataclasses
1717
- h5py==3.1.0
1818
- numpy==1.16.0
19-
- pandas==0.22.0
19+
- pandas==0.25.0
2020
- scipy==1.2.0
2121
- pytest-rerunfailures # conda version is >3.6
2222
- pytest-remotedata # conda package is 0.3.0, needs > 0.3.1

ci/requirements-py36.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies:
1111
- nose
1212
- numba
1313
- numpy >= 1.16.0
14-
- pandas >= 0.22.0
14+
- pandas >= 0.25.0
1515
- pip
1616
- pytest
1717
- pytest-cov

ci/requirements-py37.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies:
1111
- nose
1212
- numba
1313
- numpy >= 1.16.0
14-
- pandas >= 0.22.0
14+
- pandas >= 0.25.0
1515
- pip
1616
- pytest
1717
- pytest-cov

ci/requirements-py38.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies:
1111
- nose
1212
- numba
1313
- numpy >= 1.16.0
14-
- pandas >= 0.22.0
14+
- pandas >= 0.25.0
1515
- pip
1616
- pytest
1717
- pytest-cov

ci/requirements-py39.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies:
1111
- nose
1212
# - numba # python 3.9 compat in early 2021
1313
- numpy >= 1.16.0
14-
- pandas >= 0.22.0
14+
- pandas >= 0.25.0
1515
- pip
1616
- pytest
1717
- pytest-cov

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ Bug fixes
1313
~~~~~~~~~
1414
* :py:func:`pvlib.irradiance.get_total_irradiance` and
1515
:py:func:`pvlib.solarposition.spa_python` now raise an error instead
16-
of silently ignoring unknown parameters (:ghpull:`1437`)
16+
of silently ignoring unknown parameters (:pull:`1437`)
17+
* Fix a bug in :py:func:`pvlib.solarposition.sun_rise_set_transit_ephem`
18+
where passing localized timezones with large UTC offsets could return
19+
rise/set/transit times for the wrong day in recent versions of ``ephem``
20+
(:issue:`1449`, :pull:`1448`)
21+
22+
1723
Testing
1824
~~~~~~~
1925

@@ -23,8 +29,10 @@ Documentation
2329
Benchmarking
2430
~~~~~~~~~~~~~
2531
* Updated version of numba in asv.conf from 0.36.1 to 0.40.0 to solve numba/numpy conflict. (:issue:`1439`, :pull:`1440`)
32+
2633
Requirements
2734
~~~~~~~~~~~~
35+
* Minimum pandas version increased to v0.25.0, released July 18, 2019. (:pull:`1448`)
2836

2937
Contributors
3038
~~~~~~~~~~~~

pvlib/iotools/crn.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"""
33

44
import pandas as pd
5+
import numpy as np
56

67

78
HEADERS = [
@@ -107,13 +108,24 @@ def read_crn(filename, map_variables=True):
107108
"""
108109

109110
# read in data
111+
# TODO: instead of parsing as strings and then post-processing, switch to
112+
# pd.read_fwf(..., dtype=dict(zip(HEADERS, DTYPES)), skip_blank_lines=True)
113+
# when our minimum pandas >= 1.2.0 (skip_blank_lines bug for <1.2.0).
114+
# As a workaround, parse all values as strings, then drop NaN, then cast
115+
# to the appropriate dtypes, and mask "sentinal" NaN (e.g. -9999.0)
110116
data = pd.read_fwf(filename, header=None, names=HEADERS, widths=WIDTHS,
111-
na_values=NAN_DICT)
112-
# Remove rows with all nans
117+
dtype=str)
118+
119+
# drop empty (bad) lines
113120
data = data.dropna(axis=0, how='all')
114-
# set dtypes here because dtype kwarg not supported in read_fwf until 0.20
121+
122+
# can't set dtypes in read_fwf because int cols can't contain NaN, so
123+
# do it here instead
115124
data = data.astype(dict(zip(HEADERS, DTYPES)))
116125

126+
# finally, replace -999 values with NaN
127+
data = data.replace(NAN_DICT, value=np.nan)
128+
117129
# set index
118130
# UTC_TIME does not have leading 0s, so must zfill(4) to comply
119131
# with %H%M format

pvlib/solarposition.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import pandas as pd
2323
import scipy.optimize as so
2424
import warnings
25+
import datetime
2526

2627
from pvlib import atmosphere
2728
from pvlib.tools import datetime_to_djd, djd_to_datetime
@@ -574,9 +575,10 @@ def sun_rise_set_transit_ephem(times, latitude, longitude,
574575
trans = []
575576
for thetime in times:
576577
thetime = thetime.to_pydatetime()
577-
# pyephem drops timezone when converting to its internal datetime
578-
# format, so handle timezone explicitly here
579-
obs.date = ephem.Date(thetime - thetime.utcoffset())
578+
# older versions of pyephem ignore timezone when converting to its
579+
# internal datetime format, so convert to UTC here to support
580+
# all versions. GH #1449
581+
obs.date = ephem.Date(thetime.astimezone(datetime.timezone.utc))
580582
sunrise.append(_ephem_to_timezone(rising(sun), tzinfo))
581583
sunset.append(_ephem_to_timezone(setting(sun), tzinfo))
582584
trans.append(_ephem_to_timezone(transit(sun), tzinfo))

pvlib/tests/iotools/test_crn.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def test_read_crn_problems(testfile_problems, columns_mapped, dtypes):
8383
'2020-07-06 13:10:00'],
8484
freq=None).tz_localize('UTC')
8585
values = np.array([
86-
[92821, 20200706, 1200, 20200706, 700, '3.0', -80.69, 28.62, 24.9,
86+
[92821, 20200706, 1200, 20200706, 700, '3', -80.69, 28.62, 24.9,
8787
0.0, np.nan, 0, 25.5, 'C', 0, 93.0, 0, nan, nan, 990, 0, 1.57, 0],
8888
[92821, 20200706, 1310, 20200706, 810, '2.623', -80.69, 28.62,
8989
26.9, 0.0, 430.0, 0, 30.2, 'C', 0, 87.0, 0, nan, nan, 989, 0,

pvlib/tests/iotools/test_psm3.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def test_read_psm3_map_variables():
170170
data, metadata = psm3.read_psm3(MANUAL_TEST_DATA, map_variables=True)
171171
columns_mapped = ['Year', 'Month', 'Day', 'Hour', 'Minute', 'dhi', 'dni',
172172
'ghi', 'dhi_clear', 'dni_clear', 'ghi_clear',
173-
'Cloud Type', 'Dew Point', 'apparent_zenith',
173+
'Cloud Type', 'Dew Point', 'solar_zenith',
174174
'Fill Flag', 'albedo', 'wind_speed',
175175
'precipitable_water', 'wind_direction',
176176
'relative_humidity', 'temp_air', 'pressure']

pvlib/tests/test_conftest.py

+9-10
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,21 @@ def test_use_fixture_with_decorator(some_data):
5252
'assert_frame_equal'])
5353
@pytest.mark.parametrize('pd_version', ['1.0.0', '1.1.0'])
5454
@pytest.mark.parametrize('check_less_precise', [True, False])
55-
def test__check_pandas_assert_kwargs(mocker, monkeypatch,
56-
function_name, pd_version,
55+
def test__check_pandas_assert_kwargs(mocker, function_name, pd_version,
5756
check_less_precise):
5857
# test that conftest._check_pandas_assert_kwargs returns appropriate
5958
# kwargs for the assert_x_equal functions
6059

61-
# patch the pandas assert; not interested in actually calling them:
62-
def patched_assert(*args, **kwargs):
63-
pass
60+
# NOTE: be careful about mixing mocker.patch and pytest.MonkeyPatch!
61+
# they do not coordinate their cleanups, so it is safest to only
62+
# use one or the other. GH #1447
6463

65-
monkeypatch.setattr(pandas.testing, function_name, patched_assert)
66-
# then attach a spy to it so we can see what args it is called with:
67-
mocked_function = mocker.spy(pandas.testing, function_name)
64+
# patch the pandas assert; not interested in actually calling them,
65+
# plus we want to spy on how they get called.
66+
spy = mocker.patch('pandas.testing.' + function_name)
6867
# patch pd.__version__ to exercise the two branches in
6968
# conftest._check_pandas_assert_kwargs
70-
monkeypatch.setattr(pandas, '__version__', pd_version)
69+
mocker.patch('pandas.__version__', new=pd_version)
7170

7271
# finally, run the function and check what args got passed to pandas:
7372
assert_function = getattr(conftest, function_name)
@@ -79,4 +78,4 @@ def patched_assert(*args, **kwargs):
7978
else:
8079
expected_kwargs = {'check_less_precise': check_less_precise}
8180

82-
mocked_function.assert_called_with(*args, **expected_kwargs)
81+
spy.assert_called_once_with(*args, **expected_kwargs)

pvlib/tracking.py

+3
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,9 @@ def singleaxis(apparent_zenith, apparent_azimuth,
510510

511511
# Calculate surface_tilt
512512
dotproduct = (panel_norm_earth * projected_normal).sum(axis=1)
513+
# for edge cases like axis_tilt=90, numpy's SIMD can produce values like
514+
# dotproduct = (1 + 2e-16). Clip off the excess so that arccos works:
515+
dotproduct = np.clip(dotproduct, -1, 1)
513516
surface_tilt = 90 - np.degrees(np.arccos(dotproduct))
514517

515518
# Bundle DataFrame for return values and filter for sun below horizon.

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
URL = 'https://github.com/pvlib/pvlib-python'
4040

4141
INSTALL_REQUIRES = ['numpy >= 1.16.0',
42-
'pandas >= 0.22.0',
42+
'pandas >= 0.25.0',
4343
'pytz',
4444
'requests',
4545
'scipy >= 1.2.0',

0 commit comments

Comments
 (0)