Skip to content

Conditional rules structure #4

Description

@Headonpillow

Summary:

  1. Replace the two mutually exclusive trimming rules with a single prepare_trimmed rule that branches on enabled("preprocess").
  2. Declare rules unconditionally; use branching inside run/shell blocks instead of wrapping entire rules in Python conditionals.
  3. Optionally split large rule groups into modules (e.g., rules/preprocess.smk, rules/phylogeny.smk) and include them conditionally to keep the DAG tidy.

Implementation notes / concrete refactor steps (proposed):

  1. Use proper booleans in config and add a small helper
  • Recommend config_templates/basic.yaml use YAML booleans (e.g., preprocess: true, phylogeny: true).
  • Add an enabled(key) helper in the Snakefile to accept multiple truthy formats (strings, integers, booleans).

Example:

def enabled(key):
    v = config.get(key, False)
    if isinstance(v, str):
        return v.lower() in ("yes","y","true","1")
    return bool(v)
  1. Build rule all targets dynamically
  • Replace the current ad-hoc myoutput list + manual appends with a function all_targets() that returns the final target list depending on flags.

Example:

def all_targets():
    targets = [
        "results/denoising/read_count_tracking.tsv",
        "results/asv/ASVs.fa",
        "results/asv/ASVs_counts.tsv",
        "results/asv/ASVs_taxonomy.tsv",
        "results/phyloseq/starting_phyla_table.tsv",
        "results/phyloseq/prevalence_graph.png",
        "results/phyloseq/Phyloseq.RData",
        "results/phyloseq/ASVs_good.fasta",
        "results/phyloseq/plots/plot_1.tiff",
    ]
    if enabled("preprocess"):
        targets += [
            "results/multiQC/report_R1.html",
            "results/multiQC/report_R2.html",
            "results/multiQC_trimmed/report_R1.html",
            "results/multiQC_trimmed/report_R2.html",
        ]
    if enabled("phylogeny"):
        targets += [
            "results/phyloseq/ASV_alignment.mafft",
            "results/phyloseq/ASV_alignment.mafft.treefile",
        ]
    return targets

rule all:
    input: all_targets()
  1. Declare rules unconditionally and branch inside rule bodies where needed
  • Avoid defining whole rules inside Python if blocks. Instead define rules always and use the enabled() helper inside run/shell blocks to branch behavior.
  • Example: replace the current two mutually-exclusive rules that create intermediate/trimmed/* with a single prepare_trimmed rule that either runs trim_galore or copies raw files depending on enabled("preprocess").
  1. Optionally split rule modules and use conditional includes
  • Put large groups of rules in rules/preprocess.smk, rules/phylogeny.smk, etc., and use if enabled("preprocess"): include: "rules/preprocess.smk". Use this only for large modules to keep the top-level Snakefile tidy.
  1. Safety and housekeeping
  • Remove transient print() calls from the Snakefile.
  • Use mkdir -p or directory() outputs instead of ad-hoc mkdir guards.
  • Add a short test checklist: create runs/demo with config.yaml toggling preprocess and phylogeny and run snakemake --configfile runs/demo/config.yaml --directory runs/demo -n to assert the DAG only contains intended targets.

Testing / Acceptance checklist for this issue

  • Add config_templates/basic.yaml with boolean flags.
  • Add enabled() and all_targets() to Snakefile.
  • Replace ad-hoc myoutput usage with all_targets().
  • Convert the two mutually-exclusive trimming rules into a single branching prepare_trimmed rule.
  • Run snakemake -n with permutations of the flags and confirm the DAG and planned jobs match expectations.

Notes on scope

  • This refactor touches Snakefile and possible new config_templates/basic.yaml.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions