Skip to content

Commit

Permalink
Test and CI updates (#129)
Browse files Browse the repository at this point in the history
* CI: drop 3.6, add 3.9, 3.10; only lint once

* FutureWarning: The series.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.

* pvlib deprecation warnings

* mirror tests for pvlib 0.9.0

* lint

* lint

* another series.append -> pd.concat

* whatsnew

* fix scipy error
  • Loading branch information
kandersolar authored Feb 16, 2022
1 parent 27ec167 commit 1d43c1a
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 50 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ jobs:

strategy:
matrix:
os: [ubuntu-latest, macos-10.15, windows-latest] # macos-latest does not have py3.6
python-version: [3.6, 3.7, 3.8]
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.7, 3.8, 3.9, "3.10"]
requirements: [requirements.txt]
include:
- requirements: requirements-min.txt
python-version: 3.6
python-version: 3.7
os: ubuntu-latest

runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -65,7 +65,7 @@ jobs:

strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
python-version: [3.7]

runs-on: ubuntu-latest

Expand Down
5 changes: 5 additions & 0 deletions docs/whatsnew/0.1.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ Bug Fixes
* Fixed an issue with :py:func:`pvanalytics.features.clearsky.reno` in recent
pandas versions (:issue:`125`, :pull:`128`)

Requirements
~~~~~~~~~~~~

* Drop support for python 3.6, which reached end of life Dec 2021 (:pull:`129`)

Documentation
~~~~~~~~~~~~~

Expand Down
39 changes: 34 additions & 5 deletions pvanalytics/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
import pytest
import numpy as np
import pandas as pd
import pvlib
from pvlib import location, pvsystem
from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS

from pkg_resources import Requirement, parse_version


def pytest_addoption(parser):
parser.addoption(
Expand All @@ -29,6 +32,25 @@ def pytest_collection_modifyitems(config, items):
item.add_marker(skip_slow)


def requires_pvlib(versionspec, reason=''):
"""
Decorator to skip pytest tests if a dependency version is not satisfied.
Parameters
----------
versionspec : str
A version specifier like '==0.8.1' or '<=0.9.0'
reason : str, optional
Additional context to show in pytest log output
"""
req = Requirement.parse('pvlib' + versionspec)
is_satisfied = parse_version(pvlib.__version__) in req
message = 'requires pvlib' + versionspec
if reason:
message += f'({reason})'
return pytest.mark.skipif(not is_satisfied, reason=message)


@pytest.fixture
def quadratic():
"""Downward facing quadratic.
Expand Down Expand Up @@ -106,17 +128,24 @@ def solarposition_year(one_year_hourly, albuquerque):


@pytest.fixture(scope='module')
def system_parameters():
"""System parameters for generating simulated power data."""
def array_parameters():
"""Array parameters for generating simulated power data."""
sandia_modules = pvsystem.retrieve_sam('SandiaMod')
sapm_inverters = pvsystem.retrieve_sam('cecinverter')
module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
inverter = sapm_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']
temperature_model_parameters = (
TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
)
return {
'module_parameters': module,
'inverter_parameters': inverter,
'temperature_model_parameters': temperature_model_parameters
}


@pytest.fixture(scope='module')
def system_parameters():
"""PVSystem parameters for generating simulated power data."""
sapm_inverters = pvsystem.retrieve_sam('cecinverter')
inverter = sapm_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']
return {
'inverter_parameters': inverter,
}
9 changes: 3 additions & 6 deletions pvanalytics/tests/features/test_clearsky.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
"""Tests for feature labeling functions."""
import pytest
import pandas as pd
import pvlib
from pvanalytics.features import clearsky
from ..conftest import requires_pvlib

from pkg_resources import parse_version
is_old_pvlib = parse_version(pvlib.__version__) < parse_version("0.9.0")


@pytest.mark.skipif(is_old_pvlib, reason="GH #105")
@requires_pvlib('>=0.9.0', reason="GH #105")
@pytest.mark.filterwarnings("ignore:Support for multi-dimensional indexing")
def test_reno_identical(quadratic):
"""Identical clearsky and measured irradiance all True"""
Expand All @@ -18,7 +15,7 @@ def test_reno_identical(quadratic):
assert clearsky.reno(quadratic, quadratic).all()


@pytest.mark.skipif(is_old_pvlib, reason="GH #105")
@requires_pvlib('>=0.9.0', reason="GH #105")
@pytest.mark.filterwarnings("ignore:Support for multi-dimensional indexing")
@pytest.mark.filterwarnings("ignore:invalid value encountered in")
def test_reno_begining_end(quadratic):
Expand Down
20 changes: 12 additions & 8 deletions pvanalytics/tests/features/test_clipping.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,12 @@ def test_threshold_clipping_four_days(quadratic, quadratic_clipped):
# scale the rest of the days below the clipping threshold
full_day *= 0.75

power = full_day_clipped
power.append(full_day)
power.append(full_day)
power.append(full_day)
power = pd.concat([
full_day_clipped,
full_day,
full_day,
full_day,
])

power.index = pd.date_range(
start='01/01/2020 00:00', freq='10T', periods=len(power)
Expand All @@ -232,10 +234,12 @@ def test_threshold_no_clipping_four_days(quadratic):
)
full_day.fillna(0)

power = full_day
power.append(full_day * 1.3)
power.append(full_day * 1.2)
power.append(full_day * 1.1)
power = pd.concat([
full_day,
full_day * 1.3,
full_day * 1.2,
full_day * 1.1,
])

power.index = pd.date_range(
start='01/01/2020 00:00', freq='10T', periods=len(power)
Expand Down
67 changes: 64 additions & 3 deletions pvanalytics/tests/features/test_orientation.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import pytest
from pandas.util.testing import assert_series_equal
import pandas as pd
from pvlib import tracking, modelchain, irradiance
from pvlib import tracking, pvsystem, modelchain, irradiance
from pvanalytics.features import orientation

from ..conftest import requires_pvlib


def test_clearsky_ghi_fixed(clearsky, solarposition):
"""Identify every day as fixed, since clearsky GHI is sunny."""
Expand Down Expand Up @@ -40,9 +42,13 @@ def test_ghi_not_tracking(clearsky, solarposition):


@pytest.fixture
def power_tracking(clearsky, albuquerque, system_parameters):
def power_tracking_old_pvlib(clearsky, albuquerque, array_parameters,
system_parameters):
"""Simulated power for a pvlib SingleAxisTracker PVSystem in Albuquerque"""
system = tracking.SingleAxisTracker(**system_parameters)
# copy of `power_tracking` but with older pvlib API
# TODO: remove when minimum pvlib version is >= 0.9.0
system = tracking.SingleAxisTracker(**array_parameters,
**system_parameters)
mc = modelchain.ModelChain(
system,
albuquerque,
Expand All @@ -51,6 +57,34 @@ def power_tracking(clearsky, albuquerque, system_parameters):
return mc.ac


@pytest.fixture
def power_tracking(clearsky, albuquerque, array_parameters, system_parameters):
"""Simulated power for a pvlib SingleAxisTracker PVSystem in Albuquerque"""
array = pvsystem.Array(pvsystem.SingleAxisTrackerMount(),
**array_parameters)
system = pvsystem.PVSystem(arrays=[array],
**system_parameters)
mc = modelchain.ModelChain(
system,
albuquerque,
)
mc.run_model(clearsky)
return mc.results.ac


@requires_pvlib('<0.9.0', reason="SingleAxisTracker deprecation")
def test_power_tracking_old_pvlib(power_tracking_old_pvlib, solarposition):
"""simulated power from a single axis tracker is identified as sunny
with tracking=True"""
# copy of `test_power_tracking` but with older pvlib API
# TODO: remove when minimum pvlib version is >= 0.9.0
assert orientation.tracking_nrel(
power_tracking_old_pvlib,
solarposition['zenith'] < 87
).all()


@requires_pvlib('>=0.9.0', reason="Array class")
def test_power_tracking(power_tracking, solarposition):
"""simulated power from a single axis tracker is identified as sunny
with tracking=True"""
Expand All @@ -60,6 +94,33 @@ def test_power_tracking(power_tracking, solarposition):
).all()


@requires_pvlib('<0.9.0', reason="SingleAxisTracker deprecation")
def test_power_tracking_perturbed_old_pvlib(power_tracking_old_pvlib,
solarposition):
"""A day with perturbed values is not marked as tracking."""
# copy of `test_power_tracking_perturbed` but with older pvlib API
# TODO: remove when minimum pvlib version is >= 0.9.0
power_tracking_old_pvlib.iloc[6:18] = 10
expected = pd.Series(True, index=power_tracking_old_pvlib.index)
expected.iloc[0:24] = False
assert_series_equal(
expected,
orientation.tracking_nrel(
power_tracking_old_pvlib,
solarposition['zenith'] < 87
)
)
assert_series_equal(
expected,
orientation.tracking_nrel(
power_tracking_old_pvlib,
solarposition['zenith'] < 87,
peak_min=100
)
)


@requires_pvlib('>=0.9.0', reason="Array class")
def test_power_tracking_perturbed(power_tracking, solarposition):
"""A day with perturbed values is not marked as tracking."""
power_tracking.iloc[6:18] = 10
Expand Down
2 changes: 1 addition & 1 deletion pvanalytics/tests/quality/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ def _shift_between(series, shift, start, end):
during = series[start:end]
after = series[end:]
during = during + shift
shifted = before.append(during).append(after)
shifted = pd.concat([before, during, after])
return shifted[~shifted.index.duplicated()]


Expand Down
Loading

0 comments on commit 1d43c1a

Please sign in to comment.