From 57a05e35e70948ed7967b1e2bb97755814444eaf Mon Sep 17 00:00:00 2001 From: Hugh Runyan Date: Tue, 8 Sep 2026 14:47:36 -0700 Subject: [PATCH 1/2] pytest runs in CI on every push and pull request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tests/ directory has had 8 test files and no workflow that runs them. Nothing gated them, so model unit tests got written in WasteMAP's backend/tests/fast instead — the only repo of the pair with test CI — which forced WasteMAP's suite to reach into private SWEET_python helpers (e.g. SWEET_python.advanced_dst_city._prevent_food_waste, flagged by Copilot on RMI/WasteMAP#772). Tests of this package's internals can now live in the repo that owns them. All 133 existing tests pass on Python 3.12 with the pinned lockfile. None are stale and none need a database, network access or environment variables: the suite passes in a few seconds with every socket call blocked. So nothing is disabled or excluded here. The `integration` marker is registered anyway, and the job runs `-m "not integration"`, so the mechanism is live the moment a test does need a database — mirroring how WasteMAP splits backend/tests/fast from backend/tests/integration. --strict-markers keeps a mistyped marker from silently landing in the fast job. This complements WasteMAP's CI rather than replacing it. WasteMAP installs a SWEET_python branch with the same name as the WasteMAP branch under test, so a model change here and its consumer over there are already exercised as a pair. What that pairing never did was run this repo's own tests. Co-Authored-By: Claude Opus 5 --- .github/workflows/tests.yml | 64 +++++++++++++++++++++++++++++++++++++ README.md | 28 ++++++++++++++++ pytest.ini | 7 ++++ 3 files changed, 99 insertions(+) create mode 100644 .github/workflows/tests.yml create mode 100644 pytest.ini diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..3d5f120 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,64 @@ +name: Tests + +# Both events, deliberately: a branch pushed here often has no pull request yet, +# because the usual workflow is to push a SWEET_python branch alongside a +# same-named WasteMAP branch (WasteMAP's CI installs the matching branch) and open +# the PRs later. `pull_request` on top of that covers forks. The cost is that a +# branch with an open PR in this repo runs the suite twice for the same commit, +# which is cheap here — the whole suite is a few seconds. +on: [push, pull_request] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + fast: + name: Fast tests + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + # 3.12 is what WasteMAP's CI and deploy images run, which is where this + # package actually executes. The code itself needs 3.10+ (PEP 604 `X | Y` + # annotations), so it is not a floor imposed by this workflow. + python-version: "3.12" + cache: pip + cache-dependency-path: requirements.txt + + - name: Install libpq headers + # psycopg2 (not psycopg2-binary) publishes no manylinux wheel, so pip + # builds it from source and needs pg_config, which libpq-dev provides. + run: | + sudo apt-get update + sudo apt-get install -y libpq-dev + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + # The pinned lockfile — reproducible installs are what requirements.txt + # exists for; requirements.in holds the abstract deps consumers get. + pip install -r requirements.txt + # Bounded rather than pinned: minor/patch pytest releases are welcome, + # a major one should not break CI on a day nobody touched the model. + pip install "pytest>=8,<10" + # Editable, --no-deps: makes `import SWEET_python` resolve to this + # checkout without re-resolving what requirements.txt just pinned, and + # exercises setup.py's packaging on the way. + pip install --no-deps -e . + + - name: Run fast tests + # Tests needing a live database or the network are marked `integration` + # and excluded here, mirroring how WasteMAP splits backend/tests/fast from + # backend/tests/integration. This repo has none yet: the whole suite is + # hermetic. When the first one lands, give it a job of its own instead of + # attaching a database to this one. + run: pytest -m "not integration" --verbose diff --git a/README.md b/README.md index b8aee8d..0155f1c 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,34 @@ After following these steps, SWEET_python can be imported: 3) cd into the SWEET_python directory, then write `pip install -e .` to install in editable mode, which allows editing the code. Updates to the code in the repo should be automatically reflected in the installed package. If they are not, reinstall it. +# Tests + +The test suite lives in `tests/` and runs with pytest: + +``` +pip install -r requirements.txt "pytest>=8,<10" +pip install -e . +pytest +``` + +Every test in the suite is hermetic — no database, no network, no environment +variables — and the whole thing takes a few seconds. + +CI (`.github/workflows/tests.yml`) runs `pytest -m "not integration"` on Python +3.12 for every push and pull request. If you add a test that does need a live +database or network access, mark it `@pytest.mark.integration` so it stays out of +that job, following the same fast/integration split as WasteMAP's +`backend/tests/fast` and `backend/tests/integration`. There are no such tests +today; the first one should get a CI job of its own rather than a database being +bolted onto the fast job. + +This is complementary to WasteMAP's CI, not a replacement for it: WasteMAP +installs a SWEET_python branch with the same name as the WasteMAP branch under +test, so a model change here and its WasteMAP consumer are already exercised as a +pair over there. What that pairing does *not* do is run this repo's own tests — +that is the gap this workflow fills. Tests of this package's internals belong +here, in the repo that owns them. + # Usage You will have to write your own code to import your data files. Examples are in SWEET_python/sweet_tools_obj.py—the load_from_database method illustrates the many different parameters that can be specified. For many parameters, default values are available. These are stored in the defaults_2019.py file, and the sweet_tools_obj.py file contains many examples of accessing them. The code for the model itself is in model.py. Models are generally run as part of a Landfill instance—the Landfill class is defined at the bottom of sweet_tools_obj.py diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..b2ffdcd --- /dev/null +++ b/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +testpaths = tests +# --strict-markers so a mistyped marker (@pytest.mark.integraton) is an error +# rather than a test that silently keeps running in the fast job. +addopts = --strict-markers +markers = + integration: needs a live database or network access; excluded from the fast CI job. Run these with `pytest -m integration`. From 203fdfc163b278e89eee7d8975d9bbf63d8f3eda Mon Sep 17 00:00:00 2001 From: Hugh Runyan Date: Tue, 8 Sep 2026 14:49:24 -0700 Subject: [PATCH 2/2] Current action majors, so the workflow lands without a deprecation warning checkout@v4 and setup-python@v5 both target Node 20, which the runners now force onto Node 24 with a deprecation annotation. v7 of each is the Node 24 build. The only other breaking change in between is checkout's safer `pull_request_target` default, and this workflow uses `pull_request`. Co-Authored-By: Claude Opus 5 --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3d5f120..9a0674c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,10 +22,10 @@ jobs: timeout-minutes: 15 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v7 with: # 3.12 is what WasteMAP's CI and deploy images run, which is where this # package actually executes. The code itself needs 3.10+ (PEP 604 `X | Y`