From a3da3b6da00560498187b07bedfac217d9ad3823 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 6 Aug 2020 11:22:08 -0600 Subject: [PATCH 1/7] add wrapper functions for pandas testing asserts --- pvlib/tests/conftest.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pvlib/tests/conftest.py b/pvlib/tests/conftest.py index ee2f2ae06c..cc6481c416 100644 --- a/pvlib/tests/conftest.py +++ b/pvlib/tests/conftest.py @@ -35,6 +35,29 @@ def inner(*args, **kwargs): return inner return wrapper + +# custom test function that handles the change in default +# tolerances in pandas 1.1.0. See pvlib GH #1018 +def assert_series_equal(left, right, **kwargs): + if parse_version(pd.__version__) >= parse_version('1.1.0'): + kwargs.pop('check_less_precise') + else: + kwargs.pop('rtol') + kwargs.pop('atol') + pd.testing.assert_series_equal(left, right, **kwargs) + + +# custom test function that handles the change in default +# tolerances in pandas 1.1.0. See pvlib GH #1018 +def assert_frame_equal(left, right, **kwargs): + if parse_version(pd.__version__) >= parse_version('1.1.0'): + kwargs.pop('check_less_precise') + else: + kwargs.pop('rtol') + kwargs.pop('atol') + pd.testing.assert_frame_equal(left, right, **kwargs) + + # commonly used directories in the tests TEST_DIR = Path(__file__).parent DATA_DIR = TEST_DIR.parent / 'data' From f725744623f7e4dd1529929e476d864746f05778 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 6 Aug 2020 11:22:49 -0600 Subject: [PATCH 2/7] update tests to use assert wrapper instead of importing from pandas.testing --- pvlib/tests/iotools/test_crn.py | 2 +- pvlib/tests/iotools/test_solrad.py | 2 +- pvlib/tests/test_atmosphere.py | 2 +- pvlib/tests/test_bifacial.py | 10 +++++----- pvlib/tests/test_clearsky.py | 2 +- pvlib/tests/test_iam.py | 2 +- pvlib/tests/test_inverter.py | 2 +- pvlib/tests/test_irradiance.py | 2 +- pvlib/tests/test_location.py | 2 +- pvlib/tests/test_modelchain.py | 2 +- pvlib/tests/test_pvsystem.py | 2 +- pvlib/tests/test_snow.py | 2 +- pvlib/tests/test_soiling.py | 2 +- pvlib/tests/test_solarposition.py | 2 +- pvlib/tests/test_temperature.py | 2 +- pvlib/tests/test_tracking.py | 2 +- 16 files changed, 20 insertions(+), 20 deletions(-) diff --git a/pvlib/tests/iotools/test_crn.py b/pvlib/tests/iotools/test_crn.py index 465add4cb4..afb17dce7f 100644 --- a/pvlib/tests/iotools/test_crn.py +++ b/pvlib/tests/iotools/test_crn.py @@ -1,5 +1,5 @@ import pandas as pd -from pandas.testing import assert_frame_equal +from conftest import assert_frame_equal import numpy as np from numpy import dtype, nan import pytest diff --git a/pvlib/tests/iotools/test_solrad.py b/pvlib/tests/iotools/test_solrad.py index b4a17bfd2f..9a3494f250 100644 --- a/pvlib/tests/iotools/test_solrad.py +++ b/pvlib/tests/iotools/test_solrad.py @@ -1,5 +1,5 @@ import pandas as pd -from pandas.testing import assert_frame_equal +from conftest import assert_frame_equal import numpy as np from numpy import nan diff --git a/pvlib/tests/test_atmosphere.py b/pvlib/tests/test_atmosphere.py index 5412389d83..c23827a4d6 100644 --- a/pvlib/tests/test_atmosphere.py +++ b/pvlib/tests/test_atmosphere.py @@ -4,7 +4,7 @@ from numpy import nan from numpy.testing import assert_allclose import pandas as pd -from pandas.testing import assert_series_equal +from conftest import assert_series_equal import pytest from pvlib import atmosphere diff --git a/pvlib/tests/test_bifacial.py b/pvlib/tests/test_bifacial.py index e80fde93d4..925d9be4de 100644 --- a/pvlib/tests/test_bifacial.py +++ b/pvlib/tests/test_bifacial.py @@ -1,7 +1,7 @@ import pandas as pd from datetime import datetime from pvlib.bifacial import pvfactors_timeseries -from conftest import requires_pvfactors +from conftest import requires_pvfactors, assert_series_equal import pytest @@ -49,8 +49,8 @@ def test_pvfactors_timeseries(): rho_front_pvrow=rho_front_pvrow, rho_back_pvrow=rho_back_pvrow, horizon_band_angle=horizon_band_angle) - pd.testing.assert_series_equal(ipoa_inc_front, expected_ipoa_front) - pd.testing.assert_series_equal(ipoa_inc_back, expected_ipoa_back) + assert_series_equal(ipoa_inc_front, expected_ipoa_front) + assert_series_equal(ipoa_inc_back, expected_ipoa_back) @requires_pvfactors @@ -97,5 +97,5 @@ def test_pvfactors_timeseries_pandas_inputs(): rho_front_pvrow=rho_front_pvrow, rho_back_pvrow=rho_back_pvrow, horizon_band_angle=horizon_band_angle) - pd.testing.assert_series_equal(ipoa_inc_front, expected_ipoa_front) - pd.testing.assert_series_equal(ipoa_inc_back, expected_ipoa_back) + assert_series_equal(ipoa_inc_front, expected_ipoa_front) + assert_series_equal(ipoa_inc_back, expected_ipoa_back) diff --git a/pvlib/tests/test_clearsky.py b/pvlib/tests/test_clearsky.py index 67b185e56b..9ec4b1dfb9 100644 --- a/pvlib/tests/test_clearsky.py +++ b/pvlib/tests/test_clearsky.py @@ -7,7 +7,7 @@ import pytest from numpy.testing import assert_allclose -from pandas.testing import assert_frame_equal, assert_series_equal +from conftest import assert_frame_equal, assert_series_equal from pvlib.location import Location from pvlib import clearsky diff --git a/pvlib/tests/test_iam.py b/pvlib/tests/test_iam.py index 9b886762b2..9b1d2a01d8 100644 --- a/pvlib/tests/test_iam.py +++ b/pvlib/tests/test_iam.py @@ -9,7 +9,7 @@ import pandas as pd import pytest -from pandas.testing import assert_series_equal +from conftest import assert_series_equal from numpy.testing import assert_allclose from pvlib import iam as _iam diff --git a/pvlib/tests/test_inverter.py b/pvlib/tests/test_inverter.py index 0816683f3a..79d4cc2fb9 100644 --- a/pvlib/tests/test_inverter.py +++ b/pvlib/tests/test_inverter.py @@ -3,7 +3,7 @@ import numpy as np import pandas as pd -from pandas.testing import assert_series_equal +from conftest import assert_series_equal from numpy.testing import assert_allclose from pvlib import inverter diff --git a/pvlib/tests/test_irradiance.py b/pvlib/tests/test_irradiance.py index b39b4543de..3a7399e39c 100644 --- a/pvlib/tests/test_irradiance.py +++ b/pvlib/tests/test_irradiance.py @@ -9,7 +9,7 @@ import pytest from numpy.testing import assert_almost_equal, assert_allclose -from pandas.testing import assert_frame_equal, assert_series_equal +from conftest import assert_frame_equal, assert_series_equal from pvlib import irradiance diff --git a/pvlib/tests/test_location.py b/pvlib/tests/test_location.py index 0694035df0..6bff7cb3ff 100644 --- a/pvlib/tests/test_location.py +++ b/pvlib/tests/test_location.py @@ -4,7 +4,7 @@ import numpy as np from numpy import nan import pandas as pd -from pandas.testing import assert_frame_equal, assert_index_equal +from conftest import assert_frame_equal, assert_index_equal import pytest diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 5fe7367b28..2a26c5d372 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -10,7 +10,7 @@ from pvlib.location import Location from pvlib._deprecation import pvlibDeprecationWarning -from pandas.testing import assert_series_equal +from conftest import assert_series_equal import pytest from conftest import fail_on_pvlib_version, requires_scipy, requires_tables diff --git a/pvlib/tests/test_pvsystem.py b/pvlib/tests/test_pvsystem.py index 539e903651..e560894ed2 100644 --- a/pvlib/tests/test_pvsystem.py +++ b/pvlib/tests/test_pvsystem.py @@ -5,7 +5,7 @@ import pandas as pd import pytest -from pandas.testing import assert_series_equal, assert_frame_equal +from conftest import assert_series_equal, assert_frame_equal from numpy.testing import assert_allclose from pvlib import inverter, pvsystem diff --git a/pvlib/tests/test_snow.py b/pvlib/tests/test_snow.py index e988f4a191..c93cfc8f82 100644 --- a/pvlib/tests/test_snow.py +++ b/pvlib/tests/test_snow.py @@ -1,7 +1,7 @@ import numpy as np import pandas as pd -from pandas.testing import assert_series_equal +from conftest import assert_series_equal from pvlib import snow from pvlib.tools import sind diff --git a/pvlib/tests/test_soiling.py b/pvlib/tests/test_soiling.py index 8ca5a41618..ddc068c97d 100644 --- a/pvlib/tests/test_soiling.py +++ b/pvlib/tests/test_soiling.py @@ -4,7 +4,7 @@ import datetime import numpy as np import pandas as pd -from pandas.testing import assert_series_equal +from conftest import assert_series_equal from pvlib.soiling import hsu, kimber from pvlib.iotools import read_tmy3 from conftest import requires_scipy, DATA_DIR diff --git a/pvlib/tests/test_solarposition.py b/pvlib/tests/test_solarposition.py index 187c4851d3..3d29749fb2 100644 --- a/pvlib/tests/test_solarposition.py +++ b/pvlib/tests/test_solarposition.py @@ -5,7 +5,7 @@ import numpy as np import pandas as pd -from pandas.testing import assert_frame_equal, assert_series_equal +from conftest import assert_frame_equal, assert_series_equal from numpy.testing import assert_allclose import pytest diff --git a/pvlib/tests/test_temperature.py b/pvlib/tests/test_temperature.py index 2015cdba58..19e65a05e3 100644 --- a/pvlib/tests/test_temperature.py +++ b/pvlib/tests/test_temperature.py @@ -2,7 +2,7 @@ import numpy as np import pytest -from pandas.testing import assert_series_equal +from conftest import assert_series_equal from numpy.testing import assert_allclose from pvlib import temperature diff --git a/pvlib/tests/test_tracking.py b/pvlib/tests/test_tracking.py index c229ea7422..365dca121c 100644 --- a/pvlib/tests/test_tracking.py +++ b/pvlib/tests/test_tracking.py @@ -3,7 +3,7 @@ import pandas as pd import pytest -from pandas.testing import assert_frame_equal +from conftest import assert_frame_equal from numpy.testing import assert_allclose from pvlib.location import Location From 023ea0b806005a1e546fffe243be542085f9bcf1 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 6 Aug 2020 11:33:12 -0600 Subject: [PATCH 3/7] update wrappers --- pvlib/tests/conftest.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pvlib/tests/conftest.py b/pvlib/tests/conftest.py index cc6481c416..9a34dba502 100644 --- a/pvlib/tests/conftest.py +++ b/pvlib/tests/conftest.py @@ -36,25 +36,25 @@ def inner(*args, **kwargs): return wrapper -# custom test function that handles the change in default +# custom test function that handles the change in API related to default # tolerances in pandas 1.1.0. See pvlib GH #1018 def assert_series_equal(left, right, **kwargs): if parse_version(pd.__version__) >= parse_version('1.1.0'): - kwargs.pop('check_less_precise') + kwargs.pop('check_less_precise', None) else: - kwargs.pop('rtol') - kwargs.pop('atol') + kwargs.pop('rtol', None) + kwargs.pop('atol', None) pd.testing.assert_series_equal(left, right, **kwargs) -# custom test function that handles the change in default +# custom test function that handles the change in API related to default # tolerances in pandas 1.1.0. See pvlib GH #1018 def assert_frame_equal(left, right, **kwargs): if parse_version(pd.__version__) >= parse_version('1.1.0'): - kwargs.pop('check_less_precise') + kwargs.pop('check_less_precise', None) else: - kwargs.pop('rtol') - kwargs.pop('atol') + kwargs.pop('rtol', None) + kwargs.pop('atol', None) pd.testing.assert_frame_equal(left, right, **kwargs) From 52646f3baa7658083b2ee104bda8d8baa9748a0b Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 6 Aug 2020 19:35:06 -0600 Subject: [PATCH 4/7] refactor asserts --- pvlib/tests/conftest.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/pvlib/tests/conftest.py b/pvlib/tests/conftest.py index 9a34dba502..40aefcd403 100644 --- a/pvlib/tests/conftest.py +++ b/pvlib/tests/conftest.py @@ -36,25 +36,34 @@ def inner(*args, **kwargs): return wrapper -# custom test function that handles the change in API related to default -# tolerances in pandas 1.1.0. See pvlib GH #1018 -def assert_series_equal(left, right, **kwargs): +def _check_pandas_assert_kwargs(kwargs): + # handles the change in API related to default + # tolerances in pandas 1.1.0. See pvlib GH #1018 if parse_version(pd.__version__) >= parse_version('1.1.0'): - kwargs.pop('check_less_precise', None) + if kwargs.pop('check_less_precise', False): + kwargs['atol'] = 1e-3 + kwargs['rtol'] = 1e-3 + else: + kwargs['atol'] = 1e-5 + kwargs['rtol'] = 1e-5 else: kwargs.pop('rtol', None) kwargs.pop('atol', None) + return kwargs + + +def assert_index_equal(left, right, **kwargs): + kwargs = _check_pandas_assert_kwargs(kwargs) + pd.testing.assert_index_equal(left, right, **kwargs) + + +def assert_series_equal(left, right, **kwargs): + kwargs = _check_pandas_assert_kwargs(kwargs) pd.testing.assert_series_equal(left, right, **kwargs) -# custom test function that handles the change in API related to default -# tolerances in pandas 1.1.0. See pvlib GH #1018 def assert_frame_equal(left, right, **kwargs): - if parse_version(pd.__version__) >= parse_version('1.1.0'): - kwargs.pop('check_less_precise', None) - else: - kwargs.pop('rtol', None) - kwargs.pop('atol', None) + kwargs = _check_pandas_assert_kwargs(kwargs) pd.testing.assert_frame_equal(left, right, **kwargs) From 87db5b4f8dc4628e9100e1cbae5d6945fc958158 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Fri, 7 Aug 2020 06:41:51 -0600 Subject: [PATCH 5/7] update basic_chain test values --- pvlib/tests/test_modelchain.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pvlib/tests/test_modelchain.py b/pvlib/tests/test_modelchain.py index 2a26c5d372..bba8a711a0 100644 --- a/pvlib/tests/test_modelchain.py +++ b/pvlib/tests/test_modelchain.py @@ -757,9 +757,9 @@ def test_basic_chain_alt_az(sam_data, cec_inverter_parameters, surface_tilt=surface_tilt, surface_azimuth=surface_azimuth) - expected = pd.Series(np.array([115.40352679, -2.00000000e-02]), + expected = pd.Series(np.array([111.621405, -2.00000000e-02]), index=times) - assert_series_equal(ac, expected, check_less_precise=1) + assert_series_equal(ac, expected) @requires_scipy @@ -778,9 +778,9 @@ def test_basic_chain_strategy(sam_data, cec_inverter_parameters, cec_inverter_parameters, orientation_strategy='south_at_latitude_tilt', altitude=altitude) - expected = pd.Series(np.array([183.522449305, -2.00000000e-02]), + expected = pd.Series(np.array([178.382754, -2.00000000e-02]), index=times) - assert_series_equal(ac, expected, check_less_precise=1) + assert_series_equal(ac, expected) @requires_scipy @@ -803,9 +803,9 @@ def test_basic_chain_altitude_pressure(sam_data, cec_inverter_parameters, surface_azimuth=surface_azimuth, pressure=93194) - expected = pd.Series(np.array([116.595664887, -2.00000000e-02]), + expected = pd.Series(np.array([113.190045, -2.00000000e-02]), index=times) - assert_series_equal(ac, expected, check_less_precise=1) + assert_series_equal(ac, expected) dc, ac = modelchain.basic_chain(times, latitude, longitude, module_parameters, temp_model_params, @@ -814,9 +814,9 @@ def test_basic_chain_altitude_pressure(sam_data, cec_inverter_parameters, surface_azimuth=surface_azimuth, altitude=altitude) - expected = pd.Series(np.array([116.595664887, -2.00000000e-02]), + expected = pd.Series(np.array([113.189814, -2.00000000e-02]), index=times) - assert_series_equal(ac, expected, check_less_precise=1) + assert_series_equal(ac, expected) @pytest.mark.parametrize('strategy, strategy_str', [ From 004c91ed3bd449c015f2705467d55d0f899ea73d Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Fri, 7 Aug 2020 10:16:23 -0600 Subject: [PATCH 6/7] whatsnew --- docs/sphinx/source/whatsnew/v0.8.0.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index cbe57587e9..2bda4b0db8 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -53,6 +53,9 @@ Testing (:pull:`1006`) * Update the `data/test_psm3_tmy-2017.csv` datafile to match the updated NSRDB data. (:issue:`1005`, :pull:`1007`) +* Add wrappers around the pandas assert_X_equal functions to accommodate the + changed API and default precision thresholds in pandas 1.1.0 + (:issue:`1018`, :pull:`1021`) Documentation ~~~~~~~~~~~~~ From 390ff61cb50968ad45aa8baef4d8fda3df818a5b Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Fri, 7 Aug 2020 13:27:36 -0600 Subject: [PATCH 7/7] add test --- pvlib/tests/test_conftest.py | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pvlib/tests/test_conftest.py b/pvlib/tests/test_conftest.py index 300f58d325..1efa0b62b3 100644 --- a/pvlib/tests/test_conftest.py +++ b/pvlib/tests/test_conftest.py @@ -1,5 +1,7 @@ import pytest +import pandas +import conftest from conftest import fail_on_pvlib_version from pvlib._deprecation import pvlibDeprecationWarning, deprecated @@ -43,3 +45,38 @@ def test_use_fixture_with_decorator(some_data): assert some_data == "some data" with pytest.warns(pvlibDeprecationWarning): # test for deprecation warning deprec_func(some_data) + + +@pytest.mark.parametrize('function_name', ['assert_index_equal', + 'assert_series_equal', + 'assert_frame_equal']) +@pytest.mark.parametrize('pd_version', ['1.0.0', '1.1.0']) +@pytest.mark.parametrize('check_less_precise', [True, False]) +def test__check_pandas_assert_kwargs(mocker, monkeypatch, + function_name, pd_version, + check_less_precise): + # test that conftest._check_pandas_assert_kwargs returns appropriate + # kwargs for the assert_x_equal functions + + # patch the pandas assert; not interested in actually calling them: + def patched_assert(*args, **kwargs): + pass + + monkeypatch.setattr(pandas.testing, function_name, patched_assert) + # then attach a spy to it so we can see what args it is called with: + mocked_function = mocker.spy(pandas.testing, function_name) + # patch pd.__version__ to exercise the two branches in + # conftest._check_pandas_assert_kwargs + monkeypatch.setattr(pandas, '__version__', pd_version) + + # finally, run the function and check what args got passed to pandas: + assert_function = getattr(conftest, function_name) + args = [None, None] + assert_function(*args, check_less_precise=check_less_precise) + if pd_version == '1.1.0': + tol = 1e-3 if check_less_precise else 1e-5 + expected_kwargs = {'atol': tol, 'rtol': tol} + else: + expected_kwargs = {'check_less_precise': check_less_precise} + + mocked_function.assert_called_with(*args, **expected_kwargs)