From 121a4b25272b076473deb2669c223984ab8adc69 Mon Sep 17 00:00:00 2001 From: energyscholar Date: Thu, 5 Mar 2026 19:35:02 -0800 Subject: [PATCH 1/2] Add Python 3.12 support, update CI and dependencies - Add Python 3.12 to CI matrix with TF gate (no 3.12 wheels for TF <2.16) - Drop Python 3.8 (EOL Oct 2024), update Actions to v4/v5 - Update dependency floors for 3.12 wheel availability (numpy>=1.26, arch>=6.2) - Separate TF-dependent tests with pytest marker - Correct TF version constraint (<=2.16 -> <2.16, excludes Keras 3) Prepared with assistance from Claude Opus 4.6. --- .github/workflows/tests.yml | 12 +++++++----- pyproject.toml | 12 ++++++++---- tests/test_ewstools.py | 9 +++++---- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d68787c..318258d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,12 +14,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10"] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -27,8 +27,10 @@ jobs: python -m pip install --upgrade pip pip install flake8 pytest pytest-cov pip --default-timeout=100 install -e . - pip --default-timeout=100 install "tensorflow>=2.10,<2.16" - # pip --default-timeout=100 install "tensorflow>=2.13" + - name: Install TensorFlow + # TF <2.16 has no 3.12 wheels (3.12 support requires TF 2.16+/Keras 3) + if: matrix.python-version != '3.12' + run: pip install "tensorflow>=2.10,<2.16" - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names diff --git a/pyproject.toml b/pyproject.toml index 818ecb1..42b88f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,13 +8,13 @@ version = "2.1.2" description = "A Python package for early warning signals (EWS) of bifurcations in time series data." authors = [{ name = "Thomas M Bury", email = "tombury182@gmail.com" }] readme = "README.md" -requires-python = ">=3.8,<3.12" # Adjust based on your supported Python version +requires-python = ">=3.9" dependencies = [ "pandas>=0.23.0", - "numpy>=1.14.0,<1.25.0", + "numpy>=1.26.0,<2.0", # 1.26 is oldest with 3.12 wheels; <2.0 avoids breaking changes "plotly>=2.3.0", "lmfit>=0.9.0", - "arch>=4.4", + "arch>=6.2", # 6.2 is oldest with compiled 3.12 wheels "statsmodels>=0.9.0", "scipy>=1.0.1", "deprecation>=2.0", @@ -31,9 +31,13 @@ classifiers = [ [project.optional-dependencies] tf = [ - "tensorflow>=2.10,<=2.16 ; sys_platform != 'win32'", + # <=2.16 includes 2.16.0 (Keras 3 breaking change); <2.16 excludes it + "tensorflow>=2.10,<2.16 ; sys_platform != 'win32'", ] +[tool.pytest.ini_options] +markers = ["tensorflow: tests requiring TensorFlow (deselect with '-m \"not tensorflow\"')"] + [tool.setuptools.packages] find = {} diff --git a/tests/test_ewstools.py b/tests/test_ewstools.py index a67ddf2..288f47f 100644 --- a/tests/test_ewstools.py +++ b/tests/test_ewstools.py @@ -8,10 +8,6 @@ import pandas as pd import plotly -import tensorflow as tf -from tensorflow.keras.models import load_model -from packaging import version - # Import ewstools import ewstools from ewstools import core @@ -221,11 +217,16 @@ def test_TimeSeries_ews(): assert type(fig) == plotly.graph_objs._figure.Figure +@pytest.mark.tensorflow def test_TimeSeries_dl_preds(): """ Test the TimeSeries methods that involve computing DL predictions """ + # TF imports moved inside test so rest of suite runs without TF installed + tf = pytest.importorskip("tensorflow") + from tensorflow.keras.models import load_model + from packaging import version # Simulate a time series tVals = np.arange(0, 10, 0.1) From 4e671ae4170208d815be21a6e4b0979b18c69e2b Mon Sep 17 00:00:00 2001 From: energyscholar Date: Thu, 5 Mar 2026 19:35:14 -0800 Subject: [PATCH 2/2] Fix scipy 1.16.0 compatibility in spectral EWS scipy 1.16.0 rewrote signal.welch internals to use ShortTimeFFT, which performs tuple indexing (x[..., i0:i1]) that fails on pandas Series. Convert input to ndarray before passing to signal.welch. np.asarray is idempotent for ndarray input and safe across all scipy versions. Prepared with assistance from Claude Opus 4.6. --- ewstools/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ewstools/helpers.py b/ewstools/helpers.py index 34e1fbe..9fded5d 100644 --- a/ewstools/helpers.py +++ b/ewstools/helpers.py @@ -106,7 +106,7 @@ def pspec_welch(yVals, ham_offset_points = int(ham_offset*ham_length) ## Compute the periodogram using Welch's method (scipy.signal function) - pspec_raw = signal.welch(yVals, + pspec_raw = signal.welch(np.asarray(yVals), fs, nperseg=ham_length, noverlap=ham_offset_points,