Architecture
ViralUnity is a thin Python orchestration layer over Snakemake workflows. The
Python code validates inputs, writes a YAML config, and launches one of six
Snakemake workflows; all the bioinformatics lives in the .smk rule files.
Data flow
CLI (click) viralunity_cli.py → <subcommand>_cli.py
│ parses options, configures logging (--log-level / --json-logs)
▼
main(args) viralunity_consensus.py / viralunity_meta.py
│ thin wrapper around…
▼
_orchestrator.run_pipeline(...) viralunity/_orchestrator.py
│ resolve_paths → validate → generate_config → [run manifest] → run_workflow
▼
ConfigGenerator → YAML viralunity/config_generator.py
│ emits the exact keys the .smk files read (config["samples"], …)
▼
snakemake(workflow.smk, config) viralunity/scripts/<pipeline>_<datatype>.smk
│ rule all → _all_inputs() → include: rules/*.smk
▼
per-rule conda envs viralunity/scripts/envs/*.yaml (--use-conda)
Module map
Module |
Responsibility |
|---|---|
|
Top-level click group; wires |
|
Per-subcommand click options → plain |
|
Own |
|
Shared |
|
File/dir existence, sample-sheet parsing, cross-dependency checks, input sanitization, and content-level input-integrity orchestration ( |
|
Streaming, pure-stdlib content validators for consensus inputs (FASTQ/FASTA/BED/GFF3); collect |
|
Splits a multi-record |
|
Writes the YAML config (the contract with the |
|
|
|
Typed error hierarchy with machine-readable |
|
Central logging (run id, text/JSON). |
|
|
|
|
|
The actual pipelines. |
|
Helpers run via Snakemake’s |
The config is the contract
ConfigGenerator emits keys that are hard-coded as strings in the .smk files
(e.g. config["samples"], config["output"], config["run_denovo_assembly"]).
Adding a pipeline option means touching four places: the click option in the
relevant *_cli.py, the validators.py check, a ConfigGenerator.add_* setter,
and the rule(s) that read it. config["samples"] maps sample-<id> to a list
of FASTQ paths (readers tolerate the legacy space-joined string form too).
Workflow selection
run_snakemake_workflow formats a path:
scripts/{consensus,metagenomics}_{illumina,nanopore}[_segmented].smk.
Segmentation is chosen when args["reference"] is a dict — built either from
repeatable --segmented-reference SEGMENT=PATH, or by reference_splitter.py
auto-splitting a single multi-record --reference FASTA during validation
(unless --single-reference). There is no segmented metagenomics variant.