Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/actions/setup-pybnf/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Set up pybnf (bngsim-less)
description: >-
Install BioNetGen (BNG2.pl) plus pybnf and its public runtime/test
dependencies into a uv venv, deliberately omitting the private, macOS-only
bngsim wheel. Tests run under PYBNF_NO_BNGSIM=1 so bngsim-marked tests skip
(see tests/conftest.py). BNG2.pl is still required: Configuration validation
execs `BNG2.pl -v` for any BNGLModel regardless of bngsim, and the analytical
tests aside, most of the suite builds such configs.

inputs:
python-version:
description: Python version for the venv (e.g. "3.10", "3.12").
required: true

runs:
using: composite
steps:
# Provision the interpreter with setup-python rather than uv's managed
# (python-build-standalone) builds: libroadrunner is a C++ extension that
# dlopen's libpython, and uv's standalone Python 3.10 does not expose
# libpython3.10.so.1.0 on the loader path (3.12's does). setup-python's
# Pythons are built --enable-shared with libpython discoverable, so
# roadrunner imports on every matrix leg.
- uses: actions/setup-python@v5
id: python
with:
python-version: ${{ inputs.python-version }}

- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
# No uv.lock in this repo; key the cache on pyproject.toml so it can
# invalidate when deps change.
cache-dependency-glob: pyproject.toml

- name: Install BioNetGen 2.9.3
shell: bash
run: |
# BioNetGen is free/open-source and provides BNG2.pl (Perl is
# preinstalled on ubuntu runners). It is NOT vendored into the repo or
# the pybnf wheel -- it is fetched onto the ephemeral runner each run,
# mirroring the developer prerequisite (BNGPATH on a local machine).
curl -fsSL \
https://github.com/RuleWorld/bionetgen/releases/download/BioNetGen-2.9.3/BioNetGen-2.9.3-linux.tar.gz \
-o "$RUNNER_TEMP/bionetgen.tar.gz"
tar -xzf "$RUNNER_TEMP/bionetgen.tar.gz" -C "$RUNNER_TEMP"
echo "BNGPATH=$RUNNER_TEMP/BioNetGen-2.9.3" >> "$GITHUB_ENV"

- name: Create venv and install pybnf without bngsim
shell: bash
run: |
# Build the venv from the setup-python interpreter (see note above), not
# a uv-managed one.
uv venv --python "${{ steps.python.outputs.python-path }}"
# Mirror pyproject.toml's runtime deps MINUS bngsim (private, mac-only
# wheel, not on PyPI), plus the test stack and pytest-xdist. Keep these
# version bounds in sync with pyproject.toml; bngsim is the only
# intentional omission.
uv pip install \
'dask>=2021.5.0,<2023.0' \
'distributed>=2021.6.2,<2023.0' \
'libroadrunner>=1.6.0,<3' \
'msgpack>=0.6.2,<2' \
'numpy>=1.24,<3' \
'paramiko>=2.7,<5' \
'pyparsing>=2.4,<4' \
'scipy>=1.10,<2' \
'tornado>=6.1,<7' \
'pytest>=7,<10' \
'hypothesis>=6,<7' \
'pytest-xdist' \
'tomli>=2,<3; python_version < "3.11"'
# Install pybnf itself without re-resolving deps (which would pull
# bngsim and fail).
uv pip install --no-deps .
30 changes: 30 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: integration

# Manual only. The slow tier is the 4 statistical-recovery tests against
# analytical targets (AnalyticalModel) -- bngsim-free and BNG2.pl-free, ~8 min.
#
# NOTE: the bngsim *simulation* suites (true NFsim/RuleMonkey/SBML runs) are
# deliberately NOT in hosted CI -- they need the private, macOS-only bngsim
# wheel. They remain covered by the local pre-push hook (.pre-commit-config.yaml)
# on a dev machine until bngsim ships Linux wheels.
#
# A nightly `schedule:` cron could be added here, but is intentionally omitted
# pending a maintainer decision.
on:
workflow_dispatch:

jobs:
slow:
runs-on: ubuntu-latest
name: slow recovery tests
steps:
- uses: actions/checkout@v4

- uses: ./.github/actions/setup-pybnf
with:
python-version: '3.12'

- name: Run slow analytical recovery tests
env:
PYBNF_NO_BNGSIM: '1'
run: uv run --no-sync pytest -m slow -n auto
27 changes: 27 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: lint

on:
push:
branches: [master]
pull_request:

jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5
with:
enable-cache: true

- name: ruff check
# Pin ruff so the rule set is reproducible: the [tool.ruff] config in
# pyproject.toml pins which rules run, but a newer ruff could add rules
# to the default selection and turn the gate red unexpectedly.
run: uvx ruff@0.15.14 check .

# NOTE: `ruff format --check` is intentionally NOT enforced in v1. The
# codebase predates ruff formatting; a repo-wide reformat is a large,
# behavior-adjacent diff best done in its own dedicated PR. Add a format
# check here once that lands.
35 changes: 35 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: tests

on:
push:
branches: [master]
pull_request:

jobs:
pytest:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Min and max of the supported range (requires-python >= 3.10;
# classifiers list through 3.12).
python-version: ['3.10', '3.12']
name: pytest (py${{ matrix.python-version }})
steps:
- uses: actions/checkout@v4

- uses: ./.github/actions/setup-pybnf
with:
python-version: ${{ matrix.python-version }}

- name: Run unit tests (bngsim-less, parallel)
env:
# bngsim is a private mac-only wheel; with it absent, conftest.py
# auto-skips bngsim/nfsim/sbml/etc.-marked tests. The remaining suite
# runs against the bngsim-less code paths (and BNG2.pl from the
# composite action). -n auto parallelizes across the runner's cores.
PYBNF_NO_BNGSIM: '1'
# --no-sync: do NOT let `uv run` re-resolve the project env from
# pyproject.toml (that would pull the private bngsim and fail). The
# composite action already populated .venv.
run: uv run --no-sync pytest -m "not slow" -n auto
2 changes: 1 addition & 1 deletion examples/sampler_benchmarking/run_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def main():
print(f"{submitted} jobs completed, {failed} failed.")
else:
print(f"{submitted} jobs submitted, {failed} failed.")
print(f"Monitor with: squeue -u $USER")
print("Monitor with: squeue -u $USER")


if __name__ == "__main__":
Expand Down
4 changes: 1 addition & 3 deletions pybnf/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from subprocess import STDOUT
from .pset import run_subprocess

from numpy import mean

from .bngsim_model import (
BngsimModel,
Expand All @@ -24,9 +23,8 @@
from .data import Data
from .pset import PSet
from .pset import Trajectory
from .pset import TimeCourse
from .pset import BNGLModel
from .pset import NetModel, BNGLModel, SbmlModelNoTimeout
from .pset import NetModel
from .pset import OutOfBoundsException
from .pset import FailedSimulationError
from .printing import print0, print1, print2, PybnfError
Expand Down
4 changes: 0 additions & 4 deletions pybnf/bngsim_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@
from ._bngsim_caps import (
BNGSIM_AVAILABLE,
BNGSIM_ERROR,
BNGSIM_FEATURES,
BNGSIM_HAS_NFSIM,
BNGSIM_HAS_RULEMONKEY,
BNGSIM_MISSING,
BNGSIM_VERSION,
bngsim,
feature_missing_reason,
)
from .data import Data
from .pset import FreeParameter, Model, NetModel, PSet, _stage_and_rewrite_tfun_files
Expand Down Expand Up @@ -501,7 +498,6 @@ def _create_nf_session(session_backend, xml_path, molecule_limit=None):
if molecule_limit is None:
return session_cls(xml_path)
return session_cls(xml_path, molecule_limit=molecule_limit)
return session


def _destroy_nf_session(session):
Expand Down
2 changes: 0 additions & 2 deletions pybnf/bngsim_sbml_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@


from ._bngsim_caps import (
BNGSIM_AVAILABLE,
BNGSIM_HAS_LIBSBML as LIBSBML_AVAILABLE,
BNGSIM_HAS_SBML,
BNGSIM_SBML_ERROR,
bngsim,
Expand Down
4 changes: 1 addition & 3 deletions pybnf/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@


from .data import Data, DuplicateColumnError
from .objective import ChiSquareObjective, ChiSquareObjective_Dynamic, NegBinLikelihood_Dynamic, NegBinLikelihood, SumOfSquaresObjective, NormSumOfSquaresObjective, \
from .objective import ChiSquareObjective, ChiSquareObjective_Dynamic, NegBinLikelihood_Dynamic, SumOfSquaresObjective, NormSumOfSquaresObjective, \
AveNormSumOfSquaresObjective, SumOfDiffsObjective, NegBinLikelihood, KLLikelihood, DirectPassObjective

from .pset import BNGLModel, ModelError, SbmlModel, SbmlModelNoTimeout, FreeParameter, TimeCourse, ParamScan, \
Mutation, MutationSet
from .bngsim_sbml_model import (
BNGSIM_HAS_SBML,
BNGSIM_SBML_ERROR,
BngsimSbmlModel,
BngsimSbmlModelNoTimeout,
)
from .bngsim_antimony_model import (
BNGSIM_HAS_ANTIMONY,
BNGSIM_ANTIMONY_ERROR,
BngsimAntimonyModel,
BngsimAntimonyModelNoTimeout,
)
from .printing import verbosity, print1, PybnfError
Expand Down
3 changes: 1 addition & 2 deletions pybnf/pset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
import re
import copy
import signal
from subprocess import run, Popen, STDOUT, PIPE, DEVNULL, CalledProcessError, TimeoutExpired
from subprocess import Popen, STDOUT, PIPE, CalledProcessError, TimeoutExpired
from .data import Data
import heapq
import traceback
import roadrunner as rr
import pickle
from os.path import join
import os
import shutil
import tempfile
Expand Down
29 changes: 29 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,35 @@ packages = ["pybnf"]
[tool.setuptools.dynamic]
version = { attr = "pybnf.__version__" }

[tool.ruff]
target-version = "py310"
# Pins ruff's default rule set (pycodestyle E4/E7/E9 + pyflakes F) so local runs
# and CI agree. Line length (E501) and the broader style/lint families are
# intentionally left off for v1; revisit once the codebase is reformatted.

[tool.ruff.lint]
# Pre-existing legacy style that PyBNF does not enforce. Each is either purely
# cosmetic or a behavioral change to "fix", so it is out of scope for the lint
# gate (which must stay mechanical). Items tied to dev/PUNCHLIST.md are tracked
# and fixed there, not here.
ignore = [
"E402", # module-import-not-at-top: intentional (lazy backend guards, test bootstrap)
"E712", # ==True/False: legacy; rewriting can change truthiness semantics (e.g. numpy bools)
"E721", # type(x) == T comparisons: legacy, semantically fine in context
"E722", # bare except: tracked as ROB-4 in dev/PUNCHLIST.md (behavioral fix)
"E741", # ambiguous variable names (l/I/O): legacy
"F841", # unused locals: several are CQ-5 dead code (tracked); common bind-then-assert in tests
]

[tool.ruff.lint.per-file-ignores]
"tests/**" = [
"E702", # multiple-statements-on-one-line (semicolons): established test-file style
"F402", # import shadowed by loop variable
]
# context.py is a re-export shim: test modules do `from .context import data`,
# so its imports are "unused" only within the file itself.
"tests/context.py" = ["F401"]

[tool.pytest.ini_options]
minversion = "7.0"
testpaths = ["tests"]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_bayes_mcmc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .context import data, algorithms, pset, objective, config
from .context import data, algorithms, pset, config
import os
import shutil
import numpy as np
Expand Down
Loading
Loading