Skip to content

Running all tests

./test.sh runs the complete suite, with a memory-aware number of pytest workers. Some integration tests require separately installed predictors and models. Use the release gate to ensure every collected test actually passes:

TEST_SH_MAX=2 ./test.sh --require-all -ra

--require-all fails on skips, expected failures, and unexpected passes, including module-level skips and parallel workers. Ordinary development runs can still use availability-based skips when optional predictors are absent. ./test.sh prints skip and expected-failure reasons by default. Installed legacy NetMHC executables that fail their startup probes produce test setup errors, including the diagnostic output, even without --require-all. Their probes run only when a test that needs the runtime is selected. Prediction tests do not call IEDB or other public prediction services. Internet access is needed only when installing model assets and runtimes.

Recorded vaccine fixtures

The osteosarc fixtures contain source-linked vaccine sequences and native output captures from seven real predictors. Their parser and wrapper regression tests run offline in all public Python CI jobs, without downloading models or installing osteosarc:

python -m pytest tests/test_osteosarc_fixtures.py --require-all

The fixture README documents source provenance, experimental-label caveats, predictor versions, and the explicit regeneration commands.

Real-model backend tests

“Optional” describes the extra software or model assets needed for a local installation. It does not mean the backend lacks tests or is allowed to disappear from CI. The public Python jobs run offline wrapper and fixture tests; dedicated CI jobs provision Pepsickle, SMM/SMM-PMBEC, DeepTAP, and the Keras-backed DeepImmuno/TLimmuno2/NetCleave models, then run real inference with --require-all. That flag makes a skipped model test fail its job. Different jobs are necessary because some upstream weights have separate licenses and older runtime requirements, and TensorFlow is deliberately kept out of the main interpreter.

“Setup group” is simply the name passed to scripts/setup_test_backends.py to provision one bundle. For example, gfeller provisions the Gfeller lab's MixMHCpred, MixMHC2pred and PRIME implementations; it is not a scientific category of predictor.

./test.sh sources env/test-backends/activate.sh when it exists, so the isolated runtimes set up by scripts/setup_test_backends.py are found automatically. For direct pytest commands, source it yourself. Point MHCTOOLS_TEST_ENV at a different activate.sh, or set MHCTOOLS_TEST_ENV=/dev/null to run without this configuration. Installing the backends is covered in installing optional backends; this page is about running the tests that exercise them.

Each backend has focused tests. They probe the runtime and skip when it is missing, so a skip means an unprovisioned runtime, not a broken wrapper. A *_PYTHON path that does not exist raises instead of skipping, because that is a misconfiguration.

Backend Setup group Command
MixMHCpred, PRIME gfeller pytest tests/test_mixmhcpred_runtime_integration.py tests/test_mixmhcpred.py tests/test_prime.py --require-all
PhageScout full DESeq2 tables phagescout pytest tests/test_phagescout_full_profiles.py --require-all
PeptiVerse half-life and CPP classification, PlifePred2 half-life pytest tests/test_peptiverse.py tests/test_peptiverse_cpp.py tests/test_plifepred2.py --require-all
Pepsickle neural and gradient-boosted models pepsickle pytest tests/test_pepsickle_legacy.py tests/test_pepsickle_runtime.py --require-all
SMM, SMM-PMBEC smm python -m pytest tests/test_smm.py tests/test_smm_integration.py --require-all
NetTCR (LiteRT) nettcr python -m pytest tests/test_nettcr.py --require-all -W error
DeepTAP classification and regression deeptap python -m pytest tests/test_deeptap.py --require-all -ra
DeepImmuno, TLimmuno2, NetCleave keras python -m pytest tests/test_deepimmuno.py tests/test_tlimmuno2.py tests/test_netcleave.py --require-all -W error
Legacy NetMHC legacy TEST_SH_MAX=2 ./test.sh --require-all -ra

Notes on what CI asserts:

  • DeepTAP: both classification and regression run on the pinned model snapshot in an isolated PyTorch/Lightning interpreter. Classification also checks the committed upstream demo scores. Missing models or runtimes fail the job through --require-all.
  • PeptiVerse CPP: the original CPU SVC runs under scikit-learn 1.7.2. Direct native API scores, class labels, threshold and entropy agree with the adapter, including duplicates; five fixed source controls are replayed. This is source conformance, not independent biological validation.
  • MixMHCpred and PRIME: the host uses pandas 3 and the isolated backend uses pandas below 3. Unmodified native launchers provide reference scores for multi-allele rows, duplicate peptides, sequence alignment, motifs/HTML, CLI output and nested PRIME execution. The host interpreter, pandas version and environment are checked before and after inference.
  • NetTCR runs with TensorFlow absent from the host and without skips or warnings.
  • DeepImmuno, TLimmuno2 and NetCleave run through the isolated interpreter with the host free of TensorFlow. DeepImmuno and TLimmuno2 tests probe Keras-2 availability; NetCleave tests require their runtime whenever its model assets are installed.
  • SMM: the public Python jobs replay the recorded SMM outputs offline, and a dedicated integration job installs the pinned bundle and compares real inference for both methods against every recorded peptide/allele pair.
  • Pepsickle: the CI job runs the constitutive and immunoproteasome profiles against direct upstream inference, checks runtime provenance, and exercises batch save/reload. This is implementation conformance, not held-out biological validation; see cleavage validation.
  • The legacy NetMHC runtime exists only for the old NetMHC 3.4 and NetMHCcons integration tests.

Maintaining the pinned SMM subset is covered in maintaining the IEDB SMM subset.

Documentation checks

The predictor matrix is generated and tested:

python scripts/predictor_matrix.py            # rewrite docs/predictor-matrix.md
python scripts/predictor_matrix.py --check    # exit 1 if it is stale
python -m pytest tests/test_docs_predictor_matrix.py

The test fails when an exported predictor class or command-line name has no row in the matrix. To build the site locally with broken links treated as errors:

python -m pip install -e '.[docs]'
mkdocs build --strict

The header version is read from mhctools/__init__.py during each docs build. It describes the checked-out package version and is independent of GitHub release metadata.

CI and release verification

CI checks installation, dependencies, CLI startup, builds and lint on Python 3.11–3.14, with both pandas 2 and 3 on Python 3.11. It discovers all tests and runs every test without the requires_external_tool marker. New offline test files join that matrix automatically. Mark only tests that require separately installed predictor binaries, weights, or isolated upstream runtimes; keep parser, mocked-adapter, and validation tests in mixed modules unmarked. Run the same selection locally:

python -m pytest tests/ -m "not requires_external_tool" --strict-markers -ra

CI also runs the licensed NetMHC integration suite, and separate real-model jobs for TULIP, CapHLA, MixTCRpred, the two half-life predictors, the three Gfeller MHC predictors, DeepImmuno/TLimmuno2/NetCleave, NetTCR, and local SMM/SMM-PMBEC. Each focused model job uses --require-all, so a missing installation cannot silently turn it green. The complete release run requires all installed backends and zero skips:

./lint.sh
TEST_SH_MAX=2 ./test.sh --require-all -ra
# After merging, from clean master:
PYTEST_ADDOPTS=--require-all TEST_SH_MAX=2 ./deploy.sh

The two-worker limit has completed the release suite on Apple Silicon. A four-worker run intermittently crashed inside the emulated legacy NetMHCcons runtime; #599 tracks the unresolved cause. A passing run with fewer workers does not establish a runtime fix. Prediction failures remain test failures and are never retried or skipped.

CleaveNet source conformance

Provision with python scripts/setup_test_backends.py cleavenet --python python3.11, source the generated activation file, then run python -m pytest tests/test_cleavenet.py --require-all. The separate CI job runs the real five-model ensemble; the quality matrix runs validation and mocked output-contract regressions without TensorFlow. The recorded fixture comes from official source inference, not an independent experimental benchmark.