mhctools 4.4.2__tar.gz → 4.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mhctools-4.4.2/mhctools.egg-info → mhctools-4.4.4}/PKG-INFO +1 -1
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/__init__.py +1 -1
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/process_helpers.py +21 -9
- {mhctools-4.4.2 → mhctools-4.4.4/mhctools.egg-info}/PKG-INFO +1 -1
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/build_iedb_smm_subset.py +18 -9
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/setup_test_backends.py +1 -1
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mixmhcpred_runtime_integration.py +64 -4
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_process_helpers.py +47 -31
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_smm_subset_provenance.py +81 -20
- {mhctools-4.4.2 → mhctools-4.4.4}/LICENSE +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/MANIFEST.in +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/README.md +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/_resources.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/_validation.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/allele_normalization.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/annotate.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/artifacts.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/base_commandline_predictor.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/base_predictor.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/benchmark.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/bigmhc.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/binding_prediction.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/binding_prediction_collection.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/calis.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/caphla.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cavaco.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cleanup_context.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cleavage_batch.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cleavenet.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cleavenet_sidecar.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/__init__.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/annotate_table.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/args.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/artifacts.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/benchmark.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/cleavenet.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/errors.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/integrations.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/mixtcrpred.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/parsing_helpers.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/script.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/vaccine_compare.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/vaccine_report.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/vaccine_trajectory.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/cli/vaccine_windows.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/common.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/CAVACO_LICENSE.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/ITCELL_LICENSE.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/PHAGESCOUT_LICENSE.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/SERUM_CALIBRATION_LICENSE.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/__init__.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/cavaco_published_model.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/cleavage_reference.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/dpp4_keane2011.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/dpp4_qpisa.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/fap_keane2011.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/intracellular_cleavage_reference.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/intracellular_substrate_evidence.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/itcell_profiles.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/model_lineage.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/phagescout_profiles.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/serum_calibration.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/serum_cleavage_reference.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/serum_contributions.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/data/vaccine_trajectory_evidence.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/deepimmuno.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/deeptap.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/dpp4.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/enzyme_assay.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/enzyme_predictor.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/eramer.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/eramer_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/iedb.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/input_file_formats.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/integrations.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/itcell_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/logging.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/mhcflurry.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/mixmhc2pred.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/mixmhcpred.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/mixmhcpred_runtime.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/mixtcrpred.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/mixtcrpred_sidecar.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netchop.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netcleave.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc3.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc4.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc_cons.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc_pan.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc_pan28.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc_pan3.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc_pan4.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc_pan41.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhc_pan42.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhcii_pan.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/netmhcstabpan.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/nettcr.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/optional_backend.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/parsing.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/pepsickle.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/pepsickle_runtime.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/peptidases.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/peptide_input.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/peptiverse.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/peptiverse_cpp.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/peptiverse_cpp_benchmark.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/peptiverse_sidecar.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/phagescout.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/phagescout_artifacts.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/plifepred2.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/plifepred2_sidecar.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/pred.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/prime.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/processing_predictor.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/proteasome_predictor.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/random_predictor.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/sample.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/serum_calibration.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/serum_contributions.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/serum_degradation.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/smm.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/substrate_reference.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/target_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/tcr.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/tlimmuno2.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/tulip.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/unsupported_allele.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/vaccine_exposure.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/vaccine_report.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/vaccine_trajectory.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/vaccine_trajectory_report.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/vaccine_windows.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/weirdo.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools/wrapper_base.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools.egg-info/SOURCES.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools.egg-info/dependency_links.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools.egg-info/entry_points.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools.egg-info/requires.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/mhctools.egg-info/top_level.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/pyproject.toml +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/evaluate_wada_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/osteosarc_fixtures.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/record_cavaco_reference.js +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/record_smm_fixtures.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/test-backends/Dockerfile.netmhc-legacy +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/test-backends/Dockerfile.pepsickle-legacy +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/scripts/test-backends/run_netmhc.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/setup.cfg +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/cavaco_source_reference.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/itcell_source_reference.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/README.md +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/class_i.fasta +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/class_i.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/class_ii.fasta +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/class_ii.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/cleavage.fasta +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/cleavage.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/cons_9mer.fasta +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/cons_9mer.txt +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/panels.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/inputs/source.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/manifest.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/mixmhc2pred.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/mixmhc2pred.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/mixmhc2pred.tsv +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/mixmhcpred.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/mixmhcpred.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/mixmhcpred.tsv +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netchop-20s.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netchop-20s.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netchop-cterm.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netchop-cterm.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netmhccons-a0101.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netmhccons-a0101.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netmhccons-b0801.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netmhccons-b0801.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netmhciipan.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netmhciipan.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netmhcpan.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/netmhcpan.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/prime.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/prime.stdout +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/outputs/prime.tsv +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/README.md +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/manifest.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/peptides-10.fasta +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/peptides-9.fasta +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/smm-10.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/smm-10.tsv +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/smm-9.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/smm-9.tsv +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/smmpmbec-10.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/smmpmbec-10.tsv +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/smmpmbec-9.stderr +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/osteosarc/smm/smmpmbec-9.tsv +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/peptiverse_cpp_source_reference.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/peptiverse_cpp_validation_summary.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/tusar2023/README.md +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/tusar2023/catl-protected-peptides.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/wada2018/README.md +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/wada2018/figure2ac.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/data/wada2018/pepsickle-gb-evaluation.json +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_allele_batching.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_annotate_table.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_artifacts.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_backend_discovery.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_backend_requirements.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_benchmark.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_bigmhc.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_bigmhc_pairs.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_binding_prediction.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_binding_prediction_collection.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_calis.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_caphla.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cathepsin_reference.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cavaco.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_check_results.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_ci_selection.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_class2_allele_formats.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cleavage_batch.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cleavage_mechanism_scorecards.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cleavenet.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cli.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cli_embedding.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cli_filters.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cli_parsing_helpers.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cli_registry.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cli_subcommands.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_cli_user_errors.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_command_log_cleanup.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_commandline_diagnostics.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_commandline_predict_pairs.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_dataframe_schema_parity.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_deepimmuno.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_deeptap.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_deploy_script.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_docs_links.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_docs_predictor_matrix.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_docs_version.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_dpp4.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_enzyme_assay.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_enzyme_predictor.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_eramer.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_eramer_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_exposure_result.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_focused_stability_report.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_iedb_local.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_input_validation.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_integrations.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_intracellular_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_itcell_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_known_class1_epitopes.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_known_class2_epitopes.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_lazy_load.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_logging.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mhc_formats.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mhcflurry.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mhcflurry_cache_key.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mhcflurry_key_lookup.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mhcflurry_provenance.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mixmhc2pred2.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mixmhcpred.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mixmhcpred_runtime.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_mixtcrpred.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netchop.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netchop_parse.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netcleave.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netmhc_cons.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netmhc_pan.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netmhc_program_defaults.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netmhc_stabpan.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netmhc_version.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netmhcii_pan.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_netmhcii_pan32.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_nettcr.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_optional_backend.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_osteosarc_fixtures.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_osteosarc_visualization.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_packaging.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_pepsickle.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_pepsickle_legacy.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_pepsickle_runtime.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_peptidases.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_peptide_input.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_peptide_lengths.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_peptiverse.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_peptiverse_cpp.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_peptiverse_cpp_benchmark.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_phagescout.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_phagescout_artifacts.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_phagescout_full_profiles.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_plifepred2.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_pred.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_prediction_alignment.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_prime.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_processing_predictor.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_random.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_release_preflight.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_require_all.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_serum_calibration.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_serum_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_serum_contributions.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_serum_degradation.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_smm.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_smm_integration.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_stability_route.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_supported_allele_cache.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_target_cascade_analysis.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_target_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_tcr.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_tlimmuno2.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_tulip.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_unparseable_alleles.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_vaccine_comparison.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_vaccine_core_exposure.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_vaccine_report.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_vaccine_trajectory.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_vaccine_trajectory_report.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_vaccine_windows.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_wada_cleavage.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_weirdo.py +0 -0
- {mhctools-4.4.2 → mhctools-4.4.4}/tests/test_wrapper_base.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mhctools
|
|
3
|
-
Version: 4.4.
|
|
3
|
+
Version: 4.4.4
|
|
4
4
|
Summary: Python interface to MHC binding, presentation, immunogenicity, and antigen processing predictors
|
|
5
5
|
Author-email: Alex Rubinsteyn <alex@openvax.org>, Julia Kodysh <julia@openvax.org>, Tim O'Donnell <tim@openvax.org>
|
|
6
6
|
License-Expression: Apache-2.0 AND LGPL-2.1-only AND CC-BY-4.0 AND CC0-1.0
|
|
@@ -96,19 +96,31 @@ class AsyncProcess(object):
|
|
|
96
96
|
return self.process.poll()
|
|
97
97
|
|
|
98
98
|
def _terminate(self, grace_seconds):
|
|
99
|
-
"""Terminate
|
|
99
|
+
"""Terminate owned processes, including children after the leader exits."""
|
|
100
100
|
if self.terminate_process_group and os.name == "posix":
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
# start_new_session makes this PID the group ID. getpgid(pid) can
|
|
102
|
+
# fail after the leader exits while its children are still alive.
|
|
103
|
+
process_group = self.process.pid
|
|
104
|
+
deadline = time.monotonic() + grace_seconds
|
|
105
|
+
try:
|
|
106
|
+
os.killpg(process_group, signal.SIGTERM)
|
|
107
|
+
while True:
|
|
108
|
+
self.process.poll() # Reap the leader, but keep checking children.
|
|
109
|
+
os.killpg(process_group, 0)
|
|
110
|
+
remaining = deadline - time.monotonic()
|
|
111
|
+
if remaining <= 0:
|
|
112
|
+
os.killpg(process_group, signal.SIGKILL)
|
|
113
|
+
break
|
|
114
|
+
time.sleep(min(0.05, remaining))
|
|
115
|
+
except ProcessLookupError:
|
|
116
|
+
pass # The entire group has already exited.
|
|
117
|
+
self.process.wait()
|
|
118
|
+
return
|
|
119
|
+
self.process.terminate()
|
|
105
120
|
try:
|
|
106
121
|
self.process.wait(timeout=grace_seconds)
|
|
107
122
|
except TimeoutExpired:
|
|
108
|
-
|
|
109
|
-
os.killpg(process_group, signal.SIGKILL)
|
|
110
|
-
else:
|
|
111
|
-
self.process.kill()
|
|
123
|
+
self.process.kill()
|
|
112
124
|
self.process.wait()
|
|
113
125
|
|
|
114
126
|
def wait(self, timeout=None, terminate_grace_seconds=5):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mhctools
|
|
3
|
-
Version: 4.4.
|
|
3
|
+
Version: 4.4.4
|
|
4
4
|
Summary: Python interface to MHC binding, presentation, immunogenicity, and antigen processing predictors
|
|
5
5
|
Author-email: Alex Rubinsteyn <alex@openvax.org>, Julia Kodysh <julia@openvax.org>, Tim O'Donnell <tim@openvax.org>
|
|
6
6
|
License-Expression: Apache-2.0 AND LGPL-2.1-only AND CC-BY-4.0 AND CC0-1.0
|
|
@@ -19,8 +19,9 @@ LIAI_license.txt is included because the bundle is Non-Profit Open Software
|
|
|
19
19
|
License 3.0 and the terms travel with the material.
|
|
20
20
|
|
|
21
21
|
Reproducibility: entries are sorted, and mtime, mode, uid/gid and uname/gname
|
|
22
|
-
are normalized.
|
|
23
|
-
|
|
22
|
+
are normalized. The audit pins the uncompressed tar stream's SHA-256, so gzip
|
|
23
|
+
encoding differences do not affect it. The installer separately pins the exact
|
|
24
|
+
compressed bytes of the hosted artifact.
|
|
24
25
|
|
|
25
26
|
python scripts/build_iedb_smm_subset.py \
|
|
26
27
|
--archive env/test-backends/IEDB_MHC_I-3.1.7.tar.gz \
|
|
@@ -62,12 +63,13 @@ INCLUDED_PREFIXES = (
|
|
|
62
63
|
|
|
63
64
|
EXCLUDED_NAMES = ("__pycache__", ".pyc")
|
|
64
65
|
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
# what ties the hosted copy to a build from the official release rather than to
|
|
68
|
-
# whatever was uploaded.
|
|
66
|
+
# Exact hosted archive bytes, also pinned by setup_test_backends. A rebuild
|
|
67
|
+
# may use a different gzip encoding while preserving the normalized tar stream.
|
|
69
68
|
EXPECTED_SUBSET_SHA256 = (
|
|
70
69
|
"eef720a71991a76ceee64ce32fbb52e19684b91d9d44eb078c18c96f395e192e")
|
|
70
|
+
# SHA-256 after gzip decompression, including normalized tar headers and padding.
|
|
71
|
+
EXPECTED_SUBSET_TAR_SHA256 = (
|
|
72
|
+
"f1e3d6168644a33e64a8be00d77b4e56808db1bd9b72bcc704d4954828ad494e")
|
|
71
73
|
|
|
72
74
|
|
|
73
75
|
def _digest(path):
|
|
@@ -78,6 +80,11 @@ def _digest(path):
|
|
|
78
80
|
return sha256.hexdigest()
|
|
79
81
|
|
|
80
82
|
|
|
83
|
+
def _tar_digest(path):
|
|
84
|
+
with gzip.open(path, "rb") as handle:
|
|
85
|
+
return hashlib.file_digest(handle, "sha256").hexdigest()
|
|
86
|
+
|
|
87
|
+
|
|
81
88
|
MARKER = "mhc_i/"
|
|
82
89
|
|
|
83
90
|
|
|
@@ -194,16 +201,18 @@ def main():
|
|
|
194
201
|
files = [entry for entry in entries if entry[1] is not None]
|
|
195
202
|
total = sum(len(entry[1]) for entry in files)
|
|
196
203
|
digest = _digest(args.output)
|
|
204
|
+
tar_digest = _tar_digest(args.output)
|
|
197
205
|
print("files: %d" % len(files))
|
|
198
206
|
print("directories: %d" % (len(entries) - len(files)))
|
|
199
207
|
print("bytes: %d (%.1f MB uncompressed)" % (total, total / 1e6))
|
|
200
208
|
print("output: %s (%.1f MB)"
|
|
201
209
|
% (args.output, args.output.stat().st_size / 1e6))
|
|
202
210
|
print("sha256: %s" % digest)
|
|
203
|
-
|
|
211
|
+
print("tar_sha256: %s" % tar_digest)
|
|
212
|
+
if tar_digest != EXPECTED_SUBSET_TAR_SHA256:
|
|
204
213
|
raise SystemExit(
|
|
205
|
-
"Built subset does not match
|
|
206
|
-
%
|
|
214
|
+
"Built subset tar does not match EXPECTED_SUBSET_TAR_SHA256 (%s)"
|
|
215
|
+
% EXPECTED_SUBSET_TAR_SHA256)
|
|
207
216
|
|
|
208
217
|
|
|
209
218
|
if __name__ == "__main__":
|
|
@@ -220,7 +220,7 @@ def gfeller(root, python, config):
|
|
|
220
220
|
# the Actions cache evicted, which blocked unrelated merges. The release
|
|
221
221
|
# unpacks to 1031 MB, mostly bundled DTU executables SMM never runs, against
|
|
222
222
|
# 9.4 MB it needs. scripts/build_iedb_smm_subset.py
|
|
223
|
-
#
|
|
223
|
+
# audits the normalized tar contents independently of gzip encoding; the
|
|
224
224
|
# upstream Non-Profit OSL 3.0 license ships inside it.
|
|
225
225
|
SMM_SUBSET_URL = (
|
|
226
226
|
"https://github.com/openvax/mhctools/releases/download/"
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
import os
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
import shutil
|
|
6
|
+
import signal
|
|
6
7
|
import subprocess
|
|
7
8
|
import sys
|
|
9
|
+
from tempfile import TemporaryFile
|
|
10
|
+
import time
|
|
8
11
|
|
|
9
12
|
import pandas as pd
|
|
10
13
|
import pytest
|
|
@@ -16,9 +19,10 @@ from mhctools.mixmhcpred import (
|
|
|
16
19
|
resolve_mixmhcpred_path,
|
|
17
20
|
)
|
|
18
21
|
from mhctools.prime import parse_prime_results
|
|
22
|
+
from mhctools.process_helpers import run_command
|
|
23
|
+
from .common import process_is_running
|
|
19
24
|
|
|
20
25
|
|
|
21
|
-
pytestmark = pytest.mark.requires_external_tool
|
|
22
26
|
PEPTIDES = ["SIINFEKL", "MLDDFSAGA", "SIINFEKL"]
|
|
23
27
|
ALLELES = ["HLA-A*02:01", "HLA-A*01:02"]
|
|
24
28
|
|
|
@@ -49,9 +53,62 @@ def native_runtime():
|
|
|
49
53
|
assert changed == []
|
|
50
54
|
|
|
51
55
|
|
|
52
|
-
def _native(args, environment):
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
def _native(args, environment, timeout=180):
|
|
57
|
+
started = time.monotonic()
|
|
58
|
+
with TemporaryFile() as output:
|
|
59
|
+
try:
|
|
60
|
+
run_command(
|
|
61
|
+
args, env=environment, timeout=timeout,
|
|
62
|
+
terminate_process_group=True,
|
|
63
|
+
redirect_stdout_file=output, redirect_stderr_to_stdout=True)
|
|
64
|
+
except (subprocess.TimeoutExpired, subprocess.CalledProcessError) as error:
|
|
65
|
+
output.seek(0, os.SEEK_END)
|
|
66
|
+
output.seek(max(0, output.tell() - 2000))
|
|
67
|
+
tail = output.read().decode("utf-8", errors="replace").strip()
|
|
68
|
+
reason = (f"timed out (limit {timeout:g}s)"
|
|
69
|
+
if isinstance(error, subprocess.TimeoutExpired)
|
|
70
|
+
else f"exited with status {error.returncode}")
|
|
71
|
+
pytest.fail(
|
|
72
|
+
f"{args[0]} {reason} after {time.monotonic() - started:.2f}s.\n"
|
|
73
|
+
f"Output tail:\n{tail or '(empty output)'}", pytrace=False)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_native_reference_failure_reports_bounded_output():
|
|
77
|
+
command = [sys.executable, "-c",
|
|
78
|
+
"import sys; print('discarded-prefix' + 'x' * 5000, flush=True); "
|
|
79
|
+
"print('stdout marker', flush=True); "
|
|
80
|
+
"print('stderr marker', file=sys.stderr, flush=True); sys.exit(7)"]
|
|
81
|
+
with pytest.raises(pytest.fail.Exception) as error:
|
|
82
|
+
_native(command, dict(os.environ))
|
|
83
|
+
message = str(error.value)
|
|
84
|
+
assert "exited with status 7" in message
|
|
85
|
+
assert "stdout marker" in message and "stderr marker" in message
|
|
86
|
+
assert "discarded-prefix" not in message
|
|
87
|
+
assert len(message) < 2400
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@pytest.mark.skipif(os.name != "posix", reason="POSIX process-group behavior")
|
|
91
|
+
def test_native_reference_timeout_stops_children(tmp_path):
|
|
92
|
+
child = tmp_path / "child.py"
|
|
93
|
+
child.write_text(
|
|
94
|
+
"import os, sys, time\nfrom pathlib import Path\n"
|
|
95
|
+
"print('reference child active', flush=True)\n"
|
|
96
|
+
"Path(sys.argv[1]).write_text(str(os.getpid()))\ntime.sleep(60)\n")
|
|
97
|
+
parent = tmp_path / "parent.py"
|
|
98
|
+
parent.write_text(
|
|
99
|
+
"import subprocess, sys\n"
|
|
100
|
+
"subprocess.run([sys.executable, sys.argv[1], sys.argv[2]])\n")
|
|
101
|
+
ready = tmp_path / "child.pid"
|
|
102
|
+
try:
|
|
103
|
+
with pytest.raises(pytest.fail.Exception, match="timed out \\(limit 3s\\)") as error:
|
|
104
|
+
_native([sys.executable, str(parent), str(child), str(ready)],
|
|
105
|
+
dict(os.environ), timeout=3)
|
|
106
|
+
assert ready.is_file(), "Reference child did not start before the timeout"
|
|
107
|
+
assert "reference child active" in str(error.value)
|
|
108
|
+
assert not process_is_running(int(ready.read_text()))
|
|
109
|
+
finally:
|
|
110
|
+
if ready.exists() and process_is_running(int(ready.read_text())):
|
|
111
|
+
os.kill(int(ready.read_text()), signal.SIGKILL)
|
|
55
112
|
|
|
56
113
|
|
|
57
114
|
def _input(tmp_path):
|
|
@@ -60,6 +117,7 @@ def _input(tmp_path):
|
|
|
60
117
|
return str(path)
|
|
61
118
|
|
|
62
119
|
|
|
120
|
+
@pytest.mark.requires_external_tool
|
|
63
121
|
def test_isolated_multi_allele_rows_motifs_and_cli_match_native(native_runtime, tmp_path, monkeypatch):
|
|
64
122
|
executable, selected, environment = native_runtime
|
|
65
123
|
peptide_file = _input(tmp_path)
|
|
@@ -101,6 +159,7 @@ def test_isolated_multi_allele_rows_motifs_and_cli_match_native(native_runtime,
|
|
|
101
159
|
pred.percentile_rank for row in expected.predictions for pred in row.preds], abs=5e-5)
|
|
102
160
|
|
|
103
161
|
|
|
162
|
+
@pytest.mark.requires_external_tool
|
|
104
163
|
def test_isolated_sequence_alignment_prediction_and_artifacts_match_native(native_runtime, tmp_path):
|
|
105
164
|
executable, selected, environment = native_runtime
|
|
106
165
|
assert shutil.which("mafft"), "provision MAFFT for the sequence regression"
|
|
@@ -127,6 +186,7 @@ def test_isolated_sequence_alignment_prediction_and_artifacts_match_native(nativ
|
|
|
127
186
|
assert alignment_only.runtime_info["backend"]["python_executable"] == selected
|
|
128
187
|
|
|
129
188
|
|
|
189
|
+
@pytest.mark.requires_external_tool
|
|
130
190
|
def test_prime_nested_isolated_runtime_matches_native(native_runtime, tmp_path, monkeypatch):
|
|
131
191
|
executable, selected, environment = native_runtime
|
|
132
192
|
prime = os.environ.get("PRIME_EXECUTABLE")
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# See the License for the specific language governing permissions and
|
|
11
11
|
# limitations under the License.
|
|
12
12
|
|
|
13
|
-
"""
|
|
13
|
+
"""Process lifecycle, concurrency limits and runtime probes."""
|
|
14
14
|
|
|
15
15
|
import errno
|
|
16
16
|
import os
|
|
@@ -18,10 +18,12 @@ import signal
|
|
|
18
18
|
import sys
|
|
19
19
|
from subprocess import TimeoutExpired
|
|
20
20
|
import tempfile
|
|
21
|
+
import time
|
|
21
22
|
from unittest.mock import patch, MagicMock
|
|
22
23
|
|
|
23
24
|
import pytest
|
|
24
25
|
|
|
26
|
+
from .common import process_is_running
|
|
25
27
|
from mhctools.process_helpers import (
|
|
26
28
|
AsyncProcess,
|
|
27
29
|
legacy_keras_runtime_available,
|
|
@@ -31,37 +33,51 @@ from mhctools.process_helpers import (
|
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
@pytest.mark.skipif(os.name != "posix", reason="POSIX process-group behavior")
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
@pytest.mark.parametrize("parent_ignores_term,child_ignores_term", [
|
|
37
|
+
(False, False), (False, True), (True, True),
|
|
38
|
+
])
|
|
39
|
+
def test_timeout_stops_the_whole_process_group(
|
|
40
|
+
tmp_path, parent_ignores_term, child_ignores_term):
|
|
41
|
+
child = tmp_path / "child.py"
|
|
42
|
+
child.write_text(
|
|
43
|
+
"import os, signal, sys, time\nfrom pathlib import Path\n"
|
|
44
|
+
"signal.signal(signal.SIGTERM, signal.SIG_IGN if sys.argv[2] == '1' "
|
|
45
|
+
"else signal.SIG_DFL)\n"
|
|
46
|
+
"Path(sys.argv[1]).write_text(str(os.getpid()))\ntime.sleep(60)\n")
|
|
47
|
+
parent = tmp_path / "parent.py"
|
|
48
|
+
parent.write_text(
|
|
49
|
+
"import signal, subprocess, sys, time\n"
|
|
50
|
+
"signal.signal(signal.SIGTERM, signal.SIG_IGN if sys.argv[4] == '1' "
|
|
51
|
+
"else signal.SIG_DFL)\n"
|
|
52
|
+
"subprocess.Popen([sys.executable, sys.argv[1], sys.argv[2], sys.argv[3]])\n"
|
|
53
|
+
"time.sleep(60)\n")
|
|
54
|
+
ready = tmp_path / "child.pid"
|
|
55
|
+
proc = AsyncProcess(
|
|
56
|
+
[sys.executable, str(parent), str(child), str(ready),
|
|
57
|
+
str(int(child_ignores_term)), str(int(parent_ignores_term))],
|
|
58
|
+
terminate_process_group=True)
|
|
59
|
+
proc.start()
|
|
60
|
+
try:
|
|
61
|
+
deadline = time.monotonic() + 5
|
|
62
|
+
while not ready.exists():
|
|
63
|
+
assert proc.poll() is None
|
|
64
|
+
assert time.monotonic() < deadline, "Child did not become ready"
|
|
65
|
+
time.sleep(0.01)
|
|
66
|
+
child_pid = int(ready.read_text())
|
|
43
67
|
with pytest.raises(TimeoutExpired):
|
|
44
|
-
proc.wait(timeout=
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
with patch("mhctools.process_helpers.os.getpgid", return_value=456), \
|
|
58
|
-
patch("mhctools.process_helpers.os.killpg") as killpg:
|
|
59
|
-
with pytest.raises(TimeoutExpired):
|
|
60
|
-
proc.wait(timeout=1, terminate_grace_seconds=0.1)
|
|
61
|
-
assert killpg.call_args_list == [
|
|
62
|
-
((456, signal.SIGTERM),),
|
|
63
|
-
((456, signal.SIGKILL),),
|
|
64
|
-
]
|
|
68
|
+
proc.wait(timeout=0.05, terminate_grace_seconds=0.1)
|
|
69
|
+
assert proc.process.returncode is not None
|
|
70
|
+
deadline = time.monotonic() + 2
|
|
71
|
+
while process_is_running(child_pid) and time.monotonic() < deadline:
|
|
72
|
+
time.sleep(0.01)
|
|
73
|
+
assert not process_is_running(child_pid), "Timeout left a running child"
|
|
74
|
+
finally:
|
|
75
|
+
# A failing regression must not leak its own sleeping child.
|
|
76
|
+
try:
|
|
77
|
+
os.killpg(proc.process.pid, signal.SIGKILL)
|
|
78
|
+
except ProcessLookupError:
|
|
79
|
+
pass
|
|
80
|
+
proc.process.wait()
|
|
65
81
|
|
|
66
82
|
|
|
67
83
|
def test_start_retries_on_blocking_io_error():
|
|
@@ -12,16 +12,13 @@
|
|
|
12
12
|
|
|
13
13
|
"""The hosted SMM subset must stay traceable to one upstream IEDB release.
|
|
14
14
|
|
|
15
|
-
The
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
version of its own -- so the chain from "what CI installs" back to "which
|
|
19
|
-
IEDB release" holds only if the installer's digest equals the one the builder
|
|
20
|
-
declares. Assert that, or a rebuilt-and-reuploaded asset could change what CI
|
|
21
|
-
installs while the recorded fixtures keep describing the old release.
|
|
15
|
+
The source archive, normalized tar stream and exact hosted gzip artifact have
|
|
16
|
+
separate checksums. Rebuilds must preserve the normalized tar stream across gzip
|
|
17
|
+
encodings; installation must still reject changes to the hosted archive bytes.
|
|
22
18
|
"""
|
|
23
19
|
|
|
24
20
|
import importlib.util
|
|
21
|
+
import gzip
|
|
25
22
|
import hashlib
|
|
26
23
|
import io
|
|
27
24
|
from pathlib import Path
|
|
@@ -32,6 +29,10 @@ import tarfile
|
|
|
32
29
|
import pytest
|
|
33
30
|
|
|
34
31
|
SCRIPTS = Path(__file__).resolve().parent.parent / "scripts"
|
|
32
|
+
# Fixed digest of the normalized tar for source_files, independently checked
|
|
33
|
+
# against its member payloads and metadata below.
|
|
34
|
+
SOURCE_FILES_TAR_SHA256 = (
|
|
35
|
+
"1220dc57900fd4be42e64a8513cc0bae94bd11713a3f183ac8adcc02852b75e0")
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
def _load(name):
|
|
@@ -63,18 +64,23 @@ def test_installer_pins_a_subset_checksum():
|
|
|
63
64
|
assert re.fullmatch(r"[0-9a-f]{64}", installer.SMM_SUBSET_SHA256)
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
def
|
|
67
|
-
"""Ties the installed artifact to a build from the pinned IEDB release.
|
|
68
|
-
|
|
69
|
-
Without this, uploading a modified asset and updating only
|
|
70
|
-
SMM_SUBSET_SHA256 passes every other check here.
|
|
71
|
-
"""
|
|
67
|
+
def test_installer_digest_matches_the_hosted_artifact_pin():
|
|
72
68
|
builder = _load("build_iedb_smm_subset")
|
|
73
69
|
installer = _load("setup_test_backends")
|
|
74
70
|
|
|
75
71
|
assert installer.SMM_SUBSET_SHA256 == builder.EXPECTED_SUBSET_SHA256
|
|
76
72
|
|
|
77
73
|
|
|
74
|
+
@pytest.mark.requires_external_tool
|
|
75
|
+
def test_hosted_archive_matches_the_pinned_tar_content():
|
|
76
|
+
archive = SCRIPTS.parent / "env/test-backends/IEDB_MHC_I-3.1.7-smm-subset.tar.gz"
|
|
77
|
+
if not archive.is_file():
|
|
78
|
+
pytest.skip("Provision the SMM artifact: python scripts/setup_test_backends.py smm")
|
|
79
|
+
builder = _load("build_iedb_smm_subset")
|
|
80
|
+
assert builder._digest(archive) == builder.EXPECTED_SUBSET_SHA256
|
|
81
|
+
assert builder._tar_digest(archive) == builder.EXPECTED_SUBSET_TAR_SHA256
|
|
82
|
+
|
|
83
|
+
|
|
78
84
|
def test_subset_carries_the_upstream_licenses():
|
|
79
85
|
"""NPOSL-3.0 material is redistributed, so its notices must travel."""
|
|
80
86
|
builder = _load("build_iedb_smm_subset")
|
|
@@ -83,8 +89,7 @@ def test_subset_carries_the_upstream_licenses():
|
|
|
83
89
|
assert notice in builder.INCLUDED_PREFIXES
|
|
84
90
|
|
|
85
91
|
|
|
86
|
-
def
|
|
87
|
-
"""The installed artifact must be the one build_iedb_smm_subset writes."""
|
|
92
|
+
def test_installer_downloads_the_pinned_subset_release():
|
|
88
93
|
installer = _load("setup_test_backends")
|
|
89
94
|
|
|
90
95
|
assert installer.SMM_SUBSET_URL.startswith(
|
|
@@ -143,8 +148,8 @@ def _build_subset(monkeypatch, archive, output, **pins):
|
|
|
143
148
|
monkeypatch.setattr(builder, "ARCHIVE_SHA256", pins.get(
|
|
144
149
|
"source", hashlib.sha256(archive.read_bytes()).hexdigest()))
|
|
145
150
|
# Synthetic archives exercise the real builder without the 341 MB download.
|
|
146
|
-
monkeypatch.setattr(builder, "
|
|
147
|
-
pins.get("subset",
|
|
151
|
+
monkeypatch.setattr(builder, "EXPECTED_SUBSET_TAR_SHA256",
|
|
152
|
+
pins.get("subset", SOURCE_FILES_TAR_SHA256))
|
|
148
153
|
monkeypatch.setattr(sys, "argv", [
|
|
149
154
|
str(SCRIPTS / "build_iedb_smm_subset.py"),
|
|
150
155
|
"--archive", str(archive), "--output", str(output)])
|
|
@@ -163,7 +168,7 @@ def test_builder_preserves_payload_and_normalizes_metadata(
|
|
|
163
168
|
second = tmp_path / "second.tar.gz"
|
|
164
169
|
_build_subset(monkeypatch, archive, first)
|
|
165
170
|
_build_subset(monkeypatch, archive, second,
|
|
166
|
-
subset=hashlib.sha256(first.read_bytes()).hexdigest())
|
|
171
|
+
subset=hashlib.sha256(gzip.decompress(first.read_bytes())).hexdigest())
|
|
167
172
|
assert first.read_bytes() == second.read_bytes()
|
|
168
173
|
with tarfile.open(first) as subset:
|
|
169
174
|
assert subset.getnames() == sorted(source_files)
|
|
@@ -212,13 +217,69 @@ def test_builder_rejects_wrong_source_checksum(tmp_path, monkeypatch, source_fil
|
|
|
212
217
|
assert not output.exists()
|
|
213
218
|
|
|
214
219
|
|
|
215
|
-
def
|
|
220
|
+
def test_builder_rejects_wrong_tar_checksum(tmp_path, monkeypatch, source_files):
|
|
216
221
|
archive = tmp_path / "upstream.tar.gz"
|
|
217
222
|
_write_archive(archive, source_files)
|
|
218
|
-
with pytest.raises(SystemExit, match="does not match
|
|
223
|
+
with pytest.raises(SystemExit, match="does not match EXPECTED_SUBSET_TAR_SHA256"):
|
|
219
224
|
_build_subset(monkeypatch, archive, tmp_path / "subset.tar.gz", subset="0" * 64)
|
|
220
225
|
|
|
221
226
|
|
|
227
|
+
@pytest.mark.parametrize("encoding", [
|
|
228
|
+
{"compresslevel": 0},
|
|
229
|
+
{"compresslevel": 1},
|
|
230
|
+
{"filename": "another-name.tar", "mtime": 123456789},
|
|
231
|
+
])
|
|
232
|
+
def test_builder_accepts_different_gzip_encodings(
|
|
233
|
+
tmp_path, monkeypatch, source_files, capsys, encoding):
|
|
234
|
+
archive = tmp_path / "upstream.tar.gz"
|
|
235
|
+
_write_archive(archive, source_files)
|
|
236
|
+
first, second = tmp_path / "first.tar.gz", tmp_path / "second.tar.gz"
|
|
237
|
+
_build_subset(monkeypatch, archive, first)
|
|
238
|
+
original_gzip = gzip.GzipFile
|
|
239
|
+
|
|
240
|
+
def alternate_gzip(*args, **kwargs):
|
|
241
|
+
if kwargs.get("mode") == "wb":
|
|
242
|
+
kwargs.update(encoding)
|
|
243
|
+
return original_gzip(*args, **kwargs)
|
|
244
|
+
|
|
245
|
+
monkeypatch.setattr(gzip, "GzipFile", alternate_gzip)
|
|
246
|
+
_build_subset(monkeypatch, archive, second)
|
|
247
|
+
assert first.read_bytes() != second.read_bytes()
|
|
248
|
+
assert gzip.decompress(first.read_bytes()) == gzip.decompress(second.read_bytes())
|
|
249
|
+
assert capsys.readouterr().out.count("tar_sha256: " + SOURCE_FILES_TAR_SHA256) == 2
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@pytest.mark.parametrize("change", ["payload", "path"])
|
|
253
|
+
def test_builder_rejects_changed_tar_content(
|
|
254
|
+
tmp_path, monkeypatch, source_files, change):
|
|
255
|
+
if change == "payload":
|
|
256
|
+
source_files["mhc_i/src/setupinfo.template"] += b"changed\n"
|
|
257
|
+
else:
|
|
258
|
+
source_files["mhc_i/src/renamed.template"] = source_files.pop(
|
|
259
|
+
"mhc_i/src/setupinfo.template")
|
|
260
|
+
archive = tmp_path / "upstream.tar.gz"
|
|
261
|
+
_write_archive(archive, source_files)
|
|
262
|
+
with pytest.raises(SystemExit, match="does not match EXPECTED_SUBSET_TAR_SHA256"):
|
|
263
|
+
_build_subset(monkeypatch, archive, tmp_path / "subset.tar.gz")
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def test_installer_rejects_reencoded_hosted_artifact(
|
|
267
|
+
tmp_path, monkeypatch, source_files):
|
|
268
|
+
archive = tmp_path / "upstream.tar.gz"
|
|
269
|
+
_write_archive(archive, source_files)
|
|
270
|
+
subset = tmp_path / "IEDB_MHC_I-3.1.7-smm-subset.tar.gz"
|
|
271
|
+
_build_subset(monkeypatch, archive, subset)
|
|
272
|
+
installer = _load("setup_test_backends")
|
|
273
|
+
monkeypatch.setattr(installer, "SMM_SUBSET_SHA256",
|
|
274
|
+
hashlib.sha256(subset.read_bytes()).hexdigest())
|
|
275
|
+
payload = gzip.decompress(subset.read_bytes())
|
|
276
|
+
subset.write_bytes(gzip.compress(payload, compresslevel=0, mtime=0))
|
|
277
|
+
assert _load("build_iedb_smm_subset")._tar_digest(subset) == SOURCE_FILES_TAR_SHA256
|
|
278
|
+
with pytest.raises(SystemExit, match="Unexpected IEDB SMM subset checksum"):
|
|
279
|
+
installer.smm(tmp_path, sys.executable, {})
|
|
280
|
+
assert not (tmp_path / "iedb-3.1.7").exists()
|
|
281
|
+
|
|
282
|
+
|
|
222
283
|
def test_installer_replaces_stale_tree_after_verifying_checksum(
|
|
223
284
|
tmp_path, monkeypatch, source_files):
|
|
224
285
|
archive = tmp_path / "upstream.tar.gz"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|