Add GitHub Actions CI (lint + tests + manual integration)#395
Merged
Conversation
tests/test_bngsim_bridge.py had 25 functions (29 parametrized cases) that call into bngsim (classify_actions_for_bngsim, _normalize_nf_action_method, _initialize_models with BNGSIM_AVAILABLE patched, etc.). These were unmarked, so under PYBNF_NO_BNGSIM=1 they failed instead of skipping via conftest's dependency-aware collection hook. Add @pytest.mark.bngsim to those functions. For the parametrized test_classify_action_method_backend_maps_methods, mark only the nf/nf_reject/ nfsim params (which route through bngsim.normalize_method); the ode/ssa/psa/ pla/unknown cases short-circuit before the BNGSIM_AVAILABLE check and still run without bngsim, so they are left unmarked. Verified: PYBNF_NO_BNGSIM=1 pytest -m 'not slow' has 0 failures (these skip), and the same tests still pass with bngsim present (no over-marking).
teardown_class removed pybnf_output/sim_* with bare rmtree() on relative paths. Those dirs only exist if a test in the class created them in the worker's cwd, so teardown raised FileNotFoundError when a dir was absent -- flaky single-core (order-dependent) and unreliable under pytest-xdist's -n auto, where the worker running this class need not have produced every dir. Use rmtree(d, ignore_errors=True) so cleanup is best-effort.
Pin ruff's default rule set (pycodestyle E4/E7/E9 + pyflakes F) in [tool.ruff] so local and CI agree, then get to green: - Auto-fix the safe findings repo-wide (ruff check --fix): unused imports (F401), duplicate imports (F811: BNGLModel in algorithms.py, NegBinLikelihood in config.py), one-line multi-import (E401), and an f-string without placeholders (F541). - Remove one line of unreachable dead code: 'return session' after two unconditional returns in bngsim_model._create_nf_session (was the lone F821). - Ignore pre-existing legacy style that is cosmetic or behavioral-to-fix: E402, E712, E721, E722 (ROB-4), E741, F841 (several are CQ-5 dead code). - per-file-ignores: tests E702 (semicolons) / F402; and F401 on tests/context.py, which is a re-export shim (test modules do 'from .context import data'). Verified: 'uvx ruff check .' exits 0; full 'pytest -m "not slow"' with bngsim still passes (811 passed), so the autofixes broke nothing.
Three workflows plus a shared composite action (.github/actions/setup-pybnf) that installs BioNetGen 2.9.3 (BNG2.pl) and pybnf's public deps into a uv venv, omitting the private macOS-only bngsim wheel. Tests run under PYBNF_NO_BNGSIM=1 so bngsim-marked tests skip via conftest. - lint.yml (push to master + PRs): uvx ruff@0.15.14 check . (pinned for a reproducible rule set). ruff format is deferred to a future dedicated PR. - tests.yml (push to master + PRs): matrix py3.10/py3.12 on ubuntu-latest; PYBNF_NO_BNGSIM=1 pytest -m 'not slow' -n auto (uv run --no-sync so uv does not re-resolve bngsim). ~3.5 min with xdist. - integration.yml (workflow_dispatch): pytest -m slow -n auto, the 4 analytical recovery tests. A nightly cron is left out pending a maintainer decision. BNG2.pl is required even bngsim-less: Configuration validation execs 'BNG2.pl -v' for any BNGLModel regardless of bngsim. BioNetGen is fetched onto the ephemeral runner (not vendored, not a pybnf dependency). The bngsim simulation suites stay on the local pre-push hook until bngsim ships Linux wheels. Validated locally by replicating the exact install in a fresh bngsim-less venv: ruff check green; PYBNF_NO_BNGSIM=1 pytest -m 'not slow' -n auto = 747 passed, 64 skipped, 0 failed.
…n py3.10 The first CI run passed on py3.12 (747 passed) but failed collection on py3.10 with 'ImportError: libpython3.10.so.1.0: cannot open shared object file'. libroadrunner is a C++ extension that dlopen's libpython, and uv's managed (python-build-standalone) Python 3.10 does not expose libpython3.10.so.1.0 on the loader path -- though its 3.12 build does, which is why only the 3.10 leg broke. Provision the interpreter with actions/setup-python (built --enable-shared, libpython discoverable) and point 'uv venv --python' at its python-path, so roadrunner imports on every matrix leg. Also key the setup-uv cache on pyproject.toml (no uv.lock exists) to silence the never-invalidates warning.
Collaborator
Author
CI is green on real GitHub infra ✅Validated this branch end-to-end on hosted runners (not just locally):
The first run exposed one Linux-only issue the local macOS replica couldn't: uv's standalone Python 3.10 doesn't expose Heads-up (non-blocking): runner annotations warn that |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds remote CI to PyBNF. Until now the only automated check was a local pre-push hook scoped to the bngsim test files, leaving the ~750 pure-Python tests uncovered on push/PR.
Three workflows + a shared composite action:
lint.yml(push tomaster+ all PRs):uvx ruff@0.15.14 check .(pinned for a reproducible rule set;[tool.ruff]inpyproject.tomlpins the rules).tests.yml(push tomaster+ all PRs): matrix py3.10 / py3.12 onubuntu-latest,PYBNF_NO_BNGSIM=1 pytest -m "not slow" -n auto. ~3.5 min with xdist.integration.yml(workflow_dispatch):pytest -m slow -n auto— the 4 analytical recovery tests..github/actions/setup-pybnf: installs BioNetGen 2.9.3 + pybnf's public deps into a uv venv, omitting the private bngsim wheel.Key finding: BNG2.pl is required even bngsim-less
The original plan assumed ~750 "pure-Python" tests need nothing but a bngsim-less install. That's not true.
Configuration._load_simulators(config.py:611-641) execsBNG2.pl -vfor anyBNGLModelregardless of bngsim. On a clean runner (noBNGPATH/BNG2.pl) the bngsim-less suite is 98 failed + 30 errors, not 29 — the affected tests are the core optimizer/sampler suites.Fix: the composite action fetches the free, open-source BioNetGen 2.9.3 Linux release onto the ephemeral runner and sets
BNGPATH. It is not vendored into the repo and not added as a pybnf dependency — it mirrors the existing developer prerequisite.import roadrunneris also top-level inconfig.py/pset.py, solibroadrunneris installed too.The bngsim simulation suites (true NFsim/RuleMonkey/SBML runs) stay out of hosted CI — they need the private, macOS-only bngsim wheel — and remain covered by the local pre-push hook until bngsim ships Linux wheels.
Commits (kept separate per concern)
test_bngsim_bridge.pygot@pytest.mark.bngsimso they skip without bngsim (they failed before). Param-level marks onmaps_methodsavoid over-skipping its net/pla/unknown cases. Real correctness fix to the suite.TestJobteardown xdist-safe —teardown_classdidrmtree('pybnf_output')on relative paths; flaky single-core (order-dependent) and unreliable under-n auto. Nowignore_errors=True.E,F; autofix safe findings (unused/duplicate imports, an f-string, one-line imports); remove one line of unreachable dead code (the lone F821); ignore legacy style (E402/E712/E721/E722/E741/F841) and per-file-ignore tests' semicolons + thecontext.pyre-export shim.Validation (local, no
act)uvx ruff@0.15.14 check .→ exit 0.pytest -m "not slow"with bngsim → 811 passed (no over-marking, ruff autofixes broke nothing).PYBNF_NO_BNGSIM=1 pytest -m "not slow" -n auto→ 747 passed, 64 skipped, 0 failed in 3:21.Notes
Any). Worth revisiting once annotations exist.ruff formatdeferred: a repo-wide reformat is a large, behavior-adjacent diff for its own PR.schedule:cron forintegration.ymlis left out pending your decision.