From 253aa823429a5d5acbbb6b76299ecc38f692bda6 Mon Sep 17 00:00:00 2001 From: Remis Date: Tue, 1 Sep 2026 18:22:47 +0100 Subject: [PATCH] Add CI, and declare scipy EKDIST was the last repository in the DCPROGS stack without CI. That mattered more once it stopped being self-contained: it now takes its log-binning from dcio, so a change over there can break it here and nothing would say so. dcio is not on PyPI, so every job installs it from git before installing EKDIST -- `pip install -e .` would otherwise fail on an unresolvable requirement. That step is the first thing to revisit when dcio is published. scipy was imported by ekplot, errors and exponentials and named in install_requires by none of them. An editable install into an environment that already has scipy cannot reveal that; only a clean one can, which is what the clean-install job is for. Declared it. Also declares python_requires='>=3.11'. setup.py named no floor, but dcio's requires-python sets one in practice, and an inherited constraint is better written down than discovered. Matrix covers 3.11-3.13 on Linux plus macOS and Windows. MPLBACKEND=Agg is set explicitly rather than left to backend autoselection, since ekplot imports matplotlib.pyplot at module level and the runners have no display. Co-Authored-By: Claude Opus 5 --- .github/workflows/ci.yml | 116 +++++++++++++++++++++++++++++++++++++++ setup.py | 2 + 2 files changed, 118 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9802fb5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,116 @@ +# EKDIST was the last repository in the DCPROGS stack without CI, which +# mattered more once it stopped being self-contained: it now takes its +# log-binning from dcio, so a change over there can break it here. +# +# dcio is not on PyPI, so every job installs it from git before installing +# EKDIST. That step is the first thing to revisit when dcio is published. + +name: CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + # ekplot imports matplotlib.pyplot at module level. Runners have no display; + # be explicit rather than relying on the backend autoselection. + MPLBACKEND: Agg + +jobs: + test: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + + strategy: + fail-fast: false + matrix: + include: + # The floor is dcio's requires-python (>=3.11), not EKDIST's own -- + # setup.py declares none, and the dependency sets it in practice. + - { name: linux-py311, os: ubuntu-24.04, python: '3.11' } + - { name: linux-py312, os: ubuntu-24.04, python: '3.12' } + - { name: linux-py313, os: ubuntu-24.04, python: '3.13' } + - { name: macos, os: macos-14, python: '3.13' } + - { name: windows, os: windows-2022, python: '3.12' } + + steps: + - uses: actions/checkout@v7 + + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python }} + + # dcio must go in first: it is named in install_requires but cannot be + # resolved from PyPI, so `pip install -e .` would fail without it. + - name: Install dcio from git + shell: bash + run: | + python -m pip install --upgrade pip + pip install git+https://github.com/DCPROGS/dcio@master + + - name: Install + shell: bash + run: | + pip install -e . + pip install pytest + pip list + + # The record files are read by relative path from the repository root + # ("./tests/AChsim.scn"), so the suite only passes when run from there. + - name: Test data present + shell: bash + run: | + for f in tests/AChsim.scn tests/intervals.txt; do + test -f "$f" || { echo "missing test data: $f"; exit 1; } + done + echo "test data present" + + - name: Tests + shell: bash + run: pytest tests/ + + # setup.py has to name everything the package imports. scipy did not appear + # in install_requires despite ekplot, errors and exponentials all importing + # it, which no editable install from a populated environment can reveal -- + # only a clean one can. This job is that clean environment. + clean-install: + name: clean-install + runs-on: ubuntu-24.04 + timeout-minutes: 15 + + steps: + - uses: actions/checkout@v7 + + - uses: actions/setup-python@v6 + with: + python-version: '3.12' + + - name: Install into an empty virtualenv + run: | + python -m venv /tmp/clean + /tmp/clean/bin/pip install --upgrade pip + /tmp/clean/bin/pip install git+https://github.com/DCPROGS/dcio@master + /tmp/clean/bin/pip install . + /tmp/clean/bin/pip list + + - name: Import every module with nothing else installed + env: + MPLBACKEND: Agg + run: | + cd /tmp + /tmp/clean/bin/python - <<'PY' + from ekdist import ekplot, ekrecord, ekscn, eklib, exponentials, errors + from ekdist.ekplot import prepare_xlog_hist + print("all ekdist modules import from a clean install") + PY diff --git a/setup.py b/setup.py index cad02c0..4424470 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,10 @@ author_email='', license='MIT', packages=['ekdist'], + python_requires='>=3.11', # dcio's floor, inherited install_requires=[ 'numpy', + 'scipy', 'matplotlib', # The shared record layer. Not on PyPI yet, so a source install # needs it first: