Skip to content

Commit 25c2799

Browse files
RHammond2ejsimley
andauthored
Fix: Dependency pinning and upgrade issues (#312)
* fix pytest v9 typing issue * update for python 3.14 support now that pygam is being updated again * adding fill_value=False to shift function in filters.unresponsive_flag to get expected behavior at end of time series with NumPy v2 * change np.Inf to np.inf in timeseries tests for compatibility with NumPy v2 * fix scikit-learn max version for unsupported functionality in pygam * udpate python in ci-tests * convert python versions to strings * attempt sklearn 1.5.x * drop 3.14 support due to windows scikit-learn build issues * update CI runner * update changelog * bump pytest minimum to support subtests for finnicky tests * add xfail to finnicky gbm test and subtests for multiple checks * add reason to xfail * update target versions for linting * autoupdate pre-commit * add subtests to yaw and xfail for UQ * update changelog * move xfail to the correct test * limit pandas to <3 * update changelog with correct date --------- Co-authored-by: Eric Simley <[email protected]>
1 parent 78ad64f commit 25c2799

File tree

10 files changed

+95
-57
lines changed

10 files changed

+95
-57
lines changed

.github/workflows/ci-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
strategy:
2121
matrix:
2222
os: [ubuntu-latest, windows-latest]
23-
python-version: [3.9, 3.11]
23+
python-version: ["3.10", "3.13"]
2424

2525
steps:
2626
- uses: actions/checkout@v4

.pre-commit-config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/pycqa/isort
3-
rev: 5.12.0
3+
rev: 7.0.0
44
hooks:
55
- id: isort
66
additional_dependencies: [toml]
@@ -15,21 +15,21 @@ repos:
1515
types: [pyi]
1616

1717
- repo: https://github.com/asottile/pyupgrade
18-
rev: v3.15.0
18+
rev: v3.21.2
1919
hooks:
2020
- id: pyupgrade
2121
args: [--py38-plus]
2222

2323
- repo: https://github.com/psf/black
24-
rev: 23.3.0
24+
rev: 26.1.0
2525
hooks:
2626
- id: black
2727
name: black
2828
stages: [pre-commit]
2929
language_version: python3
3030

3131
- repo: https://github.com/pre-commit/pre-commit-hooks
32-
rev: v4.4.0
32+
rev: v6.0.0
3333
hooks:
3434
- id: trailing-whitespace
3535
- id: end-of-file-fixer
@@ -42,6 +42,6 @@ repos:
4242
args: [--autofix]
4343

4444
- repo: https://github.com/pycqa/flake8
45-
rev: '6.0.0'
45+
rev: '7.3.0'
4646
hooks:
4747
- id: flake8

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
# Changelog
22
All notable changes to this project will be documented in this file. If you make a notable change to the project, please add a line describing the change to the "unreleased" section. The maintainers will make an effort to keep the [Github Releases](https://github.com/NREL/OpenOA/releases) page up to date with this changelog. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
33

4+
## v3.1.4 - 2026-01-29
5+
6+
- During the custom test collection, convert the `Path` objects to `str` to avoid issues with the
7+
type enforcement of `list[str]` for `args` in Pytest v9.
8+
- Update PyGAM minimum version for its latest update that includes Python 3.10-3.13 support.
9+
- Remove maximum version pins for scipy and statsmodels with the support of the latest Python versions.
10+
- Adds a maximum version for scikit-learn for a change in their `__sklearn_tags__` support.
11+
- Deprecate support for Python 3.8 and 3.9, with additional support for Python 3.12 and 3.13.
12+
- Update the min and max versions to test in the testing CI workflow.
13+
- Utilizes pytest xfail and subtests to manange intermittent and finnicky test failures until a
14+
long-term solution can be implemented.
15+
- Pin Pandas maximum version to the 2.x release cycle.
16+
417
## v3.1.3 - 2025-01-31
518

619
- Pin SciPy to >= 1.7 and <1.14 to avoid an incompatibility error with PyGAM.

openoa/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "3.1.3"
1+
__version__ = "3.1.4"
22

33
"""
44
When bumping version, please be sure to also update parameters in sphinx/conf.py

openoa/utils/filters.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ def unresponsive_flag(
103103
flag = flag == 0
104104

105105
# Need to flag preceding `threshold` values as well
106-
flag = flag | np.any([flag.shift(-1 - i, axis=0) for i in range(threshold - 1)], axis=0)
106+
flag = flag | np.any(
107+
[flag.shift(-1 - i, axis=0, fill_value=False) for i in range(threshold - 1)], axis=0
108+
)
107109

108110
# Return back a pd.Series if one was provided, else a pd.DataFrame
109111
return flag[col[0]] if to_series else flag

pyproject.toml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ dynamic = ["version"]
88
authors = [{name = "NREL PRUF OA Team", email = "[email protected]"}]
99
readme = {file = "README.md", content-type = "text/markdown"}
1010
description = "A package for collecting and assigning wind turbine metrics"
11-
requires-python = ">=3.8, <3.12"
11+
requires-python = ">=3.10,<3.14"
1212
license = {file = "LICENSE.txt"}
1313
dependencies = [
14-
"scikit-learn>=1.0",
14+
"scikit-learn>=1.0,<1.7",
1515
"requests>=2.21.0",
1616
"eia-python>=1.22",
1717
"pyproj>=3.5",
1818
"shapely>=1.8",
1919
"numpy>=1.24",
20-
"pandas>=2.2",
21-
"pygam>=0.9.0",
22-
"scipy>=1.7,<1.14",
20+
"pandas>=2.2,<3",
21+
"pygam>=0.11.0",
22+
"scipy>=1.7",
2323
"statsmodels>=0.11; python_version<'3.11'",
24-
"statsmodels>=0.13.3; python_version=='3.11'",
24+
"statsmodels>=0.13.3; python_version>='3.11'",
2525
"tqdm>=4.28.1",
2626
"matplotlib>=3.6",
2727
"bokeh>=3.3",
@@ -50,10 +50,11 @@ classifiers = [ # https://pypi.org/classifiers/
5050
"Operating System :: OS Independent",
5151
"Programming Language :: Python",
5252
"Programming Language :: Python :: 3 :: Only",
53-
"Programming Language :: Python :: 3.8",
54-
"Programming Language :: Python :: 3.9",
5553
"Programming Language :: Python :: 3.10",
5654
"Programming Language :: Python :: 3.11",
55+
"Programming Language :: Python :: 3.12",
56+
"Programming Language :: Python :: 3.13",
57+
"Programming Language :: Python :: 3.14",
5758
"Topic :: Scientific/Engineering",
5859
"Topic :: Software Development :: Libraries :: Python Modules",
5960
"Typing :: Typed",
@@ -72,7 +73,7 @@ develop = [
7273
"isort",
7374
"flake8",
7475
"flake8-docstrings",
75-
"pytest>=5.4.2",
76+
"pytest>=9",
7677
"pytest-cov>=2.8.1",
7778
]
7879
docs = [
@@ -140,7 +141,7 @@ filterwarnings = [
140141
[tool.black]
141142
# https://github.com/psf/black
142143
line-length = 100
143-
target-version = ["py38", "py39", "py310"]
144+
target-version = ["py310", "py311", "py312", "py313"]
144145
include = '\.pyi?$'
145146
exclude = '''
146147
# A regex preceded with ^/ will apply only to files and directories
@@ -166,7 +167,7 @@ exclude = '''
166167
[tool.isort]
167168
# https://github.com/PyCQA/isort
168169
profile = "black"
169-
py_version = 39
170+
py_version = 310
170171
src_paths = ["isort", "test"]
171172
line_length = "100"
172173
length_sort = "True"

test/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ def pytest_configure(config):
2525
regression = config.getoption("--regression")
2626

2727
# Provide the appropriate directories
28-
unit_tests = [el for el in (ROOT / "unit").iterdir() if el.suffix == ".py"]
29-
regression_tests = [el for el in (ROOT / "regression").iterdir() if el.suffix == ".py"]
28+
unit_tests = [str(el) for el in (ROOT / "unit").iterdir() if el.suffix == ".py"]
29+
regression_tests = [str(el) for el in (ROOT / "regression").iterdir() if el.suffix == ".py"]
3030

3131
# If both, run them all; if neither skip any modifications; otherwise run just the appropriate subset
3232
if regression and unit:

test/regression/long_term_monte_carlo_aep.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ def test_daily_gam(self):
329329
sim_results = self.analysis.results
330330
self.check_simulation_results_gam_daily(sim_results)
331331

332+
@pytest.mark.xfail(reason="Fails intermittently depending, mostly on MacOS.")
332333
def test_daily_gbm(self):
333334
reset_prng()
334335
# ____________________________________________________________________
@@ -484,7 +485,8 @@ def check_process_reanalysis_data_daily(self, df):
484485
print(computed)
485486

486487
for key in expected.keys():
487-
nptest.assert_array_almost_equal(expected[key], computed[key])
488+
with self.subTest(f"checking {key}"):
489+
nptest.assert_array_almost_equal(expected[key], computed[key])
488490

489491
def check_simulation_results_lin_monthly(self, s):
490492
# Make sure AEP results are consistent to six decimal places

test/regression/yaw_misalignment.py

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def test_yaw_misaliginment_without_UQ(self):
5050
)
5151
self.check_simulation_results_yaw_misalignment_without_UQ()
5252

53+
@pytest.mark.xfail(reason="System-dependendent intermittent failures")
5354
def test_yaw_misaliginment_with_UQ(self):
5455
reset_prng()
5556
# ____________________________________________________________________
@@ -171,21 +172,24 @@ def check_simulation_results_yaw_misalignment_without_UQ(self):
171172

172173
calculated_yaw_mis_results_overall = self.analysis.yaw_misalignment
173174

174-
nptest.assert_array_almost_equal(
175-
expected_yaw_mis_results_overall, calculated_yaw_mis_results_overall, decimal=5
176-
)
175+
with self.subTest("Checking overall results"):
176+
nptest.assert_array_almost_equal(
177+
expected_yaw_mis_results_overall, calculated_yaw_mis_results_overall, decimal=5
178+
)
177179

178180
calculated_yaw_mis_results_ws = self.analysis.yaw_misalignment_ws
179181

180-
nptest.assert_array_almost_equal(
181-
expected_yaw_mis_results_ws, calculated_yaw_mis_results_ws, decimal=5
182-
)
182+
with self.subTest("Checking wind speeds"):
183+
nptest.assert_array_almost_equal(
184+
expected_yaw_mis_results_ws, calculated_yaw_mis_results_ws, decimal=5
185+
)
183186

184187
calculated_mean_vane_results_ws = self.analysis.mean_vane_angle_ws
185188

186-
nptest.assert_array_almost_equal(
187-
expected_mean_vane_results_ws, calculated_mean_vane_results_ws, decimal=5
188-
)
189+
with self.subTest("Checking wind vane"):
190+
nptest.assert_array_almost_equal(
191+
expected_mean_vane_results_ws, calculated_mean_vane_results_ws, decimal=5
192+
)
189193

190194
def check_simulation_results_yaw_misalignment_with_UQ(self):
191195
# Make sure yaw misalignment results are consistent to six decimal places with UQ.
@@ -254,15 +258,21 @@ def check_simulation_results_yaw_misalignment_with_UQ(self):
254258

255259
calculated_yaw_mis_results_avg_overall = self.analysis.yaw_misalignment_avg
256260

257-
nptest.assert_array_almost_equal(
258-
expected_yaw_mis_results_avg_overall, calculated_yaw_mis_results_avg_overall, decimal=5
259-
)
261+
with self.subTest("Checking average of overall results"):
262+
nptest.assert_array_almost_equal(
263+
expected_yaw_mis_results_avg_overall,
264+
calculated_yaw_mis_results_avg_overall,
265+
decimal=5,
266+
)
260267

261268
calculated_yaw_mis_results_std_overall = self.analysis.yaw_misalignment_std
262269

263-
nptest.assert_array_almost_equal(
264-
expected_yaw_mis_results_std_overall, calculated_yaw_mis_results_std_overall, decimal=5
265-
)
270+
with self.subTest("Checking standard deviation wind speeds"):
271+
nptest.assert_array_almost_equal(
272+
expected_yaw_mis_results_std_overall,
273+
calculated_yaw_mis_results_std_overall,
274+
decimal=5,
275+
)
266276

267277
# calculated_yaw_mis_results_95ci_overall = self.analysis.yaw_misalignment_95ci
268278

@@ -274,15 +284,17 @@ def check_simulation_results_yaw_misalignment_with_UQ(self):
274284

275285
calculated_yaw_mis_results_avg_ws = self.analysis.yaw_misalignment_avg_ws
276286

277-
nptest.assert_array_almost_equal(
278-
expected_yaw_mis_results_avg_ws, calculated_yaw_mis_results_avg_ws, decimal=5
279-
)
287+
with self.subTest("Checking average wind speeds"):
288+
nptest.assert_array_almost_equal(
289+
expected_yaw_mis_results_avg_ws, calculated_yaw_mis_results_avg_ws, decimal=5
290+
)
280291

281292
calculated_yaw_mis_results_std_ws = self.analysis.yaw_misalignment_std_ws
282293

283-
nptest.assert_array_almost_equal(
284-
expected_yaw_mis_results_std_ws, calculated_yaw_mis_results_std_ws, decimal=5
285-
)
294+
with self.subTest("Checking standard deviation wind speeds"):
295+
nptest.assert_array_almost_equal(
296+
expected_yaw_mis_results_std_ws, calculated_yaw_mis_results_std_ws, decimal=5
297+
)
286298

287299
# calculated_yaw_mis_results_95ci_ws = self.analysis.yaw_misalignment_95ci_ws
288300

@@ -335,15 +347,21 @@ def check_simulation_results_yaw_misalignment_with_UQ_new_params(self):
335347

336348
calculated_yaw_mis_results_avg_overall = self.analysis.yaw_misalignment_avg
337349

338-
nptest.assert_array_almost_equal(
339-
expected_yaw_mis_results_avg_overall, calculated_yaw_mis_results_avg_overall, decimal=5
340-
)
350+
with self.subTest("Checking average of overall results"):
351+
nptest.assert_array_almost_equal(
352+
expected_yaw_mis_results_avg_overall,
353+
calculated_yaw_mis_results_avg_overall,
354+
decimal=5,
355+
)
341356

342357
calculated_yaw_mis_results_std_overall = self.analysis.yaw_misalignment_std
343358

344-
nptest.assert_array_almost_equal(
345-
expected_yaw_mis_results_std_overall, calculated_yaw_mis_results_std_overall, decimal=5
346-
)
359+
with self.subTest("Checking standard deviation of overall results"):
360+
nptest.assert_array_almost_equal(
361+
expected_yaw_mis_results_std_overall,
362+
calculated_yaw_mis_results_std_overall,
363+
decimal=5,
364+
)
347365

348366
# calculated_yaw_mis_results_95ci_overall = self.analysis.yaw_misalignment_95ci
349367

@@ -355,15 +373,17 @@ def check_simulation_results_yaw_misalignment_with_UQ_new_params(self):
355373

356374
calculated_yaw_mis_results_avg_ws = self.analysis.yaw_misalignment_avg_ws
357375

358-
nptest.assert_array_almost_equal(
359-
expected_yaw_mis_results_avg_ws, calculated_yaw_mis_results_avg_ws, decimal=5
360-
)
376+
with self.subTest("Checking average wind speeds"):
377+
nptest.assert_array_almost_equal(
378+
expected_yaw_mis_results_avg_ws, calculated_yaw_mis_results_avg_ws, decimal=5
379+
)
361380

362381
calculated_yaw_mis_results_std_ws = self.analysis.yaw_misalignment_std_ws
363382

364-
nptest.assert_array_almost_equal(
365-
expected_yaw_mis_results_std_ws, calculated_yaw_mis_results_std_ws, decimal=5
366-
)
383+
with self.subTest("Checking standard deviation of wind speeds"):
384+
nptest.assert_array_almost_equal(
385+
expected_yaw_mis_results_std_ws, calculated_yaw_mis_results_std_ws, decimal=5
386+
)
367387

368388
# calculated_yaw_mis_results_95ci_ws = self.analysis.yaw_misalignment_95ci_ws
369389

test/unit/test_timeseries_toolkit.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ def test_percent_nan(self):
145145
test_dict = {}
146146

147147
# All should be float Series given PlantData requirements
148-
test_dict["a"] = pd.Series([True, 1, 2, 1e5, np.Inf]).astype(float)
149-
test_dict["b"] = pd.Series([False, np.nan, 2, 1e5, np.Inf]).astype(float)
148+
test_dict["a"] = pd.Series([True, 1, 2, 1e5, np.inf]).astype(float)
149+
test_dict["b"] = pd.Series([False, np.nan, 2, 1e5, np.inf]).astype(float)
150150
test_dict["c"] = pd.Series([np.nan, 1, 2, 1e5, np.nan]).astype(float)
151151

152152
nan_values = {"a": 0.0, "b": 0.2, "c": 0.4}

0 commit comments

Comments
 (0)