This is a test version of Biostars. For the public version, visit https://www.biostars.org.
Tutorial: How to make your snakefiles self-documenting

I wrote a gist about how to make snakefiles self-documenting:

# This snippet add the "self-documenting" feature to snakemake files. 
# It is inspired by the Makefile in https://github.com/audreyr/cookiecutter-pypackage

# Add the follwing to your snakefile or include: "self_document.snake"

import re
def generate_help(sfile):
    """Parse out target and help message from file."""
    handler = open(sfile, "r")
    for line in handler:
        match = re.match(r'^rule\s+([a-zA-Z_-]+):.*?## (.*)$$', line)
        if match:
            target, help = match.groups()
            print("%-20s %s" % (target, help))

rule help: ## print list of all targets with help
    input:
        workflow.included
    run:
        print("--------------------------------------------")
        [generate_help(sfile) for sfile in input]
        print("--------------------------------------------")

# Then simply add a comment to your rule line preceded by '##'. Invoking snakemake help will print all targets and their descriptions.
snakemake

Can you replace the URL redirector with a real URL? Otherwise we have no idea where that is going to take you.

2 answers

Thanks for posting. This can also be accomplished using native snakemake's objects, workflow and rule with docstring.

rule help:
  """
  Print list of all targets with help.
  """
  run:
    for rule in workflow.rules:
      print( rule.name )
      print( rule.docstring )

rule do_something:
  """
  Do something.
  """
  run:
    pass

You can then write a function to prettify the outputs.

Yeah, this might be a better way to do it :)

Not sure if this is a newly added functionality, but I just realized one can simply do snakemake -l or snakemake --lt to display docstrings for each rule.

This is better than what I've been doing:

rule print_help:
"""Print help menu.
"""
run:
    tbl = PrettyTable(['Rules', 'Description'])
    tbl.align = 'l'
    for rule in workflow.rules:
        if not rule.name.startswith('_'):
            tbl.add_row([rule.name, rule.docstring.splitlines()[0]])
    print(tbl)

Log in to answer this question.