TOIL(1)

๐Ÿ“ฆ
version 9.1.2 ยท 4 versions
, in ubuntu resolute

โœจ NAME โœจ

Hiii, welcome to the TOIL(1) manual ๐ŸŽ€ this one is for toil, aka Toil Documentation ๐Ÿ’–

Toil is an open-source, pure-Python workflow engine that lets people write better pipelines โœจ no cap, it's giving main character energy ๐Ÿ’…

Okay so, check out the website http://toil.ucsc-cgl.org/ for a full list of Toil's features ๐ŸŒธ and read the paper http://biorxiv.org/content/early/2016/07/07/062497 to see what Toil can actually do in the real world ๐ŸŒ. Please subscribe to the low-volume announce mailing list at https://groups.google.com/forum/#!forum/toil-announce ๐Ÿ“ฌ and feel free to also join us on GitHub (https://github.com/BD2KGenomics/toil) and Gitter (https://gitter.im/bd2k-genomics-toil/Lobby) ๐Ÿซถ.

If you're using Toil for your research, bestie, please cite this ๐Ÿ“š

Vivian, J., Rao, A. A., Nothaft, F. A., Ketchum, C., Armstrong, J., Novak, A., โ€ฆ Paten, B. (2017). Toil enables reproducible, open source, big biomedical data analyses. Nature Biotechnology, 35(4), 314โ€“316. http://doi.org/10.1038/nbt.3772

โœจ QUICKSTART EXAMPLES โœจ

๐ŸŒˆ Running a basic CWL workflow

The Common Workflow Language (http://www.commonwl.org/), or CWL for short, is an emerging standard for writing workflows that are portable across multiple workflow engines and platforms ๐Ÿฆ‹. Running CWL workflows using Toil is easy, literally ๐Ÿ’–.

  1. Copy and paste the following code block into example.cwl:
cwlVersion: v1.0
class: CommandLineTool
baseCommand: echo
stdout: output.txt
inputs:
  message:
    type: string
    inputBinding:
      position: 1
outputs:
  output:
    type: stdout

and this code into example-job.yaml:

message: Hello world!
  1. To run the workflow, simply enter:
$ toil-cwl-runner example.cwl example-job.yaml

Your output will be in output.txt:

$ cat output.txt
Hello world!

Congratulations, bestie! ๐ŸŽ‰ You've run your first Toil workflow using the default Batch System (#batchsysteminterface), single_machine, and the default file job store (which was placed in a temporary directory for you by toil-cwl-runner) ๐Ÿ‘‘.

Toil uses batch systems to manage the jobs it creates ๐Ÿง.

The single_machine batch system is mainly used to prep and debug workflows on a local machine ๐Ÿ”ง. Once it's validated, try running them on a full-fledged batch system (see Batch System API (#batchsysteminterface)). Toil supports many different batch systems, such as Kubernetes (https://kubernetes.io/) and Grid Engine, so its versatility makes it easy to run your workflow in all kinds of places ๐ŸŒธ.

Toil's CWL runner is totally customizable! ๐Ÿ’… Run toil-cwl-runner --help to see a complete list of available options.

To learn more about CWL, see the CWL User Guide (https://www.commonwl.org/user_guide/), which is where this example was shamelessly borrowed from ๐Ÿ™ˆ. For info on using CWL with Toil, check out the section CWL in Toil (#cwl). And for an example of CWL on an AWS cluster, have a look at Running a CWL Workflow on AWS โœจ.

๐Ÿงš Running a basic WDL workflow

The Workflow Description Language (https://software.broadinstitute.org/wdl/), or WDL, is another emerging language for writing workflows that are portable across multiple workflow engines and platforms ๐ŸŒท. Running WDL workflows using Toil is still in alpha and currently experimental ๐Ÿงช. Toil currently supports basic workflow syntax (see WDL in Toil (#wdl) for more details and examples). Here we go over running a basic WDL helloworld workflow ๐Ÿ’–.

  1. Copy and paste the following code block into wdl-helloworld.wdl:
workflow write_simple_file {
  call write_file
}
task write_file {
  String message
  command { echo ${message} > wdl-helloworld-output.txt }
  output { File test = "wdl-helloworld-output.txt" }
}

and this code into wdl-helloworld.json:

{
  "write_simple_file.write_file.message": "Hello world!"
}
  1. To run the workflow, simply enter:
$ toil-wdl-runner wdl-helloworld.wdl wdl-helloworld.json

Your output will be in wdl-helloworld-output.txt:

$ cat wdl-helloworld-output.txt
Hello world!

Just like the CWL example above, this will use the single_machine batch system and an automatically-located file job store by default ๐Ÿซถ. You can customize how Toil runs the workflow with command-line options. Run toil-wdl-runner --help to learn about them ๐ŸŽ€.

To learn more about WDL in general, see the Terra WDL documentation (https://support.terra.bio/hc/en-us/sections/360007274612-WDL-Documentation) ๐Ÿ“–. For more on using WDL in Toil, see WDL in Toil (#wdl) ๐Ÿ’œ.

๐Ÿ Running a basic Python workflow

Besides workflow languages like CWL and WDL, Toil also supports running workflows written against its Python API ๐Ÿ“.

An example Toil Python workflow can be run with just three steps, bestie ๐Ÿฆ‹:

  1. Install Toil (see Installation (#installation-ref)).
  2. Copy and paste the following code block into a new file called helloWorld.py:
from toil.common import Toil
from toil.job import Job

def helloWorld(message, memory="1G", cores=1, disk="1G"):
    return f"Hello, world!, here's a message: {message}"

if __name__ == "__main__":
    parser = Job.Runner.getDefaultArgumentParser()
    options = parser.parse_args()
    options.clean = "always"
    with Toil(options) as toil:
        output = toil.start(Job.wrapFn(helloWorld, "You did it!"))
    print(output)
  1. Specify the name of the job store (#jobstoreoverview) and run the workflow:
$ python3 helloWorld.py file:my-job-store

For something beyond a "Hello, world!" example, refer to Example: sorting ๐Ÿ”ฅ.

Toil's customization options are available in Python workflows too. Run python3 helloWorld.py --help to see a complete list of available options ๐Ÿ’….

๐Ÿงฌ Example: mitochondrial variant calling

Let's run a more realistic workflow with Toil ๐Ÿ”ฅ. This one is mitochondrial variant calling. It takes the human reference genome and sequenced reads from an individual, then figures out how that person's mitochondrial DNA differs from the reference genome ๐Ÿงฌ.

We'll run an example workflow from Dockstore (https://dockstore.org/workflows/github.com/broadinstitute/gatk/MitochondriaPipeline:master?tab=info). First, grab an example workflow input:

(venv) $ wget https://toil-datasets.s3.us-west-2.amazonaws.com/MitochondriaInputs.zip && unzip MitochondriaInputs.zip

Then, change your current working directory:

(venv) $ cd MitochondriaInputs

This workflow will take approximately 30 minutes to run โณ.

Since Toil supports Dockstore TRS IDs, which lets the WDL runner run any workflow on Dockstore, we'll run it directly ๐Ÿ’–:

(venv) $ toil-wdl-runner '#workflow/github.com/broadinstitute/gatk/MitochondriaPipeline:master' -i ExampleInputsMitochondriaPipeline.json --logInfo --container docker --quantCheck false --outputFile mitochondria.json

Note:

  • --logInfo โ€” runs the workflow with INFO level logging. For different levels of logging, see --logLevel, --logCritical, --logError, --logWarning, --logDebug, and --logTrace ๐Ÿ“.
  • --container docker โ€” uses Docker as the container backend. By default, Toil will run with Singularity. To set it explicitly, use --container singularity ๐Ÿณ.
  • --outputFile โ€” puts the workflow JSON outputs into a file. If you leave it out, Toil will put the workflow outputs onto the commandline ๐Ÿ’Œ.
  • --quantCheck false โ€” disables certain type checks. This is useful for Cromwell compatibility ๐Ÿ™ˆ.
โš ๏ธ Unless fakeroot support is set up for Singularity, this particular workflow must be run with Docker, because it assumes commands in the container will run as root. Also, WDL workflows sometimes depend on non-spec compliant behaviors. To see if Toil has a workaround option, see Toil WDL Runner Options (#wdloptions) ๐Ÿ’€.

Once the workflow is done running, you can look at your JSON output with jq . mitochondria.json ๐Ÿ‘€. For example, if we want the out_vcf output from the workflow, we can run jq -r '.["MitochondriaPipeline.out_vcf"]' mitochondria.json to get its path:

/private/groups/patenlab/toil-dev/mitochondria/wdl-out-c6o9mjop/MitochondriaPipeline.AlignAndCall.FilterContamination/HG02571.GRCh38.chrM.vcf

To open the VCF file, we can run less $(jq -r '.["MitochondriaPipeline.out_vcf"]' mitochondria.json) ๐ŸŒˆ.

Note:

For outputs that aren't files, their values are right there in the JSON ๐Ÿซถ. For example, with jq '.["MitochondriaPipeline.median_coverage"]' mitochondria.json you can fetch the median_coverage output's value:

4183.5

Toil uses a jobstore to store all of a workflow's files and to communicate between workers ๐Ÿ—‚๏ธ. If you don't specify one, Toil will use an ephemeral directory that gets deleted after Toil is done running. To control where those files go, or to allow a workflow to be restarted, you can use the --jobStore option. If you specify a jobstore explicitly, it will stick around if the workflow fails. To keep the jobstore after a successful completion, use --clean never. To remove the jobstore even after a failing run, use --clean always ๐Ÿงน.

On a cluster, the jobstore must be somewhere accessible to all worker nodes ๐ŸŒ. Here's an example of running the workflow with a specified jobstore:

(venv) $ toil-wdl-runner MitochondriaPipeline.wdl -i ExampleInputsMitochondriaPipeline.json --logInfo --container docker --outputFile mitochondria.json --jobstore mitochondriaJobstore

Toil supports several batch systems ๐Ÿง. By default, Toil uses single_machine, which runs everything on the local machine. Other batch systems are available too. For example, you can use --batchSystem slurm to run on a Slurm cluster ๐Ÿš€:

(venv) $ toil-wdl-runner MitochondriaPipeline.wdl -i ExampleInputsMitochondriaPipeline.json --logInfo --container docker --outputFile mitochondria.json --jobStore mitochondriaJobstore --batchSystem slurm

See Running on Slurm (#runningslurm) for more information, including how to specify time limits and partitions โฐ.

Sometimes a workflow fails ๐Ÿ˜ญ. If that happens, the workflow can be restarted from the point of failure with --restart, as long as you still have the jobstore ๐Ÿ’–:

(venv) $ toil-wdl-runner MitochondriaPipeline.wdl -i ExampleInputsMitochondriaPipeline.json --logInfo --container docker --outputFile mitochondria.json --jobStore mitochondriaJobstore --batchSystem slurm

๐Ÿซง Example: sorting

For a more detailed example and explanation, we've built a sample pipeline that merge-sorts a temporary file ๐Ÿงš. This is not supposed to be an efficient sorting program. It's more of a fully worked example of what Toil is capable of ๐Ÿ’œ.

๐ŸŽ€ Running the example

  1. Download the example code ๐Ÿ“ฅ.
  2. Run it with the default settings:
$ python3 sort.py file:jobStore

Okay so the workflow just dropped a file called sortedFile.txt into your current directory ๐Ÿ“‚ Go peek at it, bestie, because it's literally full of sorted lines! ๐Ÿคฉ๐Ÿ’–

Lowkey the coolest part is that this workflow runs a smart merge sort on a file it generates, fileToSort.txt โœจ It's "smart" because every step (splitting the file into chunks ๐Ÿ”ช, sorting those chunks ๐Ÿงน, and merging them back together ๐Ÿซถ) gets its own little job. Each job can ask for its own resource requirements, and it only runs after the jobs it depends on have finished. Jobs with no dependencies? They run in parallel, no cap ๐Ÿ”ฅ

๐Ÿ’… Note: Delete fileToSort.txt before moving on to #3. This example adds options that set the size of fileToSort.txt, but only if it doesn't already exist yet. If it does exist, the workflow just uses that file, and you'll get the same results as #2.

3. Run with custom options ๐ŸŽ€

$ python3 sort.py file:jobStore \
             --numLines=5000 \
             --lineLength=10 \
             --overwriteOutput=True \
             --workDir=/tmp/

Here we see that we can add our own options to a Toil Python workflow ๐Ÿฆ‹ As we mentioned above, the first two options, --numLines and --lineLength, decide how many lines there are and how many characters go in each line. --overwriteOutput makes the current contents of sortedFile.txt get overwritten, if it already exists. The last option, --workDir, is one that's built into Toil, and it's where the temporary files unique to each job are kept ๐Ÿงš


๐Ÿ” Describing the source code ๐Ÿ”

Want to know what's actually happening under the hood? ๐Ÿ‘€ Let's start with the main() function. It looks like a LOT of code, but don't worry, we'll break it down piece by piece ๐Ÿงฉ

def main(options=None):
    if not options:
        # deal with command line arguments
        parser = ArgumentParser()
        Job.Runner.addToilOptions(parser)
        parser.add_argument(
            "--numLines",
            default=defaultLines,
            help="Number of lines in file to sort.",
            type=int,
        )
        parser.add_argument(
            "--lineLength",
            default=defaultLineLen,
            help="Length of lines in file to sort.",
            type=int,
        )
        parser.add_argument("--fileToSort", help="The file you wish to sort")
        parser.add_argument("--outputFile", help="Where the sorted output will go")
        parser.add_argument(
            "--overwriteOutput",
            help="Write over the output file if it already exists.",
            default=True,
        )
        parser.add_argument(
            "--N",
            dest="N",
            help="The threshold below which a serial sort function is used to sort file. "
            "All lines must of length less than or equal to N or program will fail",
            default=10000,
        )
        parser.add_argument(
            "--downCheckpoints",
            action="store_true",
            help="If this option is set, the workflow will make checkpoints on its way through"
            'the recursive "down" part of the sort',
        )
        parser.add_argument(
            "--sortMemory",
            dest="sortMemory",
            help="Memory for jobs that sort chunks of the file.",
            default=None,
        )

        parser.add_argument(
            "--mergeMemory",
            dest="mergeMemory",
            help="Memory for jobs that collate results.",
            default=None,
        )

        options = parser.parse_args()
    if not hasattr(options, "sortMemory") or not options.sortMemory:
        options.sortMemory = sortMemory
    if not hasattr(options, "mergeMemory") or not options.mergeMemory:
        options.mergeMemory = sortMemory

    # do some input verification
    sortedFileName = options.outputFile or "sortedFile.txt"
    if not options.overwriteOutput and os.path.exists(sortedFileName):
        print(
            f"Output file {sortedFileName} already exists.  "
            f"Delete it to run the sort example again or use --overwriteOutput=True"
        )
        exit()

    fileName = options.fileToSort
    if options.fileToSort is None:
        # make the file ourselves
        fileName = "fileToSort.txt"
        if os.path.exists(fileName):
            print(f"Sorting existing file: {fileName}")
        else:
            print(
                f"No sort file specified. Generating one automatically called: {fileName}."
            )
            makeFileToSort(
                fileName=fileName, lines=options.numLines, lineLen=options.lineLength
            )
    else:
        if not os.path.exists(options.fileToSort):
            raise RuntimeError("File to sort does not exist: %s" % options.fileToSort)

    if int(options.N) <= 0:
        raise RuntimeError("Invalid value of N: %s" % options.N)

    # Now we are ready to run
    with Toil(options) as workflow:
        sortedFileURL = "file://" + os.path.abspath(sortedFileName)
        if not workflow.options.restart:
            sortFileURL = "file://" + os.path.abspath(fileName)
            sortFileID = workflow.importFile(sortFileURL)
            sortedFileID = workflow.start(
                Job.wrapJobFn(
                    setup,
                    sortFileID,
                    int(options.N),
                    options.downCheckpoints,
                    options=options,
                    memory=sortMemory,
                )
            )
        else:
            sortedFileID = workflow.restart()
        workflow.exportFile(sortedFileID, sortedFileURL)

First we make a parser to process command line arguments using the argparse module (https://docs.python.org/2.7/library/argparse.html) ๐Ÿ› ๏ธ It's really important that we add the call to Job.Runner.addToilOptions() so the parser gets initialized with all of Toil's default options. Then we add the command line arguments unique to this workflow, and parse the input. The help message listed with each argument should give you a pretty good idea of what it can do ๐Ÿ’œ

Next we do a little bit of input verification ๐Ÿ•ต๏ธโ€โ™€๏ธ The option --fileToSort lets you specify a file that needs to be sorted. If that option isn't given, this is where we make our own file, with the call to makeFileToSort().

Finally we get to the context manager that initializes the workflow ๐ŸŽ‰ We create a path to the input file, prepended with file:// as per the documentation for toil.common.Toil() (#toil.common.Toil), when staging a file that is stored locally. Notice that we have to check whether or not the workflow is restarting, so that we don't import the file more than once. Then we can kick off the workflow by calling toil.common.Toil.start() (#toil.common.Toil.start) on the job setup. When the workflow ends, we capture its output (the sorted file's fileID) and use that in toil.common.Toil.exportFile() (#toil.common.Toil.exportFile) to move the sorted file from the job store back into "userland" ๐Ÿก

Next let's look at the job that begins the actual workflow, setup ๐ŸŒธ

def setup(job, inputFile, N, downCheckpoints, options):
    """
    Sets up the sort.
    Returns the FileID of the sorted file
    """
    RealtimeLogger.info("Starting the merge sort")
    return job.addChildJobFn(
        down,
        inputFile,
        N,
        "root",
        downCheckpoints,
        options=options,
        preemptible=True,
        memory=sortMemory,
    ).rv()

setup really only does two things ๐Ÿ™Œ First it writes to the logs using Job.log(), and then it calls addChildJobFn(). Child jobs run directly after the current job. This function turns the 'job function' down into an actual job and passes in the inputs, including an optional resource requirement, memory. The job doesn't actually get run until the call to Job.rv(). Once the job down finishes, its output is returned here ๐Ÿฆ‹

Now we can look at what down does ๐Ÿ‘€

def down(job, inputFileStoreID, N, path, downCheckpoints, options, memory=sortMemory):
    """
    Input is a file, a subdivision size N, and a path in the hierarchy of jobs.
    If the range is larger than a threshold N the range is divided recursively and
    a follow on job is then created which merges back the results else
    the file is sorted and placed in the output.
    """

    RealtimeLogger.info("Down job starting: %s" % path)
    # Read the file
    inputFile = job.fileStore.readGlobalFile(inputFileStoreID, cache=False)
    length = os.path.getsize(inputFile)
    if length > N:
        # We will subdivide the file
        RealtimeLogger.critical(
            "Splitting file: %s of size: %s" % (inputFileStoreID, length)
        )
        # Split the file into two copies
        midPoint = getMidPoint(inputFile, 0, length)
        t1 = job.fileStore.getLocalTempFile()
        with open(t1, "w") as fH:
            fH.write(copySubRangeOfFile(inputFile, 0, midPoint + 1))
        t2 = job.fileStore.getLocalTempFile()
        with open(t2, "w") as fH:
            fH.write(copySubRangeOfFile(inputFile, midPoint + 1, length))
        # Call down recursively. By giving the rv() of the two jobs as inputs to the follow-on job, up,
        # we communicate the dependency without hindering concurrency.
        result = job.addFollowOnJobFn(
            up,
            job.addChildJobFn(
                down,
                job.fileStore.writeGlobalFile(t1),
                N,
                path + "/0",
                downCheckpoints,
                checkpoint=downCheckpoints,
                options=options,
                preemptible=True,
                memory=options.sortMemory,
            ).rv(),
            job.addChildJobFn(
                down,
                job.fileStore.writeGlobalFile(t2),
                N,
                path + "/1",
                downCheckpoints,
                checkpoint=downCheckpoints,
                options=options,
                preemptible=True,
                memory=options.mergeMemory,
            ).rv(),
            path + "/up",
            preemptible=True,
            options=options,
            memory=options.sortMemory,
        ).rv()
    else:
        # We can sort this bit of the file
        RealtimeLogger.critical(
            "Sorting file: %s of size: %s" % (inputFileStoreID, length)
        )
        # Sort the copy and write back to the fileStore
        shutil.copyfile(inputFile, inputFile + ".sort")
        sort(inputFile + ".sort")
        result = job.fileStore.writeGlobalFile(inputFile + ".sort")

    RealtimeLogger.info("Down job finished: %s" % path)
    return result

Okay so down is the recursive part of the workflow ๐Ÿ’… First we read the file into the local filestore by calling job.fileStore.readGlobalFile(). This drops a copy of the file into the temp directory for this particular job ๐Ÿ“‚, and that storage disappears once this job ends. For a detailed explanation of the filestore, the job store, and their interfaces, have a look at Managing files within a workflow (see #managingfiles).

Next, down checks the base case of the recursion: is the length of the input file less than N? (Remember, N was an option we added to the workflow in main.) In the base case, we just sort the file and return the file ID of this new sorted file โœจ.

If the base case fails, the file gets split into two new tempFiles using job.fileStore.getLocalTempFile() and the helper function copySubRangeOfFile. Then we add a follow-on Job called up with job.addFollowOnJobFn(). We've already seen child jobs, but a follow-on Job is a job that runs after the current job and all of its children (and their children and follow-ons) have completed. A follow-on makes total sense here because up is responsible for merging the files together, and we don't want to merge anything until we know it's sorted ๐Ÿซถ. Again, the return value of the follow-on job is requested using Job.rv().

Looking at up ๐Ÿ‘€

def up(job, inputFileID1, inputFileID2, path, options, memory=sortMemory):
    """
    Merges the two files and places them in the output.
    """

    RealtimeLogger.info("Up job starting: %s" % path)

    with job.fileStore.writeGlobalFileStream() as (fileHandle, outputFileStoreID):
        fileHandle = codecs.getwriter("utf-8")(fileHandle)
        with job.fileStore.readGlobalFileStream(inputFileID1) as inputFileHandle1:
            inputFileHandle1 = codecs.getreader("utf-8")(inputFileHandle1)
            with job.fileStore.readGlobalFileStream(inputFileID2) as inputFileHandle2:
                inputFileHandle2 = codecs.getreader("utf-8")(inputFileHandle2)
                RealtimeLogger.info(
                    "Merging %s and %s to %s"
                    % (inputFileID1, inputFileID2, outputFileStoreID)
                )
                merge(inputFileHandle1, inputFileHandle2, fileHandle)
        # Cleanup up the input files - these deletes will occur after the completion is successful.
        job.fileStore.deleteGlobalFile(inputFileID1)
        job.fileStore.deleteGlobalFile(inputFileID2)

        RealtimeLogger.info("Up job finished: %s" % path)

        return outputFileStoreID

Here we see the two input files getting merged together ๐Ÿ”ฅ, with the output written to a brand new file using job.fileStore.writeGlobalFileStream(). After a little cleanup, the output file is returned.

Once the final up finishes and all of the rv() promises are fulfilled, main receives the sorted file's ID, which it uses in exportFile to send it to the user ๐ŸŽ€.

There are other things in this example that we didn't go over, like Checkpoints (see #checkpoints) and the details of much of the Toil Class API (see #api) ๐Ÿงš.

At the end of the script, these lines:

if __name__ == '__main__'
    main()

are included to make sure the main function only runs once, in the '__main__' process that you, the user, invoked ๐Ÿ‘‘. In Toil terms, by running the script you created the leader process, which is where main() runs. A worker process is a separate process whose only job (pun intended ๐Ÿ’…) is hosting the execution of one or more jobs defined in that script. In any Toil workflow there is always one leader process and potentially many worker processes ๐ŸŒˆ.

When you use the single-machine batch system (the default), the worker processes run on the same machine as the leader process. With full-fledged batch systems like Kubernetes, the worker processes will typically be started on separate machines ๐Ÿฆ‹. The boilerplate makes sure the pipeline only starts once (on the leader) and not when its job functions get imported and executed on the individual workers. Iconic behaviour, honestly ๐Ÿ˜ญ.

Typing python3 sort.py --help will show the complete list of arguments for the workflow, which includes both Toil's arguments and the ones defined inside sort.py. A complete explanation of Toil's arguments can be found in Commandline Options (see #commandref) ๐Ÿ“–.


Logging ๐Ÿ“œ

By default, Toil logs a lot of information about the current environment, plus messages from the batch system and jobs ๐Ÿ™ˆ. You can configure this with the --logLevel flag. For example, to only log CRITICAL level messages to the screen:

$ python3 sort.py file:jobStore \
             --logLevel=critical \
             --overwriteOutput=True

This hides most of the information we get from the Toil run ๐Ÿคซ. For more detail, run the pipeline with --logLevel=debug to see a comprehensive output. For more information, see Commandline Options (see #workflowoptions) ๐Ÿ’œ.


Error Handling and Resuming Pipelines ๐Ÿ’€

With Toil, you can recover gracefully from a bug in your pipeline without losing any progress from jobs that already completed successfully ๐Ÿซถ. To show you how this works, let's add a bug to our example code and see how Toil handles the failure and how we can resume the pipeline afterwards. Add a bad assertion at line 52 of the example (the first line of down()):

def down(job, inputFileStoreID, N, downCheckpoints, memory=sortMemory):
    ...
    assert 1 == 2, "Test error!"

When we run the pipeline, Toil will show a detailed failure log with a traceback ๐Ÿ˜ฌ:

$ python3 sort.py file:jobStore
...
---TOIL WORKER OUTPUT LOG---
...
m/j/jobonrSMP    Traceback (most recent call last):
m/j/jobonrSMP      File "toil/src/toil/worker.py", line 340, in main
m/j/jobonrSMP        job._runner(jobGraph=jobGraph, jobStore=jobStore, fileStore=fileStore)
m/j/jobonrSMP      File "toil/src/toil/job.py", line 1270, in _runner
m/j/jobonrSMP        returnValues = self._run(jobGraph, fileStore)
m/j/jobonrSMP      File "toil/src/toil/job.py", line 1217, in _run
m/j/jobonrSMP        return self.run(fileStore)
m/j/jobonrSMP      File "toil/src/toil/job.py", line 1383, in run
m/j/jobonrSMP        rValue = userFunction(*((self,) + tuple(self._args)), **self._kwargs)
m/j/jobonrSMP      File "toil/example.py", line 30, in down
m/j/jobonrSMP        assert 1 == 2, "Test error!"
m/j/jobonrSMP    AssertionError: Test error!

If we try running the pipeline again, Toil will give us an error saying that a job store of the same name already exists. By default, when something fails, the job store is preserved so the workflow can be restarted from the previously failed jobs. We can restart the pipeline by running:

$ python3 sort.py file:jobStore \
             --restart \
             --overwriteOutput=True

We can also change the number of times Toil will attempt to retry a failed job:

$ python3 sort.py file:jobStore \
             --retryCount 2 \
             --restart \
             --overwriteOutput=True

You'll now see Toil attempt to rerun the failed job until it runs out of tries ๐Ÿ”. --retryCount is useful for non-systemic errors, like downloading a file that might hit a sporadic interruption, or some other non-deterministic failure.

To successfully restart our pipeline, we can edit our script to comment out line 30, or remove it entirely, and then run:

$ python3 sort.py file:jobStore \
             --restart \
             --overwriteOutput=True

The pipeline will run successfully, and the job store will be removed on the pipeline's completion ๐ŸŽ‰โœจ.


Collecting Statistics ๐Ÿ“Š

Please see the Status Command (see #cli-status) section for more on gathering runtime and resource info on jobs ๐Ÿ’–.


Launching a Toil Workflow in AWS โ˜๏ธ

After you've installed the aws extra for Toil during the Installation (see #installation-ref) and set up AWS (see Preparing your AWS environment, #prepareaws), you can run the basic helloWorld.py script (Running a basic Python workflow) on a VM in AWS just by modifying the run command ๐Ÿฆ‹๐ŸŒธ.

Okay so, on AWS you've got two options: run the workflow on a single instance, or run it on a cluster, which is basically a bunch of containers spread across multiple AWS instances ๐ŸŒธ. For the full tea on clusters, check out Running in AWS (#runningaws) ๐Ÿ’….

Also!! Don't forget the Destroy-Cluster Command (#destroycluster) when you're finished, bestie ๐Ÿ™ˆ. Otherwise things may not get cleaned up properly ๐Ÿ˜ญ.
  1. Launch a cluster in AWS with the Launch-Cluster Command (#launchcluster) โœจ:
$ toil launch-cluster <cluster-name> \
             --clusterType kubernetes \
             --keyPairName <AWS-key-pair-name> \
             --leaderNodeType t2.medium \
             --nodeTypes t2.medium -w 1 \
             --zone us-west-2a

The arguments keyPairName, leaderNodeType, and zone are required to launch a cluster ๐Ÿ”ฅ.

  1. Copy helloWorld.py to the /tmp directory on the leader node using the Rsync-Cluster Command (#rsynccluster) ๐Ÿฆ‹:
$ toil rsync-cluster --zone us-west-2a <cluster-name> helloWorld.py :/tmp

Note that the command needs you to define the file you're copying, plus the target location on the cluster leader node ๐ŸŽ€.

  1. Log in to the cluster leader node with the Ssh-Cluster Command (#sshcluster) ๐Ÿ’œ:
$ toil ssh-cluster --zone us-west-2a <cluster-name>

Note that this command will log you in as the root user ๐Ÿ‘‘.

  1. Run the workflow on the cluster ๐Ÿš€:
$ python3 /tmp/helloWorld.py aws:us-west-2:my-S3-bucket

In this particular case, we create an S3 bucket called my-S3-bucket in the us-west-2 availability zone to store intermediate job results ๐Ÿงš.

Along with some other INFO log messages, you should get the following output in your terminal window: Hello, world!, here's a message: You did it!. Slay ๐Ÿ’–.

  1. Exit from the SSH connection ๐Ÿ‘‹.
$ exit
  1. Use the Destroy-Cluster Command (#destroycluster) to destroy the cluster ๐Ÿงน:
$ toil destroy-cluster --zone us-west-2a <cluster-name>

Note that this command will destroy the cluster leader node and any resources created to run the job, including the S3 bucket ๐Ÿ’€.


โœจ Running a CWL Workflow on AWS โœจ

After you've installed the aws and cwl extras for Toil during the Installation (#installation-ref) and set up AWS (see Preparing your AWS environment (#prepareaws)), you can run a CWL workflow with Toil on AWS ๐ŸŒˆ.

Also!! Remember to use the Destroy-Cluster Command (#destroycluster) when you're finished, or things may not be cleaned up properly ๐Ÿ˜ญ.
  1. First, launch a node in AWS with the Launch-Cluster Command (#launchcluster) ๐ŸŽ€:
$ toil launch-cluster <cluster-name> \
             --clusterType kubernetes \
             --keyPairName <AWS-key-pair-name> \
             --leaderNodeType t2.medium \
             --nodeTypes t2.medium -w 1 \
             --zone us-west-2a
  1. Copy example.cwl and example-job.yaml from the CWL example to the node with the Rsync-Cluster Command (#rsynccluster) ๐Ÿฆ‹:
toil rsync-cluster --zone us-west-2a <cluster-name> example.cwl :/tmp
toil rsync-cluster --zone us-west-2a <cluster-name> example-job.yaml :/tmp
  1. SSH into the cluster's leader node with the Ssh-Cluster Command (#sshcluster) utility ๐Ÿ’œ:
$ toil ssh-cluster --zone us-west-2a <cluster-name>
  1. Once you're on the leader node, command line tools like kubectl will be available to you ๐Ÿง‘โ€๐Ÿ’ป. It's also a good idea to update and install the following ๐Ÿซถ:
sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get -y dist-upgrade
sudo apt-get -y install git
  1. Now create a new virtualenv with the --system-site-packages option and activate it ๐ŸŒธ:
virtualenv --system-site-packages venv
source venv/bin/activate
  1. Now run the CWL workflow with the Kubernetes batch system ๐Ÿ”ฅ:
(venv) $ toil-cwl-runner \
             --provisioner aws \
             --batchSystem kubernetes \
             --jobStore aws:us-west-2:any-name \
             /tmp/example.cwl /tmp/example-job.yaml
Tip: When running a CWL workflow on AWS, input files can be provided either on the local file system or in S3 buckets using s3:// URI references. Final output files will be copied to the local file system of the leader node ๐Ÿ“.
  1. Finally, log out of the leader node and from your local computer, then destroy the cluster ๐Ÿ’…:
$ toil destroy-cluster --zone us-west-2a <cluster-name>

โœจ Running a Workflow with Autoscaling - Cactus โœจ

Cactus (https://github.com/ComparativeGenomicsToolkit/cactus) is a reference-free, whole-genome multiple alignment program that can run on any of the cloud platforms Toil supports ๐Ÿงฌ.

Note: Cloud Independence ๐ŸŒˆ This example gives you a "cloud agnostic" view of running Cactus with Toil. Most options won't change between cloud providers. However, each provisioner has unique inputs for --leaderNodeType, --nodeType and --zone. We recommend the following: - --leaderNodeType (used in launch-cluster) โ€” AWS: t2.medium, Google: n1-standard-1 - --zone (used in launch-cluster) โ€” AWS: us-west-2a, Google: us-west1-a - --zone (used in cactus) โ€” AWS: us-west-2, Google: no value listed - --nodeType (used in cactus) โ€” AWS: c3.4xlarge, Google: n1-standard-8 When executing toil launch-cluster with gce specified for --provisioner, the option --boto must be specified and given a path to your .boto file. See Running in Google Compute Engine (GCE) (#runninggce) for more information about the --boto option ๐ŸŽ€.
Also!! Remember to use the Destroy-Cluster Command (#destroycluster) when you're finished, or things may not be cleaned up properly ๐Ÿ˜ญ.
  1. Download pestis.tar.gz ๐Ÿ“ฆ.
  2. Launch a cluster with the Launch-Cluster Command (#launchcluster) ๐Ÿš€:
$ toil launch-cluster <cluster-name> \
             --provisioner <aws, gce> \
             --keyPairName <key-pair-name> \
             --leaderNodeType <type> \
             --nodeType <type> \
             -w 1-2 \
             --zone <zone>
Note: A Helpful Tip ๐Ÿ’ก When using AWS, setting the environment variable eliminates having to specify the --zone option for each command. This will be supported for GCE in the future. $ export TOIL_AWS_ZONE=us-west-2c
  1. Create an appropriate directory for uploading files ๐Ÿ“:
$ toil ssh-cluster --provisioner <aws, gce> <cluster-name>
$ mkdir /root/cact_ex
$ exit
  1. Copy the required files up to the leader node ๐Ÿง. That means seqFile.txt (a text file containing the locations of the input sequences as well as their phylogenetic tree, see here (https://github.com/ComparativeGenomicsToolkit/cactus#seqfile-the-input-file)), the organisms' genome sequence files in FASTA format, and configuration files (e.g. blockTrim1.xml, if desired):
$ toil rsync-cluster --provisioner <aws, gce> <cluster-name> pestis-short-aws-seqFile.txt :/root/cact_ex
$ toil rsync-cluster --provisioner <aws, gce> <cluster-name> GCF_000169655.1_ASM16965v1_genomic.fna :/root/cact_ex
$ toil rsync-cluster --provisioner <aws, gce> <cluster-name> GCF_000006645.1_ASM664v1_genomic.fna :/root/cact_ex
$ toil rsync-cluster --provisioner <aws, gce> <cluster-name> GCF_000182485.1_ASM18248v1_genomic.fna :/root/cact_ex
$ toil rsync-cluster --provisioner <aws, gce> <cluster-name> GCF_000013805.1_ASM1380v1_genomic.fna :/root/cact_ex
$ toil rsync-cluster --provisioner <aws, gce> <cluster-name> setup_leaderNode.sh :/root/cact_ex
$ toil rsync-cluster --provisioner <aws, gce> <cluster-name> blockTrim1.xml :/root/cact_ex
$ toil rsync-cluster --provisioner <aws, gce> <cluster-name> blockTrim3.xml :/root/cact_ex
  1. Log in to the leader node ๐Ÿ”:
$ toil ssh-cluster --provisioner <aws, gce> <cluster-name>
  1. Set up the leader node's environment so it can run Cactus ๐Ÿงช:
$ bash /root/cact_ex/setup_leaderNode.sh
$ source cact_venv/bin/activate
(cact_venv) $ cd cactus
(cact_venv) $ pip install --upgrade .
  1. Run Cactus (https://github.com/ComparativeGenomicsToolkit/cactus) as an autoscaling workflow ๐Ÿฆ‹:
(cact_venv) $ cactus \
                  --retry 10 \
                  --batchSystem kubernetes \
                  --logDebug \
                  --logFile /logFile_pestis3 \
                  --configFile \
                  /root/cact_ex/blockTrim3.xml <aws, google>:<zone>:cactus-pestis \
                  /root/cact_ex/pestis-short-aws-seqFile.txt \
                  /root/cact_ex/pestis_output3.hal
Note: Pieces of the Puzzle ๐Ÿงฉ --logDebug โ€” equivalent to --logLevel DEBUG. --logFile /logFile_pestis3 โ€” writes logs in a file named logFile_pestis3 under / folder. --configFile โ€” this is not required, depending on whether a specific configuration file is intended to run the alignment.

<aws, google>:<zone>:cactus-pestis ๐Ÿชฃ this one makes a bucket called cactus-pestis with your cloud provider of choice, and it stores the intermediate job files and metadata. ๐Ÿ’… NOTE: if you want a GCE-based jobstore, bestie, you type google here, NOT gce. ๐Ÿ™ˆ

Your result file, pestis_output3.hal, gets saved under /root/cact_ex on the leader node. ๐Ÿฆ‹

Use cactus --help to see all the Cactus and Toil flags you can use. ๐ŸŒธ

  1. Log out of the leader node: ๐Ÿšช
(cact_venv) $ exit
  1. Download the finished output to your local machine: ๐Ÿ“ฅ
(venv) $ toil rsync-cluster \
             --provisioner <aws, gce> <cluster-name> \
             :/root/cact_ex/pestis_output3.hal \
             <path-of-folder-on-local-machine>
  1. Destroy the cluster, it's giving closure ๐Ÿ’€โœจ
(venv) $ toil destroy-cluster --provisioner <aws, gce> <cluster-name>

โœจ CWL IN TOIL โœจ

okay so the Common Workflow Language (CWL) is an emerging standard for writing workflows that are portable across multiple workflow engines and platforms. ๐ŸŒˆ Toil is literally obsessed with it and has full support for the CWL v1.0, v1.1, and v1.2 standards. ๐Ÿ‘‘

You can use Toil to run CWL workflows <#runcwl> or develop and test new ones. ๐Ÿงš


โœจ RUNNING CWL WORKFLOWS โœจ

The toil-cwl-runner command handles CWL parsing using cwltool, and it borrows the job-scheduling and batch system support from Toil. ๐Ÿ’– You can use it to run CWL workflows locally or out in the cloud. โ˜๏ธ

๐ŸŽ€ Running CWL Locally

To run in local batch mode, give it the CWL file and the input object file:

$ toil-cwl-runner example.cwl example-job.yml

For a simple example of CWL with Toil, check out Running a basic CWL workflow <#cwlquickstart>. ๐Ÿ“

๐Ÿ™ˆ Note for macOS + Docker + Toil

Okay, so when you're invoking CWL documents that use Docker containers and you see errors that look like this ๐Ÿ˜ญ

docker: Error response from daemon: Mounts denied:
The paths /var/...tmp are not shared from OS X and are not known to Docker.

you may need to add this ๐Ÿ‘‡

export TMPDIR=/tmp/docker_tmp

either in your startup file (.bashrc) or manually in your shell before you invoke toil. ๐Ÿ’…

๐Ÿ’… Detailed Usage Instructions

Need help? Just run this toil command and you'll get all the info ๐Ÿซถ:

$ toil-cwl-runner -h

A more detailed example shows how you can specify both Toil and cwltool arguments for your workflow, and it's so good:

$ toil-cwl-runner \
    --singularity \
    --jobStore my_jobStore \
    --batchSystem lsf \
    --workDir `pwd` \
    --outdir `pwd` \
    --logFile cwltoil.log \
    --writeLogs `pwd` \
    --logLevel DEBUG \
    --retryCount 2 \
    --maxLogFileSize 20000000000 \
    --stats \
    standard_bam_processing.cwl \
    inputs.yaml

In this example we set the following options, which are all passed to Toil: โœจ

  • --singularity โ€” tells Toil that every job with a Docker format container should run on the Singularity container engine instead of the Docker container engine. ๐Ÿ
  • --jobStore โ€” the path to a folder that doesn't exist yet. It'll hold the Toil jobstore and all the related job-tracking info. ๐Ÿ“‚
  • --batchSystem โ€” picks the HPC or Cloud-based cluster platform you want to use. โ˜๏ธ
  • --workDir โ€” the directory where all the temporary files for the workflow get created. A subdirectory of this becomes the $TMPDIR environment variable, and you can reference that subdirectory with the CWL parameter reference $(runtime.tmpdir) in CWL tools and workflows. ๐Ÿงธ
  • --outdir โ€” the directory where your final File and Directory outputs get written. References to these and other output types show up in the JSON object printed to the stdout stream after the workflow runs. ๐ŸŒท
  • --logFile โ€” the path to the main logfile. ๐Ÿ“
  • --writeLogs โ€” the directory where job logs get stored. At DEBUG log level, this includes logs for each Toil job run, plus stdout/stderr logs for each CWL CommandLineTool that didn't use the stdout/stderr directives to redirect output. ๐Ÿ”
  • --retryCount โ€” how many times to retry each Toil job. ๐Ÿ”
  • --maxLogFileSize โ€” logs that get bigger than this value get truncated. โœ‚๏ธ
  • --stats โ€” saves resource usages in json files, which you can collect with the toil stats command once the workflow is done. ๐Ÿ“Š

๐ŸŒธ Extra Toil CWL Options

Besides the normal Toil options and the options cwltool supports, toil-cwl-runner adds a few of its own, bestie:

  • --bypass-file-store โ€” skips Toil's file store system and assumes all paths are accessible in place from all nodes. This can dodge possibly-redundant file copies into Toil's job store storage, and it's required for CWL's InplaceUpdateRequirement. โš ๏ธ BUT it lets a failed job execution leave behind a partially-modified state, which means a restarted workflow might not work correctly. ๐Ÿ’€
  • --reference-inputs โ€” doesn't copy remote inputs into Toil's file store and assumes they're accessible in place from all nodes. ๐Ÿ“Œ
  • --disable-streaming โ€” doesn't allow streaming of job input files. By default, files marked with streamable True get streamed from remote job stores. ๐ŸŒŠ
  • --cwl-default-ram โ€” applies the CWL specification default ramMin. ๐Ÿง 
  • --no-cwl-default-ram โ€” does NOT apply the CWL specification default ramMin, so Toil --defaultMemory kicks in instead. This can help jobs get to Slurm with no memory limit assigned. ๐Ÿง
  • --cwl-min-ram BYTES โ€” sets a minimum memory allocation for all tasks. If --no-cwl-default-ram is passed, this doesn't apply to tools that don't specify a memory requirement, and --defaultMemory gets used for those tools instead. ๐ŸŽฏ

โ˜๏ธ Running CWL in the Cloud

To run in cloud and HPC configurations, you may need to give additional command line parameters to select and configure the batch system you want to use. ๐Ÿซง

To run a CWL workflow in AWS with toil, check out Running a CWL Workflow on AWS <#awscwl>. โœˆ๏ธ

๐Ÿ”ฅ Running CWL workflows with InplaceUpdateRequirement

Some CWL workflows use the InplaceUpdateRequirement feature, which requires that operations on files have visible side effects that Toil's file store can't support. ๐Ÿ˜ค If you need to run a workflow like this, make sure all your worker nodes have a shared filesystem, then use the --bypass-file-store option with toil-cwl-runner. This leaves all CWL intermediate files on disk and shares them between jobs using file paths, instead of storing them in the file store and downloading them whenever jobs need them. ๐Ÿ—‚๏ธ

๐Ÿ“ Toil & CWL Tips

๐Ÿ”Ž See logs for just one job by using the full log file

This requires knowing the job's toil-generated ID, which you can find in the log files. ๐Ÿชช

cat cwltoil.log | grep jobVM1fIs

๐Ÿงต Grep for full tool commands from toil logs

This gives you a more concise view of the commands being run. (Note that this info is only available from Toil when you run with --logDebug.) ๐Ÿ’…

pcregrep -M "\[job .*\.cwl.*$\n(.*        .*$\n)*" cwltoil.log
#         ^allows for multiline matching

๐ŸŽž๏ธ Find Bams that have been generated for a specific step while the pipeline is running

find . | grep -P '^./out_tmpdir.*_MD\.bam$'

๐Ÿงพ See what jobs have been run

cat log/cwltoil.log | grep -oP "\[job .*.cwl\]" | sort | uniq

or:

cat log/cwltoil.log | grep -i "issued job"

๐Ÿ“ก Get status of a workflow

$ toil status /home/johnsoni/TEST_RUNS_3/TEST_run/tmp/jobstore-09ae0acc-c800-11e8-9d09-70106fb1697e
<hostname> 2018-10-04 15:01:44,184 MainThread INFO toil.lib.bioio: Root logger is at level 'INFO', 'toil' logger at level 'INFO'.
<hostname> 2018-10-04 15:01:44,185 MainThread INFO toil.utils.toilStatus: Parsed arguments
<hostname> 2018-10-04 15:01:47,081 MainThread INFO toil.utils.toilStatus: Traversing the job graph gathering jobs. This may take a couple of minutes.

Of the 286 jobs considered, there are 179 jobs with children, 107 jobs ready to run, 0 zombie jobs, 0 jobs with services, 0 services, and 0 jobs with log files currently in file:/home/user/jobstore-09ae0acc-c800-11e8-9d09-70106fb1697e.

๐Ÿ“Š Toil Stats

You can get run statistics broken down by CWL file. โœจ This only works once the workflow is finished:

$ toil stats /path/to/jobstore

This reports resource usage information for all the CWL jobs the workflow executed. See Stats Command <#cli-stats> for an explanation of what the different fields mean. ๐Ÿง

๐Ÿชต Understanding toil log files

There's a worker_log.txt file for each Toil job. It gets written to while the job is running, and it's uploaded at the end if the job finishes or if you're running at debug log level. If it gets uploaded, the contents are printed to the main log file and transferred to a log file in the --logDir folder. ๐Ÿ—ƒ๏ธ

The new log file will be named something like:

CWLJob_<name of the CWL job>_<attempt number>.log

Standard output/error files will be named like:

<name of the CWL job>.stdout_<attempt number>.log

Say you have a workflow revsort.cwl with a step rev that calls the tool revtool.cwl. The CWL job name ends up being all those parts strung together with dots: revsort.cwl.rev.revtool.cwl. ๐Ÿงฉ


โœจ CWL CONFORMANCE โœจ

โš ๏ธ Note: To fully support inplace_update, --bypass-file-store should be enabled. See Running CWL workflows with InplaceUpdateRequirement <# inplaceupdaterequirement>.

The badges below show Toil's support for different aspects of the CWL specification. ๐Ÿ… They describe the current development version of Toil, not necessarily the release documented here. ๐Ÿ’œ

๐Ÿ’– CWL 1.2 Required Features

  • [image: required] [image]

๐ŸŒˆ CWL 1.2 Optional Features

  • [image: command_line_tool] [image]
  • [image: conditional] [image]
  • [image: docker] [image]
  • [image: expression_tool] [image]
  • [image: format_checking] [image]
  • [image: initial_work_dir] [image]
  • [image: inline_javascript] [image]
  • [image: inplace_update] [image]
  • [image: input_object_requirements] [image]
  • [image: json_schema_invalid] [image]
  • [image: load_listing] [image]
  • [image: multiple_input] [image]
  • [image: networkaccess] [image]
  • [image: resource] [image]
  • [image: scatter] [image]
  • [image: schema_def] [image]
  • [image: step_input] [image]
  • [image: timelimit] [image]
  • [image: workflow] [image]
  • [image: work_reuse] [image]

โœจ WDL IN TOIL โœจ

okay so bestie, the Workflow Description Language (WDL) <https://openwdl.org/> is a programming language built for writing workflows ๐Ÿ’… It runs a whole set of tasks in a pipeline spread across multiple computers, and it's giving reproducibility ๐Ÿงช You wrap up an entire sequence of commands, where the outputs feed into the next commands, into one workflow that runs the exact same way every single time. no cap, that's how scientific analyses stay reproducible ๐Ÿ”โœจ

Toil can run <#runwdl> WDL workflows and help you develop <#devwdl> them too ๐Ÿซถ The Toil team also maintains a set of WDL conformance tests <#conformancewdl> for checking how well Toil and other WDL runners behave ๐ŸŽ€


๐Ÿฆ‹ RUNNING WDL WORKFLOWS ๐Ÿฆ‹

Toil has beta support for running WDL workflows through the toil-wdl-runner command ๐ŸŒธ It comes with the [wdl] extra. If you don't have it yet, check out Installing Toil with Extra Features <#extras> to see how to install it ๐Ÿ’–

You can run WDL workflows with toil-wdl-runner ๐Ÿ’œ Under the hood, it uses MiniWDL <https://github.com/chanzuckerberg/miniwdl/#miniwdl> to parse and interpret the workflow, and it supports WDL 1.0 or later. Those workflows have to declare a version and use inputs and outputs sections, so keep that in mind bestie ๐Ÿ™ˆ

Tip: The last release of Toil that supported unversioned, draft-2 WDL workflows was 5.12.0 <https://github.com/DataBiosphere/toil/releases/tag/releases%2F5.12.0> ๐Ÿ“

Toil is a drop-in replacement for the Cromwell <https://github.com/broadinstitute/cromwell#readme> WDL runner, at least for compatible workflows โœจ So instead of running a workflow with Cromwell like this:

java -jar Cromwell.jar run myWorkflow.wdl --inputs myWorkflow_inputs.json

you can run the same workflow with toil-wdl-runner like this:

toil-wdl-runner myWorkflow.wdl --input myWorkflow_inputs.json

(We're using --input here with Toil, but it also accepts the Cromwell-style --inputs. iykyk ๐Ÿ‘‘)

By default, this runs on the current machine, with a job store in an automatically determined temporary location. But you can add a few Toil options to use other Toil-supported batch systems, like Kubernetes ๐Ÿงš

toil-wdl-runner --jobStore aws:us-west-2:wdl-job-store --batchSystem kubernetes myWorkflow.wdl --input myWorkflow_inputs.json

For Toil, --input is optional, and you can pass inputs as a positional argument instead ๐Ÿฆ‹

toil-wdl-runner myWorkflow.wdl myWorkflow_inputs.json

You can also run workflows straight from URLs! For example, to run the MiniWDL self test workflow, you can do this ๐ŸŒˆ

toil-wdl-runner https://raw.githubusercontent.com/DataBiosphere/toil/36b54c45e8554ded5093bcdd03edb2f6b0d93887/src/toil/test/wdl/miniwdl_self_test/self_test.wdl https://raw.githubusercontent.com/DataBiosphere/toil/36b54c45e8554ded5093bcdd03edb2f6b0d93887/src/toil/test/wdl/miniwdl_self_test/inputs.json

๐Ÿ’… Toil WDL Runner Options ๐Ÿ’…

  • --jobStore โ€” This is where Toil keeps its state info while the workflow runs. It has to be accessible from all machines, bestie ๐Ÿ 
  • -o, --outputDirectory โ€” The folder or URI prefix where workflow output files get saved. It defaults to a new directory in the current directory ๐Ÿ“‚
  • -m, --outputFile โ€” A JSON file name or URI where workflow output values get saved. It defaults to standard output ๐Ÿงพ
  • -i, --input, --inputs โ€” An alternative to the positional argument for the input JSON file. Mostly here so it plays nice with other WDL runners ๐Ÿค
  • --outputDialect โ€” Picks an output format dialect. Use cromwell to just return the workflow's output values as JSON, or miniwdl to nest them under an outputs key and include a dir key ๐Ÿ’โ€โ™€๏ธ
  • --referenceInputs โ€” Decides whether input files get passed around by URL reference instead of being imported into Toil's storage. It defaults to off, and it can be True or False or other similar words ๐Ÿ”—
  • --container โ€” Picks the container engine used to run tasks. By default it's auto, which tries Singularity if it's installed and Docker if it isn't. You can also set it to docker or singularity explicitly ๐Ÿณ
  • --allCallOutputs โ€” Decides whether outputs from all calls in a workflow get included alongside the outputs from the output section, when one is defined. For strict WDL spec compliance, set it to False. It usually defaults to False. But if the workflow includes metadata for the Cromwell Output Organizer (croo) <https://github.com/ENCODE-DCC/croo>, it defaults to True ๐Ÿ“ฆ
  • --strict โ€” Decides whether Toil should immediately exit on a lint warning. By default it's false ๐Ÿšจ
  • --quantCheck โ€” Decides whether quantifier validation type checking should be enabled. Turning it off is useful for workflows that Cromwell can run but that don't fully comply with the WDL spec. By default it's true โœ…
  • --runImportsOnWorkers โ€” Runs file imports on workers. This is handy if the leader isn't network optimized and a lot of downloads are needed. By default it's false ๐Ÿƒโ€โ™€๏ธ
  • --importWorkersBatchSize โ€” Requires --runImportsOnWorkers to be true. Sets the target batch size in bytes for batched imports. As many files as can fit go into each batch import job. This also accepts abbreviations, like G or Gi ๐Ÿ“ฆ
  • --importWorkersDisk โ€” Requires --runImportsOnWorkers to be true. Sets the disk size each import worker gets. You usually won't need to set this, because Toil will try to use file streaming when downloading files. If streaming isn't possible, for example when downloading from AWS to a GCE job store, set it to the largest file size of all the files to import. By default it's 1 MiB ๐Ÿ’พ

Any number of other Toil options may also be specified. For the defined Toil options, see Commandline Options <#commandref> ๐Ÿ“–


๐Ÿงพ Managing Workflow Logs ๐Ÿงพ

At the default settings, if a WDL task succeeds, its standard output and standard error get printed in the toil-wdl-runner output. The exception is when the workflow captures them with the stdout() and stderr() WDL built-in functions. If a WDL task fails, they get printed whether they were meant to be captured or not. Complete logs from Toil for failed jobs get printed too ๐Ÿ˜ญ

If you want to save logs organized by WDL task, use the --writeLogs or --writeLogsGzip options to specify a directory where the log files should go ๐Ÿ—‚๏ธ Log files get named after the same dotted, hierarchical workflow and task names used to set values from the input JSON. The only difference is that scatters add an extra numerical component. Toil job logs for failed jobs also show up here when you're running at the default log level ๐Ÿ’

For example, if you run:

toil-wdl-runner --writeLogs logs https://raw.githubusercontent.com/DataBiosphere/toil/36b54c45e8554ded5093bcdd03edb2f6b0d93887/src/toil/test/wdl/miniwdl_self_test/self_test.wdl https://raw.githubusercontent.com/DataBiosphere/toil/36b54c45e8554ded5093bcdd03edb2f6b0d93887/src/toil/test/wdl/miniwdl_self_test/inputs.json

You'll end up with a logs/ directory containing:

hello_caller.0.hello.stderr_000.log
hello_caller.1.hello.stderr_000.log
hello_caller.2.hello.stderr_000.log

That final number is a sequential counter ๐Ÿ”ข If a step has to be retried, or if you run the workflow multiple times without clearing out the logs directory, it goes up. lowkey satisfying ๐Ÿฅฐ


๐ŸŒท Enabling WDL Call Cache ๐ŸŒท

Toil can cache task and workflow outputs so it can reuse the outputs of tasks and workflows that already ran ๐Ÿง  This can save a ton of time when you're debugging a long running workflow where a later task fails. However, it's only guaranteed for running locally, and it can eat up a considerable amount of disk space ๐Ÿ’€

To use it, set these environment variables before running the workflow:

export MINIWDL__CALL_CACHE__PUT=True
export MINIWDL__CALL_CACHE__GET=True
export MINIWDL__CALL_CACHE__DIR=/absolute_path/to/cache

The path to the cache directory has to be an absolute path, so don't skip that part ๐Ÿซถ

For setting up the call cache permanently, check out the MiniWDL call cache <https://miniwdl.readthedocs.io/en/latest/runner_reference.html#call-cache> documentation ๐ŸŒˆ

โœจ DEVELOPING WDL WORKFLOWS โœจ

okay so Toil is a total dev tool for writing and testing WDL workflows locally ๐Ÿ’– Once your workflow slays on your machine, you can run it on Toil against a cloud or cluster backend, or take it to other WDL implementations like Terra (https://support.terra.bio/hc/en-us/sections/360004147011-Workflows), Cromwell (https://github.com/broadinstitute/cromwell#readme), or MiniWDL (https://github.com/chanzuckerberg/miniwdl/#miniwdl). Main character energy ๐Ÿ‘‘

๐Ÿ“– Learning WDL

To learn how to write WDL workflows in general, you should take the WDL Tutorial (<#tutorialwdl>) ๐ŸŽ€

There are other tutorials in the resources section (<resourcesWdl>) ๐ŸŒธ

๐Ÿ› Debugging WDL Workflows

When a WDL workflow breaks, lowkey a lot of the general Toil debugging strategies (<debugging>) are super helpful, like finding failed jobs with toil status --failed or running individual jobs locally with toil debug-job. These are way easier if you use a manually specified job store by passing --jobStore to toil-wdl-runner, so you have the job store path handy for the debugging tools ๐Ÿงฐ

There are also WDL-specific debugging strategies too ๐Ÿ’…

๐Ÿ“œ Reading WDL Workflow Logs

When a WDL workflow fails, you're likely to see a message like this ๐Ÿ˜ญ

WDL.runtime.error.CommandFailed: task command failed with exit status 1
[2023-07-16T16:23:54-0700] [MainThread] [E] [toil.worker] Exiting the worker because of a failed job on host phoenix-15.prism

This means the command line command from one of your WDL tasks exited with a failing (aka nonzero) exit code. That happens either when the command line command is written wrong, or when the error detection code in the tool you're trying to run catches something and reports an error ๐Ÿ™ˆ

Go up higher in the log until you find lines that look like:

[2024-01-16T20:12:19-0500] [Thread-3 (statsAndLoggingAggregator)] [I] [toil.statsAndLogging] hello_caller.0.hello.stderr follows:

And:

[2024-01-16T20:12:19-0500] [Thread-3 (statsAndLoggingAggregator)] [I] [toil.statsAndLogging] hello_caller.0.hello.stdout follows:

These will be followed by the standard error and standard output log data from the task's command. There may be useful info in there, like an error message from the underlying tool ๐Ÿ”

If you want individual task logs saved separately for later reference, you can use the --writeLogs option to specify a directory to store them in. For more info, see Managing Workflow Logs (<#logging>) ๐Ÿ“

๐Ÿ—‚๏ธ Finding Uploaded Files

If you want to find files that were uploaded from a WDL job, look for lines like this in the job's debug log (<debuggingLog>):

[2023-07-16T15:58:39-0700] [MainThread] [D] [toil.wdl.wdltoil] Virtualized /data/tmp/2846b6012e3e5535add03b363950dd78/cb23/197c/work/bamPerChrs/Sample.chr14.bam as WDL file toilfile:2703483274%3A0%3Afiles%2Ffor-job%2Fkind-WDLTaskJob%2Finstance-b4c5x6hq%2Ffile-c4e4f1b16ddf4c2ab92c2868421f3351%2FSample.chr14.bam/Sample.chr14.bam

If you're using a file job store, you can grab that long URI:

toilfile:2703483274%3A0%3Afiles%2Ffor-job%2Fkind-WDLTaskJob%2Finstance-b4c5x6hq%2Ffile-c4e4f1b16ddf4c2ab92c2868421f3351%2FSample.chr14.bam/Sample.chr14.bam

Then URL-decode it with, for example, https://www.urldecoder.io/, and you'll get this:

toilfile:2703483274:0:files/for-job/kind-WDLTaskJob/instance-b4c5x6hq/file-c4e4f1b16ddf4c2ab92c2868421f3351/Sample.chr14.bam/Sample.chr14.bam

Then take the part after the last colon:

files/for-job/kind-WDLTaskJob/instance-b4c5x6hq/file-c4e4f1b16ddf4c2ab92c2868421f3351/Sample.chr14.bam/Sample.chr14.bam

That's the path relative to the job store directory where this file can be found โœจ

Another approach is to use find -iname 'Sample.chr14.bam' on a file job store, if you know the name the file had when it was uploaded ๐Ÿ•ต๏ธ

๐Ÿ’ก Workflow Authoring Tips

Here are some tips for writing WDL workflows. You can also consult the OpenWDL Cookbook (https://github.com/openwdl/cookbook) ๐Ÿ“

๐Ÿ—‘๏ธ Deleting Files

WDL doesn't have a built-in way to delete files. If you run a task that deletes a file, it will still exist in Toil's job store storage ๐Ÿ’€

Toil recently gained support for deleting files at the end of WDL workflows. If you have a large file that you only need for part of your workflow, consider writing the part that creates and uses it as a separate child workflow and invoking it with call. Then the file gets cleaned up when the child workflow ends, leaving more space for files created in the parent workflow ๐Ÿงน

๐ŸŒ External WDL Resources

Here are some other resources a WDL developer might find useful ๐Ÿซถ

๐ŸŽ“ Official WDL Tutorials

You can also learn to write WDL workflows for Toil by following the official WDL quickstart guide (https://docs.openwdl.org/getting-started/quickstart.html) โœ๏ธ

Once you have your workflow .wdl file and your input .json, you can run the workflow on the inputs with toil-wdl-runner:

toil-wdl-runner myWorkflow.wdl --input myWorkflow_inputs.json

๐ŸŽฌ Learn WDL Video Tutorials

For people who prefer video tutorials, Lynn Langit has a Learn WDL Video Course (https://www.youtube.com/playlist?list=PL4Q4HssKcxYv5syJKUKRrD8Fbd-_CnxTM) that will teach you how to write and run WDL workflows. The course is taught using Cromwell, but Toil should also be compatible with the course's workflows ๐Ÿ“บ

๐Ÿ“š OpenWDL Cookbook

The OpenWDL Cookbook (https://github.com/openwdl/cookbook) contains example solutions to a variety of tricky workflow authoring problems ๐Ÿง 

๐Ÿ“ WDL Specifications

WDL language specifications can be found here: https://github.com/openwdl/wdl/blob/main/versions/1.1/SPEC.md

Toil is not yet fully conformant with the WDL specification (see WDL Conformance (<#conformancewdl>)), but it inherits most of the functionality of MiniWDL (https://github.com/chanzuckerberg/miniwdl/#miniwdl) ๐Ÿ’œ

๐Ÿซ UCSC Genomics Institute Wiki

The UCSC Genomics Institute (home of the Toil project) has tips on debugging WDL workflows with Toil (https://giwiki.gi.ucsc.edu/index.php?title=Phoenix_WDL_Tutorial#Debugging_Workflows). They're designed for one particular Slurm cluster environment, but might be applicable elsewhere ๐ŸŒˆ


โœจ WDL CONFORMANCE โœจ

The Toil team maintains a set of WDL Conformance Tests (https://github.com/DataBiosphere/wdl-conformance-tests). Much like the CWL Conformance Tests (https://github.com/common-workflow-language/cwl-v1.2/blob/main/CONFORMANCE_TESTS.md) for CWL, the WDL Conformance Tests are useful for figuring out if a WDL implementation actually follows the WDL specification (https://github.com/openwdl/wdl/blob/cb875867d86f868fa08f6eb2be179a50097ba440/versions/1.1/SPEC.md) ๐Ÿ”ฅ

The WDL Conformance Tests include a runner harness that can test toil-wdl-runner, as well as Cromwell and MiniWDL, and it supports testing conformance with the 1.1, 1.0, and draft-2 versions of WDL.

If you want to evaluate Toil's WDL conformance for yourself, first make sure you have toil-wdl-runner installed. It comes with the [wdl] extra; see Installing Toil with Extra Features (<#extras>) ๐Ÿงฉ

Then, check out the test repository:

$ git clone https://github.com/DataBiosphere/wdl-conformance-tests
$ cd wdl-conformance-tests

Most tests need a Docker daemon available, so make sure yours is working properly:

$ docker info
$ docker run --rm docker/whalesay cowsay "Docker is working"

Then you can test toil-wdl-runner against a particular WDL spec version, say 1.1:

$ python3 run.py --runner toil-wdl-runner --versions 1.1

For any failed tests, the test number and the log of the failing test will be reported ๐Ÿ™ˆ

After the tests run, you can clean up intermediate files with:

$ make clean

For more options, see:

$ python3 run.py --help

Or, consult the conformance test documentation (https://github.com/DataBiosphere/wdl-conformance-tests/tree/master#wdl-workflow-description-language-spec-conformance-tests) ๐Ÿ“–


โœจ WDL TUTORIAL โœจ

This tutorial will walk you through writing a workflow in WDL that you can run with Toil (<runWdl>). We're going to write a workflow for Fizz Buzz (https://en.wikipedia.org/wiki/Fizz_buzz) ๐ŸŽ€

โœ๏ธ Writing the File

Let's go step by step through the process of creating a single-file WDL workflow ๐Ÿฆ‹

๐Ÿท๏ธ Version

All WDL files need to start with a version statement (unless they're very old draft-2 files). Toil supports draft-2, WDL 1.0, and WDL 1.1, while Cromwell (another popular WDL runner used on Terra) supports only draft-2 and 1.0 ๐Ÿ’…

So let's start a new WDL 1.0 workflow. Open up a file named fizzbuzz.wdl and start with a version statement:

version 1.0

๐Ÿงบ Workflow Block

Then, add an empty workflow named FizzBuzz.

version 1.0
workflow FizzBuzz {
}

๐ŸŽ›๏ธ Input Block

Workflows usually need some kind of user input, so let's give our workflow an input section โœจ

version 1.0
workflow FizzBuzz {
    input {
        # How many FizzBuzz numbers do we want to make?
        Int item_count
        # Every multiple of this number, we produce "Fizz"
        Int to_fizz = 3
        # Every multiple of this number, we produce "Buzz"
        Int to_buzz = 5
        # Optional replacement for the string to print when a multiple of both
        String? fizzbuzz_override
    }
}

Notice that each input has a type, a name, and an optional default value. If the type ends in ?, the value is optional, and it may be null. If an input is not optional and there is no default value, then the user's inputs file must specify a value for it in order for the workflow to run ๐Ÿง

๐Ÿงฑ Body

Now we'll start on the body of the workflow, to be inserted just after the inputs section ๐Ÿ› ๏ธ

The first thing we're going to need to do is create an array of all the numbers up to the item_count. We can do this by calling the WDL range() function and assigning the result to an Array[Int] variable.

Array[Int] numbers = range(item_count)

WDL 1.0 has a wide variety of functions in its standard library (https://github.com/openwdl/wdl/blob/main/versions/1.0/SPEC.md#standard-library), and WDL 1.1 has even more ๐Ÿคฏ

๐Ÿ” Scattering

Once we create an array of all the numbers, we can use a scatter to operate on each one. WDL does not have loops; instead it has scatters, which work a bit like map() in Python. The body of the scatter runs for each value in the input array, all in parallel. We're going to increment all the numbers, since FizzBuzz starts at 1 but WDL range() starts at 0 ๐ŸŒธ

Array[Int] numbers = range(item_count)
scatter (i in numbers) {
    Int one_based = i + 1
}

๐Ÿ’– Conditionals ๐Ÿ’–

Okay so inside the body of the scatter, we're gonna throw in some conditionals to decide whether we spit out "Fizz", "Buzz", or "FizzBuzz" ๐Ÿ™ˆ. To support our fizzbuzz_override, we make an array of it plus a default value, then use the WDL select_first() function to grab the first non-null value in that array โœจ.

Each run of a scatter is allowed to declare variables, and outside the scatter those variables get squished together into arrays of all the results ๐Ÿงš. BUT each variable can only be declared once in the scatter, even with conditionals (rude, I know ๐Ÿ’€). So we use select_first() at the end and lean on the fact that variables from conditionals that never ran are null ๐Ÿฆ‹.

Note that WDL has conditional expressions with a then and an else, but conditional statements only have a body, no else branch ๐Ÿ˜ญ. If you need an else, you'll have to check the negated condition instead ๐Ÿ’….

So first, let's handle the special cases ๐Ÿ‘‘:

Array[Int] numbers = range(item_count)
scatter (i in numbers) {
    Int one_based = i + 1
    if (one_based % to_fizz == 0) {
        String fizz = "Fizz"
        if (one_based % to_buzz == 0) {
            String fizzbuzz = select_first([fizzbuzz_override, "FizzBuzz"])
        }
    }
    if (one_based % to_buzz == 0) {
        String buzz = "Buzz"
    }
    if (one_based % to_fizz != 0 && one_based % to_buzz != 0) {
        # Just a normal number.
    }
}

๐ŸŽ€ Calling Tasks ๐ŸŽ€

Now for the normal numbers, we need to turn our number into a string ๐Ÿ“. In WDL 1.1, and in WDL 1.0 on Cromwell, you can use a ${} substitution syntax in quoted strings anywhere, not just in command line commands. Toil technically will support this too, but it's not in the spec, and the tutorial needs an excuse for you to call a task ๐Ÿ™ˆ. So we're gonna insert a call to a stringify_number task, which we'll write later.

To call a task (or another workflow), we use a call statement and give it some inputs. Then we can fish the output values out of the task with . access, only if we don't make a noise instead ๐Ÿ™Š.

Array[Int] numbers = range(item_count)
scatter (i in numbers) {
    Int one_based = i + 1
    if (one_based % to_fizz == 0) {
        String fizz = "Fizz"
        if (one_based % to_buzz == 0) {
            String fizzbuzz = select_first([fizzbuzz_override, "FizzBuzz"])
        }
    }
    if (one_based % to_buzz == 0) {
        String buzz = "Buzz"
    }
    if (one_based % to_fizz != 0 && one_based % to_buzz != 0) {
        # Just a normal number.
        call stringify_number {
            input:
                the_number = one_based
        }
    }
    String result = select_first([fizzbuzz, fizz, buzz, stringify_number.the_string])
}

We can put the code into the workflow now, and set about writing the task ๐Ÿ’–.

version 1.0
workflow FizzBuzz {
    input {
        # How many FizzBuzz numbers do we want to make?
        Int item_count
        # Every multiple of this number, we produce "Fizz"
        Int to_fizz = 3
        # Every multiple of this number, we produce "Buzz"
        Int to_buzz = 5
        # Optional replacement for the string to print when a multiple of both
        String? fizzbuzz_override
    }
    Array[Int] numbers = range(item_count)
    scatter (i in numbers) {
        Int one_based = i + 1

        if (one_based % to_fizz == 0) {
            String fizz = "Fizz"
            if (one_based % to_buzz == 0) {
                String fizzbuzz = select_first([fizzbuzz_override, "FizzBuzz"])
            }
        }
        if (one_based % to_buzz == 0) {
            String buzz = "Buzz"
        }
        if (one_based % to_fizz != 0 && one_based % to_buzz != 0) {
            # Just a normal number.
            call stringify_number {
                input:
                    the_number = one_based
            }
        }
        String result = select_first([fizzbuzz, fizz, buzz, stringify_number.the_string]
    }
}

๐Ÿฆ‹ Writing Tasks ๐Ÿฆ‹

Our task should go after the workflow in the file. It looks a lot like a workflow, except it uses task โœจ.

task stringify_number {
}

We're gonna want it to take in an integer the_number, and we want it to output a string the_string. So let's fill that in with input and output sections ๐Ÿ’….

task stringify_number {
    input {
        Int the_number
    }
    # ???
    output {
        String the_string # = ???
    }
}

Now, unlike workflows, tasks can have a command section, which gives a command to run ๐Ÿ”ฅ. This section is now usually set off with triple angle brackets, <<< and >>>, and inside it you can use ~{}, which is Bash-like substitution but with a tilde, to place WDL variables into your command script ๐ŸŒธ. So let's add a command that echoes back the number so we can see it as a string.

task stringify_number {
    input {
        Int the_number
    }
    command <<<
       # This is a Bash script.
       # So we should do good Bash script things like stop on errors
       set -e
       # Now print our number as a string
       echo ~{the_number}
    >>>
    output {
        String the_string # = ???
    }
}

Now we need to capture the result of the command script. The WDL stdout() function returns a WDL File containing the standard output printed by the task's command ๐Ÿ˜ญ. We want to read that back into a string, which we can do with the WDL read_string() function. It also removes trailing newlines, per https://github.com/openwdl/wdl/blob/main/versions/1.0/SPEC.md#string-read_stringstringfile ๐Ÿซถ.

task stringify_number {
    input {
        Int the_number
    }
    command <<<
       # This is a Bash script.
       # So we should do good Bash script things like stop on errors
       set -e
       # Now print our number as a string
       echo ~{the_number}
    >>>
    output {
        String the_string = read_string(stdout())
    }
}

We're also gonna add a runtime section to our task to specify resource requirements ๐Ÿงš. We're also telling it to run in a Docker container, to make sure absolutely nothing can go wrong with our delicate echo command ๐Ÿ’€. In a real workflow you probably want to set up optional inputs for all the tasks so you can control the resource requirements, but here we'll just hardcode them ๐Ÿ™ˆ.

task stringify_number {
    input {
        Int the_number
    }
    command <<<
        # This is a Bash script.
        # So we should do good Bash script things like stop on errors
        set -e
        # Now print our number as a string
        echo ~{the_number}
    >>>
    output {
        String the_string = read_string(stdout())
    }
    runtime {
        cpu: 1
        memory: "0.5 GB"
        disks: "local-disk 1 SSD"
        docker: "ubuntu:24.04"
    }
}

The disks section is a little weird ๐Ÿฅน. It isn't in the WDL spec, but Toil supports Cromwell-style strings that ask for a local-disk of a certain number of gigabytes, which may suggest that it be SSD storage.

Then we can put our task into our WDL file ๐Ÿ’–.

version 1.0
workflow FizzBuzz {
    input {
        # How many FizzBuzz numbers do we want to make?
        Int item_count
        # Every multiple of this number, we produce "Fizz"
        Int to_fizz = 3
        # Every multiple of this number, we produce "Buzz"
        Int to_buzz = 5
        # Optional replacement for the string to print when a multiple of both
        String? fizzbuzz_override
    }
    Array[Int] numbers = range(item_count)
    scatter (i in numbers) {
        Int one_based = i + 1
        if (one_based % to_fizz == 0) {
            String fizz = "Fizz"
            if (one_based % to_buzz == 0) {
                String fizzbuzz = select_first([fizzbuzz_override, "FizzBuzz"])
            }
        }
        if (one_based % to_buzz == 0) {
            String buzz = "Buzz"
        }
        if (one_based % to_fizz != 0 && one_based % to_buzz != 0) {
            # Just a normal number.
            call stringify_number {
                input:
                    the_number = one_based
            }
        }
        String result = select_first([fizzbuzz, fizz, buzz, stringify_number.the_string]
    }
}
task stringify_number {
    input {
        Int the_number
    }
    command <<<
        # This is a Bash script.
        # So we should do good Bash script things like stop on errors
        set -e
        # Now print our number as a string
        echo ~{the_number}
    >>>
    output {
        String the_string = read_string(stdout())
    }
    runtime {
        cpu: 1
        memory: "0.5 GB"
        disks: "local-disk 1 SSD"
        docker: "ubuntu:24.04"
    }
}

๐Ÿ‘‘ Output Block ๐Ÿ‘‘

Now the only thing missing is a workflow-level output section. Technically, in WDL 1.0 you aren't supposed to need this, but you do need it in 1.1, and Toil doesn't actually send your outputs anywhere yet if you don't have one ๐Ÿ˜ญ. So we're making one. We need to collect together all the strings that came out of the different tasks in our scatter into an Array[String] โœจ. We'll add the output section at the end of the workflow section, above the task ๐Ÿซถ.

version 1.0
workflow FizzBuzz {
    input {
        # How many FizzBuzz numbers do we want to make?
        Int item_count
        # Every multiple of this number, we produce "Fizz"
        Int to_fizz = 3
        # Every multiple of this number, we produce "Buzz"
        Int to_buzz = 5
        # Optional replacement for the string to print when a multiple of both
        String? fizzbuzz_override
    }
    Array[Int] numbers = range(item_count)
    scatter (i in numbers) {
        Int one_based = i + 1
        if (one_based % to_fizz == 0) {
            String fizz = "Fizz"
            if (one_based % to_buzz == 0) {
                String fizzbuzz = select_first([fizzbuzz_override, "FizzBuzz"])
            }
         }
        if (one_based % to_buzz == 0) {
            String buzz = "Buzz"
        }
        if (one_based % to_fizz != 0 && one_based % to_buzz != 0) {
            # Just a normal number.
            call stringify_number {
                input:
                    the_number = one_based
            }
        }
        String result = select_first([fizzbuzz, fizz, buzz, stringify_number.the_string]
    }
    output {
       Array[String] fizzbuzz_results = result
    }
}
task stringify_number {
    input {
        Int the_number
    }
    command <<<
        # This is a Bash script.
        # So we should do good Bash script things like stop on errors
        set -e
        # Now print our number as a string
        echo ~{the_number}
    >>>
    output {
        String the_string = read_string(stdout())
    }
    runtime {
        cpu: 1
        memory: "0.5 GB"
        disks: "local-disk 1 SSD"
        docker: "ubuntu:24.04"
    }
}

Okay so because result is defined inside a scatter, when we reference it outside the scatter it shows up as an array ๐Ÿซถ

๐Ÿš€ Running the Workflow

Now all that's left is to actually run it, bestie ๐Ÿ’… First, make an inputs file to specify the workflow inputs:

echo '{"FizzBuzz.item_count": 20}' >fizzbuzz.json

Then run it with Toil. If you're on a Slurm cluster and you're currently in a shared directory that's available on all your nodes, you can run:

toil-wdl-runner --jobStore ./fizzbuzz_store --batchSystem slurm --slurmTime 00:10:00 --caching false --batchLogsDir ./logs fizzbuzz.wdl fizzbuzz.json -o fizzbuzz_out -m fizzbuzz_out.json

Or if you want to run it locally, just do:

toil-wdl-runner fizzbuzz.wdl fizzbuzz.json -o fizzbuzz_out -m fizzbuzz_out.json

๐ŸŒธ Next Steps


โœจ INTRODUCTION โœจ

Toil runs basically everywhere, locally or in the cloud (#cloudoverview), specifically Amazon Web Services and Google Compute Engine. It also speaks two workflow DSLs, CWL (#cwl) and WDL (#wdl), plus plain Python workflows (see Developing a Python Workflow, #devpython) ๐ŸŒˆ

Toil is built in a modular way, so it can run on lots of different systems with different configurations. The three configurable pieces are:

  • Job Store ๐Ÿ“ฆ: a filepath or URL that hosts and centralizes all the files for a workflow, like a local folder or an AWS s3 bucket url.
  • Batch System ๐Ÿ–ฅ๏ธ: either a local single machine or one of the supported HPC environments (lsf, mesos, slurm, torque, htcondor, kubernetes, or grid_engine).
  • Provisioner โ˜๏ธ: only for running in the cloud. It decides which cloud provider supplies the instances that do the "work" of your workflow.

Job Store

The job store is a storage abstraction that holds all of the information used in a Toil run. It centralizes every file the jobs in the workflow use, plus the details of how far the run has progressed. If a workflow crashes or fails, the job store has everything it needs to resume with minimal repeated work ๐Ÿ”

Several different job stores are supported, including the file job store and cloud job stores. For info on developing job stores, see Job Store API (#jobstoreinterface).

File Job Store

The file job store is for local use. It keeps the workflow info in a directory on the machine where the workflow is launched. It's the simplest and most convenient job store for testing or small runs ๐ŸŽ€

For an example that uses the file job store, see Running a basic CWL workflow (#quickstart).

Cloud Job Stores

Toil currently supports these cloud storage systems as job stores:

  • AWS Job Store (#awsjobstore): an AWS S3 bucket formatted as aws:<zone>:<bucketname>, where only numbers, letters, and dashes are allowed in the bucket name. Example: aws:us-west-2:my-aws-jobstore-name.
  • Google Job Store (#googlejobstore): a Google Cloud Storage bucket formatted as gce:<zone>:<bucketname>, where only numbers, letters, and dashes are allowed in the bucket name. Example: gce:us-west2-a:my-google-jobstore-name.

These use cloud buckets to house all of the files. This is super useful when several different worker machines are all running jobs and need to access the same job store ๐Ÿซถ

Batch System

A Toil batch system is either a local single machine (one computer) or a currently supported cluster of computers (lsf, mesos, slurm, torque, htcondor, or grid_engine). These environments manage individual worker nodes under a leader node to process the work a workflow needs. The leader and its workers all coordinate their tasks and files through one centralized job store location.

For a more detailed description of the different batch systems, or info on developing them, see Batch System API (#batchsysteminterface).

Provisioner

The Toil provisioner is a tool set for running a Toil workflow on a particular cloud platform โ˜๏ธ

The Toil Cluster Utilities (#clusterutils) are the command line tools you use to provision nodes on your desired cloud platform. They let you launch nodes, ssh to the leader, and rsync files back and forth.

For detailed instructions on using the provisioner, see Running in AWS (#runningaws) or Running in Google Compute Engine (GCE) (#runninggce).


โœจ COMMANDLINE OPTIONS โœจ

Want to see every single one of Toil's commandline options? Quick way to do it is to run this on a workflow language front-end ๐Ÿ‘‘

$ toil-wdl-runner --help

Or for a Toil Python workflow:

$ python3 example.py --help

For a basic Toil workflow, there's exactly one mandatory argument: the job store. Everything else is optional ๐Ÿ’–

The Config File

Instead of typing out arguments on the command line every time, Toil lets you use a configuration file. Lowkey a lifesaver ๐Ÿ˜ญ

Options get applied with priority, in this order:

  1. Command line options
  2. Environmental Variables
  3. Config file values
    • a. Provided config file through --config
    • b. Default config value in $HOME/.toil/default.yaml
  4. Defaults

You can manually generate an example configuration file at any path you pick. To make one, run:

$ toil config [filename].yaml

Then uncomment whatever options you need and change or add values.

After editing the config file, you can run Toil with those settings by passing it on the command line:

$ python3 example.py --config=[filename].yaml

Alternatively, you can edit the default config file, which lives at $HOME/.toil/default.yaml ๐ŸŒธ

If you use CLI options in addition to the configuration file, the CLI options overwrite the configuration file options. For example:

$ python3 example.py --config=[filename].yaml --defaultMemory 80Gi
Heads up bestie โš ๏ธ this will result in a default memory per job of 80GiB no matter what's in the configuration file provided. The CLI wins every time.

The Job Store

Running Toil workflows requires a file path or URL pointing to a central location for all of the workflow's intermediate files: the job store ๐Ÿ“ฆ For toil-cwl-runner and toil-wdl-runner, a job store can often be selected automatically, or you can specify one with the --jobStore option. Toil Python workflows generally need the job store as a positional command line argument.

To run the Python quickstart (#pyquickstart) example, say you're on a node with a big /scratch volume. You can have the job store created there by running python3 HelloWorld.py /scratch/my-job-store, or more explicitly, python3 HelloWorld.py file:/scratch/my-job-store โœจ

Syntax for specifying different job stores:

  • Local: file:job-store-name
  • AWS: aws:region-here:job-store-name
  • Google: google:projectID-here:job-store-name

Different types of job store options can be found below ๐Ÿงš

Commandline Options

Core Toil Options

Options to specify the location of the Toil workflow and turn on stats collation about the performance of jobs ๐Ÿ“Š

  • --workDir WORKDIR โ€” Pick an absolute path to the directory where Toil's temporary files go. Standard output and error from batch system jobs land here too (unless --noStdOutErr is set), and a cache directory may live here as well. Temp files and folders go into a directory called toil-<workflowID> inside workDir. Toil generates the workflowID itself and reports it in the workflow logs. If you don't set this, the default comes from the TMPDIR, TEMP, and TMP variables via mkdtemp. For CWL, the temporary output directory is used instead (see CWL option --tmp-outdir-prefix). This directory needs to exist on all machines running jobs. If you want standard output and error from batch system jobs captured, it'll generally need to be on a shared file system. When sharing a cache between containers on a host, this directory must be shared between the containers too ๐Ÿ’…
  • --coordinationDir COORDINATION_DIR โ€” Pick an absolute path to the directory where Toil keeps its state and lock files. When sharing a cache between containers on a host, this directory must be shared between the containers ๐Ÿ”’
  • --noStdOutErr โ€” Don't capture standard output and error from batch system jobs ๐Ÿ™ˆ
  • --stats โ€” okay so this one saves stats about your toil workflow so you can pull them up later with toil stats ๐Ÿ“Šโœจ
  • --clean=STATE โ€” this decides whether the jobStore gets deleted when the program wraps up ๐Ÿงน Your choices are 'always', 'onError', 'never', or 'onSuccess'. Heads up, bestie: --stats needs info from the jobStore at the end, so with that flag on the jobStore is never deleted ๐Ÿซถ Wanna be able to restart the run? Go with 'never' or 'onSuccess' ๐Ÿ”„ The default is 'never' if stats is enabled, and 'onSuccess' otherwise ๐Ÿ’…
  • --cleanWorkDir STATE โ€” controls when the temporary worker directory gets cleaned up after a job finishes ๐Ÿ—‘๏ธ Choices: 'always', 'onError', 'never', or 'onSuccess'. Default = always.
โš ๏ธ WARNING: this one is really only for debugging, babe. Running a full pipeline with it changed could fill your disk with intermediate data ๐Ÿ’€
  • --clusterStats FILEPATH โ€” if enabled, it writes out JSON resource usage stats to a file ๐Ÿ“ The default spot is the current working directory, but you can pass an absolute path to pick exactly where the file lands ๐Ÿ—บ๏ธ This only applies when using scalable batch systems โœจ
  • --restart โ€” if you pass this, toil will try to restart the existing workflow at the location pointed to by --jobStore ๐Ÿ” If the workflow doesn't exist, it'll raise an exception ๐Ÿ™…โ€โ™€๏ธ

โœจ Logging Options โœจ

Okay so toil keeps stdout and stderr hidden by default ๐Ÿ™ˆ except when a job fails. Log levels follow priority from the logging module, so here's the vibe ๐Ÿ“š

  • --logOff โ€” only CRITICAL log messages show up ๐Ÿคซ Same as --logLevel=OFF or --logLevel=CRITICAL.
  • --logCritical โ€” only CRITICAL log messages show up ๐Ÿšจ Same as --logLevel=OFF or --logLevel=CRITICAL.
  • --logError โ€” only ERROR and CRITICAL messages show up ๐Ÿ˜ฌ Equivalent to --logLevel=ERROR.
  • --logWarning โ€” WARN, ERROR, and CRITICAL messages show up โš ๏ธ Equivalent to --logLevel=WARNING.
  • --logInfo โ€” all the non-debugging messages show up ๐Ÿ’ Equivalent to --logLevel=INFO.
  • --logDebug โ€” DEBUG messages and everything above them show up ๐Ÿ” Equivalent to --logLevel=DEBUG.
  • --logTrace โ€” TRACE messages and everything above them show up ๐Ÿฆ‹ Equivalent to --logLevel=TRACE.
  • --logLevel=LOGLEVEL โ€” pick your level! It can be set to OFF (or CRITICAL), ERROR, WARN (or WARNING), INFO, DEBUG, or TRACE ๐ŸŽ€
  • --logFile FILEPATH โ€” the file path where the logging output gets written ๐Ÿ“„
  • --rotatingLogging โ€” turns on rotating logging so your log files don't get too huge ๐Ÿ”„ (you set the size with --maxLogFileSize BYTESIZE).
  • --maxLogFileSize BYTESIZE โ€” the max size of a job log file you wanna keep, in bytes โœ‚๏ธ Bigger log files get truncated down to the last X bytes. Setting this to zero means no truncation at all ๐Ÿ™Œ Setting it to a negative value truncates from the beginning instead. Default=100MiB. This only sets the max size in bytes when --rotatingLogging is active.
  • --log-dir DIRPATH โ€” for CWL and local file system only ๐Ÿ“‚ Logs stdout and stderr (if the tool asks for stdout/stderr) into the DIRPATH.
  • --logColors BOOL โ€” turns colored logging on or off ๐ŸŒˆ Default=True.

โœจ Batch System Options โœจ

  • --batchSystem BATCHSYSTEM โ€” the type of batch system you wanna run your jobs with ๐Ÿ–ฅ๏ธ Default = single_machine.
  • --disableAutoDeployment โ€” this turns off auto-deployment of Toil Python workflows ๐Ÿ™…โ€โ™€๏ธ If True, the workflow's Python code has to be sitting in the same location on every single worker. Default = False.
  • --maxJobs MAXJOBS โ€” the max number of jobs you can submit to the backing scheduler at once ๐Ÿšฆ Not supported on Mesos or AWS Batch. Use 0 for unlimited. Defaults to unlimited.
  • --maxLocalJobs MAXLOCALJOBS โ€” the max number of housekeeping jobs that can run at the same time on your local system ๐Ÿงน Use 0 for unlimited. Defaults to the number of local cores.
  • --manualMemArgs โ€” skips the default arguments 'hv=MEMORY' & 'h_vmem=MEMORY' in the qsub call ๐Ÿ™…โ€โ™€๏ธ and relies on TOIL_GRIDGENGINE_ARGS to supply your own arguments instead. Requires that TOIL_GRIDGENGINE_ARGS be set.
  • --memoryIsProduct โ€” if your batch system understands requested memory as a product of the requested memory and the number of cores, set this flag so memory gets allocated properly ๐Ÿงฎ This is pretty common with grid engine clusters (Ex: SGE, PBS, Torque).
  • --runCwlInternalJobsOnWorkers โ€” decides whether CWL internal jobs (e.g. CWLScatter) run on the worker nodes instead of the primary node ๐Ÿƒโ€โ™€๏ธ If false (default), all of those jobs run on the primary node. Setting this to true can speed things up for very large workflows with lots of sub-workflows and/or scatters, as long as your worker pool is big enough ๐Ÿš€
  • --statePollingWait STATEPOLLINGWAIT โ€” how many seconds to wait before doing a scheduler query for job state โณ If you're still inside that waiting period, you get cached results. Only works for grid engine batch systems such as gridengine, htcondor, torque, slurm, and lsf.
  • --statePollingTimeout STATEPOLLINGTIMEOUT โ€” how many seconds to keep retrying against a broken scheduler ๐Ÿ”ง Only works for grid engine batch systems such as gridengine, htcondor, torque, slurm, and lsf.
  • --batchLogsDir BATCHLOGSDIR โ€” the directory the backing batch system logs into ๐Ÿ“’ It should be available on both the leader and the workers if the batch system writes logs to the worker machines' filesystems, which lots of HPC schedulers do. If unset, the Toil work directory gets used. Only works for grid engine batch systems such as gridengine, htcondor, torque, slurm, and lsf.
  • --mesosEndpoint MESOSENDPOINT โ€” the host and port of your Mesos server, separated by a colon ๐ŸŒ (default: <leader IP>:5050)
  • --mesosFrameworkId MESOSFRAMEWORKID โ€” use a specific Mesos framework ID ๐Ÿ†”
  • --mesosRole MESOSROLE โ€” use a Mesos role ๐Ÿ‘‘
  • --mesosName MESOSNAME โ€” the Mesos name to use ๐Ÿท๏ธ (default: toil)
  • --scale SCALE โ€” a scaling factor that changes the value of all submitted tasks' submitted cores ๐Ÿ“ Used in the single_machine batch system. It's super handy for running workflows on smaller machines than they were designed for, by setting a value less than 1. (default: 1)
  • --slurmAllocateMem SLURM_ALLOCATE_MEM โ€” if False, don't use --mem ๐Ÿฉน This is a workaround for Slurm clusters that reject jobs with memory allocations.
  • --slurmTime SLURM_TIME โ€” the Slurm job time limit, in [DD-]HH:MM:SS format โฐ
  • --slurmPartition SLURM_PARTITION โ€” the partition you wanna send Slurm jobs to ๐Ÿ—‚๏ธ
  • --slurmGPUPartition SLURM_GPU_PARTITION โ€” the partition to send Slurm jobs to if they ask for GPUs ๐ŸŽฎ
  • --slurmPE SLURM_PE โ€” a special partition to send Slurm jobs to if they ask for more than 1 CPU ๐Ÿ’œ Useful for Slurm clusters that don't offer a partition accepting both single-core and multi-core jobs.
  • --slurmArgs SLURM_ARGS โ€” extra arguments to pass along to Slurm โž•
  • --kubernetesHostPath KUBERNETES_HOST_PATH โ€” the path on Kubernetes hosts to use as a shared inter-pod temp directory ๐Ÿ“
  • --kubernetesOwner KUBERNETES_OWNER โ€” the username to mark Kubernetes jobs with ๐Ÿท๏ธ
  • --kubernetesServiceAccount KUBERNETES_SERVICE_ACCOUNT โ€” the service account to run jobs as ๐Ÿชช
  • --kubernetesPodTimeout KUBERNETES_POD_TIMEOUT โ€” how many seconds to wait for a scheduled Kubernetes pod to start running โŒ› (default: 120s)
  • --kubernetesPrivileged BOOL โ€” whether Kubernetes pods are allowed to run as privileged ๐Ÿ”“ This can be used to enable FUSE mounts for faster runtimes with Singularity. When launching Toil-managed clusters, this gets set to true by --allowFuse. (default: False)
  • --kubernetesPodSecurityContext KUBERNETES_POD_SECURITY_CONTEXT โ€” the path to a YAML defining a pod security context to apply to all pods ๐Ÿ“œ
  • --kubernetesSecurityContext KUBERNETES_SECURITY_CONTEXT โ€” the path to a YAML defining a security context to apply to all containers ๐Ÿ›ก๏ธ
  • --awsBatchRegion AWS_BATCH_REGION โ€” the AWS region holding the AWS Batch queue you're submitting to โ˜๏ธ
  • --awsBatchQueue AWS_BATCH_QUEUE โ€” the name or ARN of the AWS Batch queue you're submitting to ๐Ÿ“ฌ
  • --awsBatchJobRoleArn AWS_BATCH_JOB_ROLE_ARN โ€” the ARN of an IAM role to run AWS Batch jobs as ๐ŸŽญ so they can e.g. access a job store. It must be assumable by ecs-tasks.amazonaws.com.

โœจ Data Storage Options โœจ

Allows configuring Toil's data storage ๐Ÿ—„๏ธ

  • --symlinkImports BOOL โ€” with a filesystem-based job store, CWL input files get symlinked in by default ๐Ÿ”— Setting this to True copies the files into the job store instead, which may protect them from being modified externally. When set to False and caching is enabled, Toil protects the file automatically by changing its permissions to read-only ๐Ÿ”’ (Default=True)
  • --moveOutputs BOOL โ€” with a filesystem-based job store, output files get moved to the output directory by default, and a symlink to the moved file gets created at the original spot ๐Ÿšš Setting this to True copies the files into the output directory instead. Applies to filesystem-based job stores only. (Default=False)
  • --caching BOOL โ€” turns worker level file caching on or off ๐Ÿ’พ Set it to "true" if you want caching. By default, caching is enabled on supported batch systems. It doesn't affect CWL or WDL task caching.
  • --symlinkJobStoreReads BOOL โ€” bestie, this lets jobs read from a JobStore's shared filesystem, and do container mounts, directly through a symlink ๐Ÿ”—. If the shared filesystem can't handle every job hammering it at once, you can turn this off and use --caching=True so each node reads from its own local cache storage instead ๐Ÿซถ. (Default=True)

โœจ Autoscaling Options โœจ

This is where you set the minimum and maximum number of nodes in an autoscaled cluster, plus the knobs for how much it provisions ๐ŸŽ€.

  • --provisioner CLOUDPROVIDER โ€” the provisioner for cluster auto-scaling, and the main Toil --provisioner option ๐Ÿ’…. It defaults to None for running on single_machine and non-auto-scaling batch systems. The currently supported choices are 'aws' or 'gce'.
  • --nodeTypes NODETYPES โ€” a list of comma-separated node types, where each one is made of slash-separated instance types ๐Ÿฆ‹. You can add an optional spot bid after a colon, which makes that node type preemptible. Instance types can show up in multiple node types, and the same node type can be both preemptible and non-preemptible, no cap.
    • Valid argument specifying two node types: c5.4xlarge/c5a.4xlarge:0.42,t2.large
    • Node types: c5.4xlarge/c5a.4xlarge:0.42 and t2.large
    • Instance types: c5.4xlarge, c5a.4xlarge, and t2.large
    • Semantics: bid $0.42/hour for either c5.4xlarge or c5a.4xlarge instances, treated interchangeably, while they're available at that price, and buy t2.large instances at full price ๐Ÿ’ธ
  • --minNodes MINNODES โ€” the minimum number of nodes of each type in the cluster when auto-scaling ๐Ÿ“. Give it as a comma-separated list the same length as your list of node types. default=0
  • --maxNodes MAXNODES โ€” the maximum number of nodes of each type when autoscaling, also as a comma-separated list ๐Ÿงš. If the list is shorter than the number of nodeTypes, the first value is used as the default. default=10
  • --targetTime TARGETTIME โ€” how rapidly you aim to finish jobs, in seconds ๐Ÿ”ฅ. Shorter times mean more aggressive parallelization. The autoscaler scales up or down so it expects all queued jobs to finish within targetTime seconds. (Default: 1800)
  • --betaInertia BETAINERTIA โ€” a smoothing parameter that stops the number of provisioned nodes from wobbling around for no reason ๐ŸŒŠ. It controls an exponentially weighted moving average of the estimated number of nodes. A value of 0.0 disables smoothing completely, and a value of 0.9 smooths so much that hardly any changes ever get made. Must be between 0.0 and 0.9. (Default: 0.1)
  • --scaleInterval SCALEINTERVAL โ€” the gap in seconds between checks on whether the cluster's size needs to change โฐ. (Default: 60)
  • --preemptibleCompensation PREEMPTIBLECOMPENSATION โ€” how much the autoscaler prefers swapping in non-preemptible nodes when preemptible nodes can't be started for some reason ๐Ÿซถ. Defaults to 0.0, and it must be between 0.0 and 1.0, inclusive. A value of 0.0 turns compensation off, a value of 0.5 covers two missing preemptible nodes with one non-preemptible node, and a value of 1.0 replaces every missing preemptible node with a non-preemptible one.
  • --nodeStorage NODESTORAGE โ€” the size of the root volume of worker nodes when they launch, in gigabytes ๐Ÿ’พ. Set this if your jobs need a lot of disk space. The default value is 50.
  • --nodeStorageOverrides NODESTORAGEOVERRIDES โ€” a comma-separated list of nodeType:nodeStorage pairs that override the --nodeStorage default for the specified nodeType(s) ๐ŸŒˆ. This is super useful for heterogeneous jobs where some tasks need way more disk than others.
  • --metrics โ€” turns on the prometheus/grafana dashboard so you can watch CPU/RAM usage, queue size, and issued jobs ๐Ÿ“Š.
  • --assumeZeroOverhead โ€” ignores scheduler and OS overhead, and assumes jobs can use every last byte of memory and disk on a node when autoscaling ๐Ÿ™ˆ.

โœจ Service Options โœจ

This lets you cap the maximum number of service jobs in a cluster. Keeping it limited means nodes don't get clogged up with services, which can cause deadlocks ๐Ÿ”’. (Not for CWL).

  • --maxServiceJobs MAXSERVICEJOBS โ€” the max number of service jobs that can run concurrently, not counting ones on preemptible nodes ๐Ÿง. default=9223372036854775807
  • --maxPreemptibleServiceJobs MAXPREEMPTIBLESERVICEJOBS โ€” the max number of service jobs that can run concurrently on preemptible nodes ๐Ÿฆ‹. default=9223372036854775807
  • --deadlockWait DEADLOCKWAIT โ€” how many seconds the workflow can run only the same service jobs, with no jobs to use them, before it's declared deadlocked and stopped ๐Ÿ’€. default=60
  • --deadlockCheckInterval DEADLOCKCHECKINTERVAL โ€” how many seconds to wait between checks on whether the workflow is stuck running only service jobs with nothing to use them ๐Ÿง . It should be shorter than --deadlockWait. You might need to raise it if the batch system can't enumerate running jobs fast enough, or if polling for running jobs puts an unacceptable load on a shared cluster. default=30

โœจ Resource Options โœจ

These set the default cores/memory requirements (if the jobs don't specify their own), and let you limit the total memory/cores requested from the batch system ๐Ÿ’ช.

  • --defaultMemory INT โ€” the default amount of memory to request for a job ๐Ÿง . It only applies to jobs that don't set an explicit value for this requirement. Standard suffixes like K, Ki, M, Mi, G or Gi are supported. Default is 2.0Gi
  • --defaultCores FLOAT โ€” the default number of CPU cores to dedicate to a job โšก. It only applies to jobs without an explicit value for this requirement. Fractions of a core (like 0.1) work on some batch systems, namely Mesos and single_machine. Default is 1.0
  • --defaultDisk INT โ€” the default amount of disk space to dedicate to a job ๐Ÿ’ฝ. It only applies to jobs without an explicit value for this requirement. Standard suffixes like K, Ki, M, Mi, G or Gi are supported. Default is 2.0Gi
  • --defaultAccelerators ACCELERATOR โ€” the default amount of accelerators to request for a job ๐ŸŽฎ. It only applies to jobs without an explicit value for this requirement. Each accelerator spec can have a type (gpu [default], nvidia, amd, cuda, rocm, opencl, or a specific model like nvidia-tesla-k80), and a count [default: 1]. If you use both a type and a count, they must be separated by a colon. If you use multiple types of accelerators, separate the specs with commas. Default is [].
  • --defaultPreemptible BOOL โ€” makes all jobs able to run on preemptible (spot) nodes by default ๐Ÿฆ‹.
  • --maxCores INT โ€” the maximum number of CPU cores to request from the batch system at any one time ๐Ÿšง. Standard suffixes like K, Ki, M, Mi, G or Gi are supported.
  • --maxMemory INT โ€” the maximum amount of memory to request from the batch system at any one time ๐Ÿšง. Standard suffixes like K, Ki, M, Mi, G or Gi are supported.
  • --maxDisk INT โ€” the maximum amount of disk space to request from the batch system at any one time ๐Ÿšง. Standard suffixes like K, Ki, M, Mi, G or Gi are supported.

โœจ Options for rescuing/killing/restarting jobs โœจ

These are for jobs that run too long, fail, or get lost, because some batch systems have issues! ๐Ÿ™ƒ

  • --retryCount INT โ€” how many times to retry a failing job before giving up and labeling it failed ๐Ÿ”. default=1
  • --stopOnFirstFailure BOOL โ€” stops the workflow at the first complete job failure ๐Ÿ›‘.
  • --enableUnlimitedPreemptibleRetries โ€” if set, preemptible failures (or any failure caused by an instance getting unexpectedly terminated) won't count toward job failures or --retryCount ๐ŸŒธ.
  • --doubleMem โ€” if set, batch jobs that die from hitting the memory limit on batch schedulers get their memory doubled and are retried ๐Ÿ’ช. The remaining retry count is reduced by 1. Currently only supported by LSF. default=False.
  • --maxJobDuration INT โ€” the max runtime of a job in seconds before it gets killed โฑ๏ธ. This is a lower bound, so the actual time before the job is killed may be longer.
  • --rescueJobsFrequency INT โ€” how many seconds to wait between checks for missing or overlong jobs, meaning jobs the batch system lost ๐Ÿ•ต๏ธ. Expert parameter.
  • --jobStoreTimeout FLOAT โ€” the max number of seconds to wait for a job's update to the job store before declaring it failed ๐Ÿงƒ.

โœจ Log Management Options โœจ

  • --maxLogFileSize MAXLOGFILESIZE โ€” the max size of a job log file to keep, in bytes ๐Ÿ“œ. Log files bigger than this get truncated to the last X bytes. Setting this to zero prevents any truncation. Setting it to a negative value truncates from the beginning. Default=62.5 K
  • --writeLogs FILEPATH โ€” okay so this one takes the worker logs the leader collects and saves each into its own file at the path you give ๐Ÿ“. Any non-empty standard output and error from failed batch system jobs gets written into files at that path too ๐Ÿ’€. No path? The current working directory is used ๐ŸŒธ. Ngl, by default the leader only gets logs back from failed jobs ๐Ÿ™ˆ. If you want logs from successful jobs too, set the log level to 'debug' or turn on --writeLogsFromAllJobs, and tweak --maxLogFileSize to control the truncation limit for worker logs โœจ.
  • --writeLogsGzip FILEPATH โ€” literally the same energy as --writeLogs, except the log files get gzipped on the leader ๐ŸŽ.
  • --writeMessages FILEPATH โ€” the file where messages from the leader's message bus get sent ๐Ÿ“จ.
  • --realTimeLogging BOOL โ€” turns on real-time logging from workers to the leader โšก.

๐ŸŽ€ Miscellaneous Options ๐ŸŽ€

  • --disableChaining BOOL โ€” turns off job chaining ๐Ÿ”—. Chaining is when one job reuses its resource allocation for its successor job, if that's possible ๐Ÿซถ.
  • --disableJobStoreChecksumVerification โ€” turns off checksum verification for files moved to and from the job store ๐Ÿ™…. Checksum verification is a safety check that makes sure your data doesn't get corrupted during transfer ๐Ÿ›ก๏ธ. Currently only supported for non-streaming AWS files.
  • --sseKey SSEKEY โ€” give it the path to a file containing a 32 character key ๐Ÿ”. That key gets used for server-side encryption on awsJobStore or googleJobStore. SSE won't be used at all if you don't pass this flag ๐Ÿ’….
  • --setEnv NAME, -e NAME โ€” NAME=VALUE, NAME, -e NAME=VALUE, or just NAME are all valid, bestie ๐Ÿ’ซ. This sets an environment variable early on in the worker. If you leave out VALUE, it gets looked up in the current environment. Separately from this, the worker tries to emulate the leader's environment before running a job, except for some variables known to vary across systems ๐ŸŒˆ. With this option, a variable can be injected straight into the worker process itself before it starts ๐Ÿงš.
  • --servicePollingInterval SERVICEPOLLINGINTERVAL โ€” how long service jobs wait between checking whether the keep-alive flag exists โฐ (default=60)
  • --forceDockerAppliance โ€” disables the sanity check for whether the docker image specified by TOIL_APPLIANCE_SELF exists ๐Ÿณ. Toil uses that image to provision mesos for autoscaling, so this is the check you're skipping ๐Ÿ™ˆ.
  • --statusWait INT โ€” seconds to wait between reports of running jobs โณ (default=3600)
  • --disableProgress โ€” turns off the progress bar that shows up when standard error is a terminal ๐Ÿซ .
  • --publishWorkflowMetrics PUBLISHWORKFLOWMETRICS โ€” decides whether workflow metrics reports get published to Dockstore when a workflow completes ๐Ÿ“Š. Those reports include unique workflow and task run IDs, job names, and version and Toil feature use information. Selecting "current" publishes metrics for the current workflow. Selecting "all" also publishes prior workflow runs from the Toil history database, even if they were run with "no" ๐Ÿ‘‘.
โš ๏ธ Main character warning: once published, workflow metrics CANNOT be deleted or un-published. They will stay published forever! ๐Ÿ˜ญ

๐Ÿ” Debug Options ๐Ÿ”

Debug options for finding problems or helping with testing ๐Ÿ•ต๏ธโ€โ™€๏ธ.

  • --debugWorker โ€” an experimental no forking mode for local debugging ๐Ÿงช. Workers aren't forked, and stderr/stdout aren't redirected to the log. (default=False)
  • --disableWorkerOutputCapture โ€” lets worker output go to the worker's standard out/error instead of per-job logs ๐Ÿ“ฃ.
  • --badWorker BADWORKER โ€” for testing purposes, this randomly kills a --badWorker proportion of jobs using SIGKILL ๐Ÿ’€. (Default: 0.0)
  • --badWorkerFailInterval BADWORKERFAILINTERVAL โ€” when killing a job, it picks uniformly within the interval from 0.0 to --badWorkerFailInterval seconds after the worker starts ๐ŸŽฒ. (Default: 0.01)
  • --kill_polling_interval KILL_POLLING_INTERVAL โ€” the interval (in seconds) the leader waits between polling for the kill flag inside the job store. That flag is set by the "toil kill" command ๐Ÿชฆ. (default=5)

๐Ÿ”„ Restart Option ๐Ÿ”„

In the event of failure, Toil can resume the pipeline by adding the argument --restart and rerunning the workflow ๐Ÿ’–. Toil Python workflows (but not CWL or WDL workflows) can even be edited and resumed, which is super useful for development or troubleshooting ๐Ÿ› ๏ธ.

๐Ÿงธ Running Workflows with Services ๐Ÿงธ

Toil supports jobs, or clusters of jobs, that run as services to other accessor jobs. Example services include server databases or Apache Spark Clusters ๐Ÿฆ‹. Service jobs exist to provide services to accessor jobs, so their runtime depends on their accessor jobs running at the same time. Those dependencies can create potential deadlock scenarios ๐Ÿ˜ต. That's when the workflow hangs because only service jobs are running, and their accessor jobs can't be scheduled because resources are too limited to run both at once. Toil tries to schedule services and accessors intelligently, but to avoid a deadlock when running service jobs, it's advisable to use these parameters:

  • --maxServiceJobs: the maximum number of service jobs that can be run concurrently, excluding service jobs running on preemptible nodes.
  • --maxPreemptibleServiceJobs: the maximum number of service jobs that can run concurrently on preemptible nodes.

If you set these so that at a maximum cluster size there are enough resources to run accessors alongside services, a deadlock can't happen ๐Ÿ™Œ.

If too low a limit is specified, a deadlock can occur. Toil can't schedule enough service jobs at once to finish the workflow ๐Ÿฅฒ. Toil will detect this if it happens and throw a toil.DeadlockException exception. Increasing the cluster size and these limits will fix it ๐Ÿ’….

๐Ÿ Setting Options directly in a Python Workflow ๐Ÿ

It's good to remember that commandline options can be overridden in the code of a Python workflow ๐Ÿ’œ. For example, toil.job.Job.Runner.getDefaultOptions() can be used to get the default Toil options, ignoring what was passed on the command line. In this example, that's used to ignore command-line options and always run with the "./toilWorkflow" directory as the jobstore:

options = Job.Runner.getDefaultOptions("./toilWorkflow") # Get the options object

with Toil(options) as toil:
    toil.start(Job())  # Run the root job

However, each option can be explicitly set within the workflow by modifying the options object. In this example, we're setting logLevel = "DEBUG" (all log statements are shown) and clean="ALWAYS" (always delete the jobstore) like so:

options = Job.Runner.getDefaultOptions("./toilWorkflow") # Get the options object
options.logLevel = "DEBUG" # Set the log level to the debug level.
options.clean = "ALWAYS" # Always delete the jobStore after a run

with Toil(options) as toil:
    toil.start(Job())  # Run the root job

However, the usual incantation is to accept commandline args from the user with the following:

parser = Job.Runner.getDefaultArgumentParser() # Get the parser
options = parser.parse_args() # Parse user args to create the options object

with Toil(options) as toil:
    toil.start(Job())  # Run the root job

We can also have code in the workflow overwrite user supplied arguments:

parser = Job.Runner.getDefaultArgumentParser() # Get the parser
options = parser.parse_args() # Parse user args to create the options object
options.logLevel = "DEBUG" # Set the log level to the debug level.
options.clean = "ALWAYS" # Always delete the jobStore after a run

with Toil(options) as toil:
    toil.start(Job())  # Run the root job

๐Ÿงฐ TOIL UTILITIES ๐Ÿงฐ

Toil includes some utilities for inspecting or manipulating workflows during and after their execution ๐Ÿ”Ž. (There are additional Toil Cluster Utilities available for working with Toil-managed clusters in the cloud โ˜๏ธ.)

The generic toil subcommand utilities are:

  • stats โ€” reports runtime and resource usage for all jobs in a specified jobstore. The workflow must have originally been run using the --stats option ๐Ÿ“ˆ.
  • status โ€” inspects a job store to see which jobs have failed, run successfully, etc. ๐Ÿ‘€
  • debug-job โ€” runs a failing job on your local machine ๐Ÿง‘โ€๐Ÿ’ป.
  • clean โ€” deletes the job store used by a previous Toil workflow invocation ๐Ÿงน.
  • kill โ€” kills any running jobs in a rogue toil ๐Ÿšจ.

For information on a specific utility, run it with the --help option:

toil stats --help

๐Ÿ“Š Stats Command ๐Ÿ“Š

To use the stats command, a workflow must first be run using the --stats option. Using this command makes certain that toil does not delete the job store, no matter what other options are specified. Normally the option --clean=always would delete the job store, but --stats overrides this ๐Ÿ™Œ.

๐Ÿงช Running an Example ๐Ÿงช

We can run an example workflow and record stats:

python3 tutorial_stats.py file:my-jobstore --stats

Where tutorial_stats.py is the following:

import math
import time
from multiprocessing import Process

from toil.common import Toil
from toil.job import Job

def think(seconds):
    start = time.time()
    while time.time() - start < seconds:
        # Use CPU
        math.sqrt(123456)

class TimeWaster(Job):
    def __init__(self, time_to_think, time_to_waste, space_to_waste, *args, **kwargs):
        self.time_to_think = time_to_think
        self.time_to_waste = time_to_waste
        self.space_to_waste = space_to_waste
        super().__init__(*args, **kwargs)

    def run(self, fileStore):
        # Waste some space
        file_path = fileStore.getLocalTempFile()
        with open(file_path, "w") as stream:
            for i in range(self.space_to_waste):
                stream.write("X")
        # Do some "useful" compute
        processes = []
        for core_number in range(max(1, self.cores)):
            # Use all the assigned cores to think
            p = Process(target=think, args=(self.time_to_think,))
            p.start()
            processes.append(p)
        for p in processes:
            p.join()

        # Also waste some time
        time.sleep(self.time_to_waste)

def main():
    options = Job.Runner.getDefaultArgumentParser().parse_args()

    job1 = TimeWaster(0, 0, 0, displayName="doNothing")
    job2 = TimeWaster(10, 0, 4096, displayName="efficientJob")
    job3 = TimeWaster(10, 0, 1024, cores=4, displayName="multithreadedJob")
    job4 = TimeWaster(1, 9, 65536, displayName="inefficientJob")

    job1.addChild(job2)
    job1.addChild(job3)
    job3.addChild(job4)

    with Toil(options) as toil:
        if not toil.options.restart:
            toil.start(job1)
        else:
            toil.restart()

if __name__ == "__main__":
    main()

Notice the displayName key ๐Ÿ‘€, which can rename a job and give it an alias when it finally shows up in stats. So cute, right? ๐ŸŽ€


โœจ Displaying Stats โœจ

okay bestie, this part is my fave ๐Ÿ’–. To see the runtime and resources each job used when it ran, just type:

toil stats file:my-jobstore

It should spit out something like this ๐Ÿ“Š:

Batch System: single_machine
Default Cores: 1  Default Memory: 2097152KiB
Max Cores: unlimited
Local CPU Time: 55.54 coreยทs  Overall Runtime: 26.23 s
Worker
    Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
        n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
        3 |     0.34   10.83   10.80   21.23   32.40 |     0.33   10.43   17.94   43.07   53.83 |     0.01    0.40   14.08   41.85   42.25 |  177168Ki 179312Ki 178730Ki 179712Ki 536192Ki |      0Ki     4Ki    22Ki    64Ki    68Ki
Job
 Worker Jobs  |     min    med    ave    max
              |       1      1 1.3333      2
    Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
        n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
        4 |     0.33   10.83    8.10   10.85   32.38 |     0.33   10.43   13.46   41.70   53.82 |     0.01    1.68    2.78    9.02   11.10 |  177168Ki 179488Ki 178916Ki 179696Ki 715664Ki |      0Ki     4Ki    18Ki    64Ki    72Ki
 multithreadedJob
    Total Cores: 4.0
    Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
        n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
        1 |    10.85   10.85   10.85   10.85   10.85 |    41.70   41.70   41.70   41.70   41.70 |     1.68    1.68    1.68    1.68    1.68 |  179488Ki 179488Ki 179488Ki 179488Ki 179488Ki |      4Ki     4Ki     4Ki     4Ki     4Ki
 efficientJob
    Total Cores: 1.0
    Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
        n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
        1 |    10.83   10.83   10.83   10.83   10.83 |    10.43   10.43   10.43   10.43   10.43 |     0.40    0.40    0.40    0.40    0.40 |  179312Ki 179312Ki 179312Ki 179312Ki 179312Ki |      4Ki     4Ki     4Ki     4Ki     4Ki
 inefficientJob
    Total Cores: 1.0
    Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
        n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
        1 |    10.38   10.38   10.38   10.38   10.38 |     1.36    1.36    1.36    1.36    1.36 |     9.02    9.02    9.02    9.02    9.02 |  179696Ki 179696Ki 179696Ki 179696Ki 179696Ki |     64Ki    64Ki    64Ki    64Ki    64Ki
 doNothing
    Total Cores: 1.0
    Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
        n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
        1 |     0.33    0.33    0.33    0.33    0.33 |     0.33    0.33    0.33    0.33    0.33 |     0.01    0.01    0.01    0.01    0.01 |  177168Ki 177168Ki 177168Ki 177168Ki 177168Ki |      0Ki     0Ki     0Ki     0Ki     0Ki

This report tells you about the resources your workflow used ๐Ÿ“Š๐Ÿซถ. Heads up though: right now it does NOT track CPU and memory used inside Docker containers ๐Ÿณ๐Ÿ’€, only Singularity containers.

There are three parts to this report ๐ŸŽ€.

โœจ Overall Summary โœจ

At the top is a section with the overall summary stats for the run ๐Ÿ’…:

Batch System: single_machine
Default Cores: 1  Default Memory: 2097152KiB
Max Cores: unlimited
Local CPU Time: 55.54 coreยทs  Overall Runtime: 26.23 s

This lists some important settings for the Toil batch system that actually ran your jobs. It also gives you:

  • ๐Ÿง  The CPU time used on the local machine, in core seconds. This counts the Toil leader itself (excluding some startup time) and any jobs running under the leader, which for the single_machine batch system means every job. It does not include CPU used by jobs that ran on other machines.
  • โฑ๏ธ The overall wall-clock runtime of the workflow in seconds, as measured by the leader.

These last two numbers skip some startup and shutdown time spent loading and saving files, so you may still want to use the time shell built-in to time your Toil runs overall ๐Ÿ•ฐ๏ธ.

๐Ÿ‘‘ Worker Summary

After the overall summary, there's a section with stats about the Toil worker processes that Toil used to run your workflow's jobs ๐Ÿงš:

Worker
    Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
        n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
        3 |     0.34   10.83   10.80   21.23   32.40 |     0.33   10.43   17.94   43.07   53.83 |     0.01    0.40   14.08   41.85   42.25 |  177168Ki 179312Ki 178730Ki 179712Ki 536192Ki |      0Ki     4Ki    22Ki    64Ki    68Ki
  • ๐Ÿ”ข Count: this shows that Toil had to submit 3 Toil worker processes to the backing scheduler to run this workflow. (In this case, it ran them all on the local machine.)
  • โณ Real Time: stats about the wall clock times all the worker processes took. Every sub-column value is in seconds.
  • ๐Ÿงฎ CPU Time: stats about the CPU usage of all the worker processes. Every sub-column value is in core seconds.
  • ๐Ÿ˜ด CPU Wait: stats about CPU time that was reserved for worker processes but never actually used. Here, the max and total are pretty high compared to both real time and CPU time, which means a lot of reserved CPU went unused ๐Ÿ˜ญ. That can mean the workflow is overestimating how many cores it needs, that small jobs are running inside the same resource reservations as large jobs via chaining, or that the workflow is stuck waiting around for slow disk I/O.
  • ๐Ÿง  Memory: the peak memory usage of each worker process and its child processes.
  • ๐Ÿ’พ Disk: the disk usage in each worker. It's polled at the end of each job the worker runs, so it may not always show the actual peak disk usage.

๐Ÿฆ‹ Job Breakdown

Finally, there's the breakdown of resource usage by jobs. It starts with a table summarizing how many jobs ran on each worker:

Job
 Worker Jobs  |     min    med    ave    max
              |       1      1 1.3333      2

In this example, most workers ran one job each, but one worker managed to run two jobs through chaining ๐Ÿ”—. (Jobs chain when a job has only one dependent job, which in turn depends only on that first job, and the second job needs no more resources than the first job did.)

Next up, we have stats for resource usage across all jobs together ๐Ÿ’œ:

Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
    n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
    4 |     0.33   10.83    8.10   10.85   32.38 |     0.33   10.43   13.46   41.70   53.82 |     0.01    1.68    2.78    9.02   11.10 |  177168Ki 179488Ki 178916Ki 179696Ki 715664Ki |      0Ki     4Ki    18Ki    64Ki    72Ki

And finally, for each kind of job (as determined by the job's displayName), we get stats summarizing the resources used by the instances of that kind of job ๐ŸŒธ:

multithreadedJob
   Total Cores: 4.0
   Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
       n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
       1 |    10.85   10.85   10.85   10.85   10.85 |    41.70   41.70   41.70   41.70   41.70 |     1.68    1.68    1.68    1.68    1.68 |  179488Ki 179488Ki 179488Ki 179488Ki 179488Ki |      4Ki     4Ki     4Ki     4Ki     4Ki
efficientJob
   Total Cores: 1.0
   Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
       n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
       1 |    10.83   10.83   10.83   10.83   10.83 |    10.43   10.43   10.43   10.43   10.43 |     0.40    0.40    0.40    0.40    0.40 |  179312Ki 179312Ki 179312Ki 179312Ki 179312Ki |      4Ki     4Ki     4Ki     4Ki     4Ki
inefficientJob
   Total Cores: 1.0
   Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
       n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
       1 |    10.38   10.38   10.38   10.38   10.38 |     1.36    1.36    1.36    1.36    1.36 |     9.02    9.02    9.02    9.02    9.02 |  179696Ki 179696Ki 179696Ki 179696Ki 179696Ki |     64Ki    64Ki    64Ki    64Ki    64Ki
doNothing
   Total Cores: 1.0
   Count |                           Real Time (s)* |                        CPU Time (coreยทs) |                        CPU Wait (coreยทs) |                                    Memory (B) |                                 Disk (B)
       n |      min    med*     ave     max   total |      min     med     ave     max   total |      min     med     ave     max   total |       min      med      ave      max    total |      min     med     ave     max   total
       1 |     0.33    0.33    0.33    0.33    0.33 |     0.33    0.33    0.33    0.33    0.33 |     0.01    0.01    0.01    0.01    0.01 |  177168Ki 177168Ki 177168Ki 177168Ki 177168Ki |      0Ki     0Ki     0Ki     0Ki     0Ki

okay so for each job we slap its name up top ๐Ÿ’…, then the total cores it asked for (summed across every single instance of it ๐Ÿซถ), and then the stats table. โœจ

Here the * marker in the table headers is the main character ๐Ÿ‘‘. It shows that jobs are sorted by the median of the real time used. You can switch that up with the --sortCategory option ๐Ÿฆ‹.

The columns mean the same thing as they did for the workers, so here's the tea:

  • Count โ€” how many jobs of each type ran ๐ŸŒธ
  • Real Time โ€” stats on the wall clock times that instances of the job type took. All the sub-column values are in seconds โฑ๏ธ
  • CPU Time โ€” stats on the CPU usage amounts of each job. Lowkey iconic: multithreadedJob managed to use CPU time at faster than one core second per second ๐Ÿ”ฅ, because it reserved multiple cores and ran multiple threads
  • CPU Wait โ€” stats on CPU time that was reserved for but not consumed by jobs. Not me noticing inefficientJob used hardly any of the cores it requested for most of its real time ๐Ÿ’€
  • Memory โ€” the peak memory usage of each job ๐Ÿง 
  • Disk โ€” the disk usage at the end of each job. It may not always reflect the actual peak disk usage ๐Ÿ™ˆ

โœจ Example Cleanup โœจ

Once we're done looking at the stats, we can clean up the job store by running:

toil clean file:my-jobstore

๐Ÿ’– Status Command ๐Ÿ’–

Continuing the example from the stats section above, if we ran our workflow with the command:

python3 tutorial_stats.py file:my-jobstore --stats

we can poke at our jobstore with the status command, for example:

toil status file:my-jobstore

If the run was successful, this won't return much valuable info, something like:

2018-01-11 19:31:29,739 - toil.lib.bioio - INFO - Root logger is at level 'INFO', 'toil' logger at level 'INFO'.
2018-01-11 19:31:29,740 - toil.utils.toilStatus - INFO - Parsed arguments
2018-01-11 19:31:29,740 - toil.utils.toilStatus - INFO - Checking if we have files for Toil
The root job of the job store is absent, the workflow completed successfully.

Otherwise, toil status will return something like the following:

Of the 3 jobs considered, there are 1 completely failed jobs, 1 jobs
with children, 2 jobs ready to run, 0 zombie jobs, 0 jobs with
services, 0 services, and 0 jobs with log files currently in
FileJobStore(/Users/anovak/workspace/toil/tree).

The toil status command supports several useful flags, including:

  • --perJob to get per-job status information ๐ŸŽ€
  • --logs to print stored worker logs ๐Ÿ“œ
  • --failed to list all failed jobs in the workflow โŒ

For more info, run toil status --help ๐Ÿซถ.

One use case of toil status is the --printStatus argument. Running toil status --printStatus file:my-jobstore at any point in the workflow's lifecycle can tell you the progress of the workflow. Note: this command will output all current running jobs but not any finished or failed jobs ๐Ÿฆ‹.

For example, after running workflow.py in another terminal:

$ toil status --printStatus file:my-jobstore
[2024-05-31T13:59:13-0700] [MainThread] [I] [toil.utils.toilStatus] Traversing the job graph gathering jobs. This may take a couple of minutes.
Of the 2 jobs considered, there are 0 completely failed jobs, 1 jobs with children, 1 jobs ready to run, 0 zombie jobs, 0 jobs with services, 0 services, and 0 jobs with log files currently in FileJobStore(/path/to/my-jobstore).

Message bus path:  /tmp/tmp9cnaq3bm
Job ID kind-TimeWaster/instance-zvdsdkm_ with name TimeWaster is running on SingleMachineBatchSystem as ID 101349.
Job ID kind-TimeWaster/instance-7clm8cv2 with name TimeWaster is running on SingleMachineBatchSystem as ID 101350.

At this exact moment, two jobs named "TimeWaster" are running on my local machine ๐Ÿงš

๐Ÿงน Clean Command ๐Ÿงน

If a Toil pipeline didn't finish successfully, or it was run using --clean=always or --stats, the job store will stick around until it's deleted. toil clean <jobStore> makes sure all the artifacts associated with a job store are removed ๐Ÿซง. This is especially useful for deleting AWS job stores, which reserve an SDB domain as well as an S3 bucket.

The deletion of the job store can be changed with the --clean argument. It can be set to always, onError, never, or onSuccess (default) ๐Ÿ’….

Temporary directories where jobs are running can also be saved from deletion using --cleanWorkDir, which has the same options as --clean.

โš ๏ธ Only use --cleanWorkDir when debugging, bestie. Intermediate jobs will fill up disk space ๐Ÿ’€

๐Ÿ› Debug Job Command ๐Ÿ›

If a Toil workflow fails and it wasn't run with --clean=always, the failing job will be waiting in the job store to be debugged ๐Ÿ”. (With WDL or CWL workflows, you may have needed to manually set a --jobStore location you can find again.)

You can use toil debug-job on a job in the job store to run it on your local machine and reproduce any error that may have happened during a remote workflow ๐ŸŽ€.

The toil debug-job command takes a job store, plus the ID or name of a job in it. If multiple jobs match a job name, and only one seems to have run out of retries and completely failed, it'll run that one ๐Ÿ‘‘.

You can also pass the --printJobInfo flag to dump information about the job instead of running it ๐Ÿ“‹.

๐Ÿ›‘ Kill Command ๐Ÿ›‘

To kill all currently running jobs for a given jobstore, use the command:

toil kill file:my-jobstore

๐ŸŒธ TOIL DEBUGGING ๐ŸŒธ

Toil has a bunch of tools to help with debugging, and we're about to go through them together ๐Ÿซถ. Here we get into how to work through potential problems a user might run into while trying to run a workflow.

๐Ÿƒ Failing Fast ๐Ÿƒ

If you have a workflow you're testing, you can pass --stopOnFirstFailure=True to have Toil stop the workflow as soon as any job is completely failed (i.e. it runs out of retry attempts) ๐Ÿ›‘. If you don't want Toil to retry failing jobs at all, pass --retryCount=0 ๐Ÿ™…โ€โ™€๏ธ.

๐Ÿ“œ Reading the Log ๐Ÿ“œ

Usually, at the end of a failed Toil workflow, Toil will reproduce the job logs for the jobs that failed. You can look at the end of your workflow log and use those job logs to figure out which jobs are failing and why ๐Ÿ•ต๏ธโ€โ™€๏ธ.

๐Ÿ”Š Using DEBUG Logging ๐Ÿ”Š

When you're debugging a broken workflow, run it with --logDebug to set the log level to DEBUG ๐Ÿง .

When debug logging is on, the log from every Toil job gets inserted into the main Toil log between these markers:

=========>
     Toil job log is here
<=========

Normally, only the logs of failing jobs and the output of commands run from WDL get reproduced like this ๐Ÿ’….

๐Ÿ”Ž Finding Failed Jobs in the Jobstore ๐Ÿ”Ž

The toil status command (see Status Command above) can be used with the --failed option to list all failed jobs in a Toil job store ๐Ÿ“‹.

You can also use it with the --logs option to retrieve per-job logs from the job store, for failed jobs that left them behind. These logs might be super useful for diagnosing and fixing the problem ๐Ÿฉบ.

๐Ÿงช Running a Job Locally ๐Ÿงช

If you have a failing job's ID or name, you can reproduce its failure on your local machine with toil debug-job. See Debug Job Command above ๐Ÿซง.

For example, say you have this WDL workflow in test.wdl. This workflow cannot succeed, due to the typo in the echo command:

version 1.0
workflow test {
  call hello
}
task hello {
  input {
  }
  command <<<
    set -e
    echoo "Hello"
  >>>
  output {
  }
}

You could try to run it with:

toil-wdl-runner --jobStore ./store test.wdl --retryCount 0

But it will fail ๐Ÿ’€.

If you want to reproduce the failure later, or on another machine, you can first find out what jobs failed with toil status:

toil status --failed --noAggStats ./store

This will produce something like:

[2024-03-14T17:45:15-0400] [MainThread] [I] [toil.utils.toilStatus] Traversing the job graph gathering jobs. This may take a couple of minutes.
Failed jobs:
'WDLTaskJob' test.hello.command kind-WDLTaskJob/instance-r9u6_dcs v6

And we can see a failed job with the display name test.hello.command ๐Ÿ”. That tells you exactly where the job lives in the WDL workflow: the command section of the hello task, called from the test workflow. (If you're writing a Toil Python script, this is the job's displayName ๐Ÿ’….) We can rerun that job locally by name with:

toil debug-job ./store test.hello.command

If there were multiple failed jobs with that name (maybe because of a WDL scatter ๐Ÿ™ˆ), we'd have to pick one by Toil job ID instead:

toil debug-job ./store kind-WDLTaskJob/instance-r9u6_dcs

And if there's only one failed WDL task, we can just tell Toil to rerun the failed WDLTaskJob by its Python class name:

toil debug-job ./store WDLTaskJob

Any of these will run the job (containers included!) on your local machine, where you can watch it live or poke at it with a debugger ๐Ÿ”ฅ.


โœจ Fetching Job Inputs โœจ

The --retrieveTaskDirectory option to toil debug-job is so useful ๐Ÿ˜ญ. It lets you send a job's input files to a directory and then stops the job from running. It works for CWL and WDL jobs, and for Python workflows that call toil.job.Job.files_downloaded_hook() after downloading their files. It makes the worker work in the directory you specify, so the job's temporary directory ends up at worker/job inside it. For WDL and CWL jobs that mount files into containers, there's also an inside directory full of symlinks to the files as they'd look from the root of the container's filesystem ๐Ÿงš.

For example, say you have a broken WDL workflow named example_alwaysfail_with_files.wdl, like this:

version 1.0
workflow test {
    call make_file as f1
    call make_file as f2
    call hello {
        input:
            name_file=f1.out,
            unused_file=f2.out
    }
}
task make_file {
    input {
    }
    command <<<
        echo "These are the contents" >test.txt
    >>>
    output {
        File out = "test.txt"
    }
}
task hello {
    input {
        File name_file
        File? unused_file
    }
    command <<<
        set -e
        echoo "Hello" "$(cat ~{name_file})"
    >>>
    output {
        File out = stdout()
    }
}

You can try and fail to run it like this:

toil-wdl-runner --jobStore ./store example_alwaysfail_with_files.wdl --retryCount 0

If you dump the files from the failing job:

toil debug-job ./store WDLTaskJob --retrieveTaskDirectory dumpdir

You'll end up with a directory tree that, according to tree, looks something like this:

dumpdir
โ”œโ”€โ”€ inside
โ”‚   โ””โ”€โ”€ mnt
โ”‚       โ””โ”€โ”€ miniwdl_task_container
โ”‚           โ””โ”€โ”€ work
โ”‚               โ””โ”€โ”€ _miniwdl_inputs
โ”‚                   โ”œโ”€โ”€ 0
โ”‚                   โ”‚   โ””โ”€โ”€ test.txt -> ../../../../../../worker/job/2c6b3dc4-1d21-4abf-9937-db475e6a6bc2/test.txt
โ”‚                   โ””โ”€โ”€ 1
โ”‚                       โ””โ”€โ”€ test.txt -> ../../../../../../worker/job/e3d724e1-e6cc-4165-97f1-6f62ab0fb1ef/test.txt
โ””โ”€โ”€ worker
    โ””โ”€โ”€ job
        โ”œโ”€โ”€ 2c6b3dc4-1d21-4abf-9937-db475e6a6bc2
        โ”‚   โ””โ”€โ”€ test.txt
        โ”œโ”€โ”€ e3d724e1-e6cc-4165-97f1-6f62ab0fb1ef
        โ”‚   โ””โ”€โ”€ test.txt
        โ”œโ”€โ”€ tmpr2j5yaic
        โ”œโ”€โ”€ tmpxqr9__y4
        โ””โ”€โ”€ work

15 directories, 4 files

You can see where Toil downloaded the job's input files into the worker's temporary directory, and how they'd be mounted into the container ๐Ÿ’–.


โœจ Interactively Investigating Running Jobs โœจ

Say you have a broken WDL workflow that can't complete. Whenever you run tutorial_debugging_hangs.wdl, it hangs ๐Ÿ˜ญ:

version 1.1

workflow TutorialDebugging {

    input {
        Array[String] messages = ["Uh-oh!", "Oh dear", "Oops"]
    }

    scatter(message in messages) {

        call WhaleSay {
            input:
                message = message
        }

        call CountLines {
            input:
                to_count = WhaleSay.result
        }
    }

    Array[File] to_compress = flatten([CountLines.result, WhaleSay.result])

    call CompressFiles {
        input:
            files = to_compress
    }

    output {
        File compressed = CompressFiles.result
    }

}

# Draw ASCII art
task WhaleSay {
    input {
        String message
    }

    command <<<
        cowsay "~{message}"
    >>>

    output {
        File result = stdout()
    }

    runtime {
        container: "docker/whalesay"
    }
}

# Count the lines in a file
task CountLines {
    input {
        File to_count
    }

    command <<<
        wc -l ~{to_count}
    >>>

    output {
        File result = stdout()
    }

    runtime {
        container: ["ubuntu:latest", "https://gcr.io/standard-images/ubuntu:latest"]
    }
}

# Compress files into a ZIP
task CompressFiles {
    input {
        Array[File] files
    }

    command <<<
    set -e
    cat >script.py <<'EOF'
    import sys
    from zipfile import ZipFile
    import os

    # Interpret command line arguments
    to_compress = list(reversed(sys.argv[1:]))

    with ZipFile("compressed.zip", "w") as z:
        while to_compress != []:
            # Grab the file to add off the end of the list
            input_filename = to_compress[-1]
            # Now we need to write this to the zip file.
            # What internal filename should we use?
            basename = os.path.basename(input_filename)
            disambiguation_number = 0
            while True:
                target_filename = str(disambiguation_number) + basename
                try:
                    z.getinfo(target_filename)
                except KeyError:
                    # Filename is free
                    break
                # Otherwise try another name
                disambiguation_number += 1
            # Now we can actually make the compressed file
            with z.open(target_filename, 'w') as out_stream:
                with open(input_filename) as in_stream:
                    for line in in_stream:
                        # Prefix each line of text with the original input file
                        # it came from.
                        # Also remember to encode the text as the zip file
                        # stream is in binary mode.
                        out_stream.write(f"{basename}: {line}".encode("utf-8"))
    EOF
    python script.py ~{sep(" ", files)}
    >>>

    output {
        File result = "compressed.zip"
    }

    runtime {
        container: "python:3.11"
    }
}

You can try to run it like this, using Docker containers. Pretend this was actually a run on a large cluster ๐ŸŒˆ:

$ toil-wdl-runner --jobStore ./store tutorial_debugging_hangs.wdl --container docker

If you run this, it'll hang at the TutorialDebugging.CompressFiles.command step:

[2024-06-18T12:12:49-0400] [MainThread] [I] [toil.leader] Issued job 'WDLTaskJob' TutorialDebugging.CompressFiles.command kind-WDLTaskJob/instance-y0ga_907 v1 with job batch system ID: 16 and disk: 2.0 Gi, memory: 2.0 Gi, cores: 1, accelerators: [], preemptible: False

Workflow Progress  94%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–Ž| 15/16 (0 failures) [00:36<00:02, 0.42 jobs/s]

Say you want to find out why it's stuck. First, you need to kill the workflow. Open a new shell in the same directory and run:

# toil kill ./store

You can also hit Control+C in its terminal window and wait for it to stop.

Then you need to use toil debug-job to run the stuck job on your local machine:

$ toil debug-job ./store TutorialDebugging.CompressFiles.command

This produces some more informative logging messages, showing that the Docker container is managing to start up, but that it stays running indefinitely, with a repeating message:

[2024-06-18T12:18:00-0400] [MainThread] [N] [MiniWDLContainers] docker task running :: service: "lhui2bdzmzmg", task: "sg371eb2yk", node: "zyu9drdp6a", message: "started"
[2024-06-18T12:18:01-0400] [MainThread] [D] [MiniWDLContainers] docker task status :: Timestamp: "2024-06-18T16:17:58.545272049Z", State: "running", Message: "started", ContainerStatus: {"ContainerID": "b7210b346637210b49e7b6353dd24108bc3632bbf2ce7479829d450df6ee453a", "PID": 36510, "ExitCode": 0}, PortStatus: {}
[2024-06-18T12:18:03-0400] [MainThread] [D] [MiniWDLContainers] docker task status :: Timestamp: "2024-06-18T16:17:58.545272049Z", State: "running", Message: "started", ContainerStatus: {"ContainerID": "b7210b346637210b49e7b6353dd24108bc3632bbf2ce7479829d450df6ee453a", "PID": 36510, "ExitCode": 0}, PortStatus: {}
[2024-06-18T12:18:04-0400] [MainThread] [D] [MiniWDLContainers] docker task status :: Timestamp: "2024-06-18T16:17:58.545272049Z", State: "running", Message: "started", ContainerStatus: {"ContainerID": "b7210b346637210b49e7b6353dd24108bc3632bbf2ce7479829d450df6ee453a", "PID": 36510, "ExitCode": 0}, PortStatus: {}
...

This also gives you the Docker container ID of the running container, b7210b346637210b49e7b6353dd24108bc3632bbf2ce7479829d450df6ee453a. You can use that to get a shell inside the running container ๐Ÿ•ต๏ธโ€โ™€๏ธ:

$ docker exec -ti b7210b346637210b49e7b6353dd24108bc3632bbf2ce7479829d450df6ee453a bash
root@b7210b346637:/mnt/miniwdl_task_container/work#

Your shell is already in the working directory of the task, so we can inspect the files there to get an idea of how far it's gotten. Has it managed to create script.py? Has the script managed to create compressed.zip? Let's check ๐Ÿ‘€:

# ls -lah
total 6.1M
drwxrwxr-x 6 root root  192 Jun 18 16:17 .
drwxr-xr-x 3 root root 4.0K Jun 18 16:17 ..
drwxr-xr-x 3 root root   96 Jun 18 16:17 .toil_wdl_runtime
drwxrwxr-x 8 root root  256 Jun 18 16:17 _miniwdl_inputs
-rw-r--r-- 1 root root 6.0M Jun 18 16:23 compressed.zip
-rw-r--r-- 1 root root 1.3K Jun 18 16:17 script.py

So we can see that the script exists, and the zip file also exists ๐Ÿ“‚โœจ bestie, so maybe the script is still running?? We can check with ps, but we need the -x option to pull in processes that aren't under the current shell ๐Ÿ‘€. We can also add the -u option to get the stats too ๐Ÿ“Š:

# ps -xu
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   2316   808 ?        Ss   16:17   0:00 /bin/sh -c /bin/
root         7  0.0  0.0   4208  3056 ?        S    16:17   0:00 /bin/bash ../com
root         8  0.1  0.0   4208  1924 ?        S    16:17   0:00 /bin/bash ../com
root        20 95.0  0.4  41096 36428 ?        R    16:17   7:09 python script.py
root       645  0.0  0.0   4472  3492 pts/0    Ss   16:21   0:00 bash
root      1379  0.0  0.0   2636   764 ?        S    16:25   0:00 sleep 1
root      1380  0.0  0.0   8584  3912 pts/0    R+   16:25   0:00 ps -xu

Here we can see that python is literally running and eating 95% of a CPU core ๐Ÿ”ฅ๐Ÿ’€. So we can surmise that Python is probably stuck spinning around in an infinite loop ๐ŸŒ€. Let's look at our files again ๐Ÿง:

# ls -lah
total 8.1M
drwxrwxr-x 6 root root  192 Jun 18 16:17 .
drwxr-xr-x 3 root root 4.0K Jun 18 16:17 ..
drwxr-xr-x 3 root root   96 Jun 18 16:17 .toil_wdl_runtime
drwxrwxr-x 8 root root  256 Jun 18 16:17 _miniwdl_inputs
-rw-r--r-- 1 root root 7.6M Jun 18  2024 compressed.zip
-rw-r--r-- 1 root root 1.3K Jun 18 16:17 script.py

Note that, while we've been investigating, our compressed.zip file has grown from 6.0M to 7.6M ๐Ÿ˜ญ. So we now know that, not only is the Python script stuck in a loop, it is also writing to the ZIP file inside that loop ๐Ÿ’€๐Ÿซ .

Let's inspect the inputs ๐ŸŽ€:

# ls -lah _miniwdl_inputs/*
_miniwdl_inputs/0:
total 4.0K
drwxrwxr-x 3 root root  96 Jun 18 16:17 .
drwxrwxr-x 8 root root 256 Jun 18 16:17 ..
-rw-r--r-- 1 root root  65 Jun 18 16:15 stdout.txt

_miniwdl_inputs/1:
total 4.0K
drwxrwxr-x 3 root root  96 Jun 18 16:17 .
drwxrwxr-x 8 root root 256 Jun 18 16:17 ..
-rw-r--r-- 1 root root  65 Jun 18 16:15 stdout.txt

_miniwdl_inputs/2:
total 4.0K
drwxrwxr-x 3 root root  96 Jun 18 16:17 .
drwxrwxr-x 8 root root 256 Jun 18 16:17 ..
-rw-r--r-- 1 root root  65 Jun 18 16:15 stdout.txt

_miniwdl_inputs/3:
total 4.0K
drwxrwxr-x 3 root root  96 Jun 18 16:17 .
drwxrwxr-x 8 root root 256 Jun 18 16:17 ..
-rw-r--r-- 1 root root 384 Jun 18 16:15 stdout.txt

_miniwdl_inputs/4:
total 4.0K
drwxrwxr-x 3 root root  96 Jun 18 16:17 .
drwxrwxr-x 8 root root 256 Jun 18 16:17 ..
-rw-r--r-- 1 root root 387 Jun 18 16:15 stdout.txt

_miniwdl_inputs/5:
total 4.0K
drwxrwxr-x 3 root root  96 Jun 18 16:17 .
drwxrwxr-x 8 root root 256 Jun 18 16:17 ..
-rw-r--r-- 1 root root 378 Jun 18 16:15 stdout.txt

These are the files that are meant to be compressed into that ZIP file. But hang on... there are only six of these files, and none of them is over 400 bytes in size ๐Ÿคจ. How did we get a multi-megabyte ZIP file? The script must be putting more data than we expected into the ZIP file it is writing ๐Ÿ˜ณ.

Taking what we know, we can inspect the Python script again and see if we can find a way in which it could get stuck in an infinite loop, writing much more data to the ZIP than is actually in the input files. We can also inspect it for WDL variable substitutions (there aren't any ๐Ÿ™…โ€โ™€๏ธ). Let's look at it with line numbers using the nl tool, numbering even blank lines with -b a ๐Ÿ”ข:

# nl -b a script.py
 1  import sys
 2  from zipfile import ZipFile
 3  import os
 4
 5  # Interpret command line arguments
 6  to_compress = list(reversed(sys.argv[1:]))
 7
 8  with ZipFile("compressed.zip", "w") as z:
 9      while to_compress != []:
10          # Grab the file to add off the end of the list
11          input_filename = to_compress[-1]
12          # Now we need to write this to the zip file.
13          # What internal filename should we use?
14          basename = os.path.basename(input_filename)
15          disambiguation_number = 0
16          while True:
17              target_filename = str(disambiguation_number) + basename
18              try:
19                  z.getinfo(target_filename)
20              except KeyError:
21                  # Filename is free
22                  break
23              # Otherwise try another name
24              disambiguation_number += 1
25          # Now we can actually make the compressed file
26          with z.open(target_filename, 'w') as out_stream:
27              with open(input_filename) as in_stream:
28                  for line in in_stream:
29                      # Prefix each line of text with the original input file
30                      # it came from.
31                      # Also remember to encode the text as the zip file
32                      # stream is in binary mode.
33                      out_stream.write(f"{basename}: {line}".encode("utf-8"))

We have three loops here: while to_compress != [] on line 9, while True on line 16, and for line in in_stream on line 28 ๐ŸŒธ.

The while True loop is immediately suspicious ๐Ÿ‘€, but none of the code inside it writes to the ZIP file, so we know we can't be stuck in there ๐Ÿ™…โ€โ™€๏ธ.

The for line in in_stream loop contains the only call that writes data to the ZIP, so we must be spending time inside it, but it is constrained to loop over a single file at a time, so it can't be the infinite loop we're looking for ๐Ÿ’….

So then we must be infinitely looping at while to_compress != [], and indeed we can see that to_compress is never modified, so it can never become [] ๐Ÿคฏ.

So now we have a theory as to what the problem is, and we can exit out of our shell in the container, and stop toil debug-job with Control+C ๐Ÿ›‘. Then we can make the following change to our workflow, adding code to the script to actually pop the handled files off the end of the list ๐Ÿซถ:

--- tutorial_debugging_works.wdl   2024-06-18 12:03:32
+++ tutorial_debugging_hangs.wdl   2024-06-18 12:03:53
@@ -112,9 +112,6 @@
                        # Also remember to encode the text as the zip file
                        # stream is in binary mode.
                        out_stream.write(f"{basename}: {line}".encode("utf-8"))
-            # Even though we got distracted by zip file manipulation, remember
-            # to pop off the file we just did.
-            to_compress.pop()
     EOF
     python script.py ~{sep(" ", files)}
     >>>

If we apply that change and produce a new file, tutorial_debugging_works.wdl, we can clean up from the old failed run and run a new one ๐Ÿงน:

$ toil clean ./store
$ toil-wdl-runner --jobStore ./store tutorial_debugging_works.wdl --container docker

This will produce a successful log, ending with something like ๐ŸŽ‰:

[2024-06-18T12:42:20-0400] [MainThread] [I] [toil.leader] Finished toil run successfully.

Workflow Progress 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 17/17 (0 failures) [00:24<00:00, 0.72 jobs/s]
{"TutorialDebugging.compressed": "/Users/anovak/workspace/toil/src/toil/test/docs/scripts/wdl-out-u7fkgqbe/f5e16468-0cf6-4776-a5c1-d93d993c4db2/compressed.zip"}
[2024-06-18T12:42:20-0400] [MainThread] [I] [toil.common] Successfully deleted the job store: FileJobStore(/Users/anovak/workspace/toil/src/toil/test/docs/scripts/store)

Note the line to standard output giving us the path on disk where the TutorialDebugging.compressed output from the workflow is ๐Ÿ“. If you look at that ZIP file, you can see it contains the expected files, such as 3stdout.txt, which should contain this suitably prefixed dismayed whale ๐Ÿณ:

stdout.txt:  ________
stdout.txt: < Uh-oh! >
stdout.txt:  --------
stdout.txt:     \
stdout.txt:      \
stdout.txt:       \
stdout.txt:                     ##        .
stdout.txt:               ## ## ##       ==
stdout.txt:            ## ## ## ##      ===
stdout.txt:        /""""""""""""""""___/ ===
stdout.txt:   ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
stdout.txt:        \______ o          __/
stdout.txt:         \    \        __/
stdout.txt:           \____\______/

When we're done inspecting the output, and satisfied that the workflow now works, we might want to clean up all the auto-generated WDL output directories from the successful and failed run(s) ๐Ÿ—‘๏ธ:

$ rm -Rf wdl-out-*

๐Ÿ”Ž Introspecting the Job Store ๐Ÿ”Ž

Note: Currently these features are only implemented for use locally (single machine) with the fileJobStore.

To view what files currently reside in the jobstore, run the following command ๐Ÿ‘€:

$ toil debug-file file:path-to-jobstore-directory \
      --listFilesInJobStore

When run from the commandline, this should generate a file containing the contents of the job store (in addition to displaying a series of log messages to the terminal). This file is named "jobstore_files.txt" by default and will be generated in the current working directory ๐Ÿ“.

If one wishes to copy any of these files to a local directory, one can run for example ๐Ÿ“ฆ:

$ toil debug-file file:path-to-jobstore \
      --fetch overview.txt *.bam *.fastq \
      --localFilePath=/home/user/localpath

To fetch overview.txt, and all .bam and .fastq files. This can be used to recover previously used input and output files for debugging or reuse in other workflows, or use in general debugging to ensure that certain outputs were imported into the jobStore ๐Ÿซถ.

๐Ÿ“Š Stats and Status ๐Ÿ“Š

See Stats Command <#cli-stats> and Status Command <#cli-status> for more about gathering statistics about job success, runtime, and resource usage from workflows โœจ.

๐Ÿ Using a Python debugger ๐Ÿ

If you execute a workflow using the --debugWorker flag, or if you use toil debug-job, Toil will run the job in the process you started from the command line. This means you can either use pdb https://docs.python.org/3/library/pdb.html, or an IDE that supports debugging Python https://wiki.python.org/moin/PythonDebuggingTools#IDEs_with_Debug_Capabilities to interact with the Python process as it runs your job ๐Ÿฆ‹.

Heads up: Note that the --debugWorker flag will only work with the single_machine batch system (the default), and not any of the custom job schedulers. ๐Ÿ’€

โ˜๏ธ RUNNING IN THE CLOUD โ˜๏ธ

Toil supports Amazon Web Services (AWS) and Google Compute Engine (GCE) in the cloud and has autoscaling capabilities that can adapt to the size of your workflow, whether your workflow requires 10 instances or 20,000 ๐ŸŒˆ๐Ÿš€

Toil does this by spinning up a virtual cluster running Kubernetes ๐Ÿ’– (https://kubernetes.io/). Kubernetes needs a leader node to coordinate the workflow, plus worker nodes to actually run the tasks inside it. As the workflow goes, Kubernetes will "autoscale" ๐Ÿฆ‹, creating and terminating workers whenever the workflow needs them. Historically, toil spun up clusters with Apache Mesos (https://mesos.apache.org/gettingstarted/), but ngl that's no longer recommended ๐Ÿ’€.

Once you're comfy running toil locally (picking a jobStore, see #jobstoreoverview, and writing a workflow), you can check out the guides below to turn those workflows into cloud ready ones โœจ.

โœจ Managing a Cluster of Virtual Machines (Provisioning) โœจ

Toil can launch and manage a whole cluster of virtual machines ๐Ÿ–ฅ๏ธ using the provisioner, so your workflow runs across several nodes. The provisioner can also automatically scale the cluster up or down (autoscaling) when computational demand changes. Right now we have working provisioners for AWS and GCE. Azure support has been deprecated, so no more Azure, bestie ๐Ÿ™ˆ.

Toil uses Kubernetes (https://kubernetes.io/) as the Batch System (see #batchsystemoverview).

See here for instructions for Running in AWS (#runningaws) ๐ŸŒธ.

See here for instructions for Running in Google Compute Engine (GCE) (#runninggce) ๐ŸŒˆ.

Toil also has a whole suite of commands for using the provisioners to manage clusters ๐Ÿ’….

๐ŸŽ€ Toil Cluster Utilities ๐ŸŽ€

On top of the generic Toil Utilities (#utils), there are several utilities for starting and managing a Toil cluster with the AWS or GCE provisioners. They're installed via the [aws] or [google] extra. For installation details, see Toil Provisioner (#installprovisioner).

The toil cluster subcommands are:

  • destroy-cluster โ€” For autoscaling. Terminates the specified cluster and its associated resources ๐Ÿงน.
  • launch-cluster โ€” For autoscaling. Used to launch a toil leader instance with the specified provisioner ๐Ÿš€.
  • rsync-cluster โ€” For autoscaling. Transfers files to a cluster launched with toil launch-cluster ๐Ÿ“ฆ.
  • ssh-cluster โ€” SSHs into the toil appliance container running on the leader of the cluster ๐Ÿ’œ.

For info on a specific utility, run it with the --help option:

toil launch-cluster --help

The cluster utilities can be used for Running in Google Compute Engine (GCE) (#runninggce) and Running in AWS (#runningaws) ๐Ÿซถ.

Tip: By default, all of the cluster utilities expect to be running on AWS. To run with Google, you'll need to specify the --provisioner gce option for each utility.
Note: Boto must be configured (http://boto3.readthedocs.io/en/latest/guide/quickstart.html#configuration) with AWS credentials before using cluster utilities. Running in Google Compute Engine (GCE) (#runninggce) contains instructions for

๐Ÿฆ‹ Launch-Cluster Command ๐Ÿฆ‹

Running toil launch-cluster starts up a leader for a cluster. You can add workers to the initial cluster by specifying the -w option. An example would be:

$ toil launch-cluster my-cluster \
      --leaderNodeType t2.small -z us-west-2a \
      --keyPairName your-AWS-key-pair-name \
      --nodeTypes m3.large,t2.micro -w 1,4

The options are listed below. You can also pull them up by running:

$ toil launch-cluster --help

The main positional argument for launch-cluster is the clusterName. This is simply the name of your cluster. If it doesn't exist yet, Toil will create it for you ๐Ÿฅฐ.

๐ŸŒˆ Launch-Cluster Options ๐ŸŒˆ

  • --help, -h โ€” also accepted. Displays this help menu ๐Ÿ“–.
  • --tempDirRoot TEMPDIRROOT โ€” The path to the temporary directory where all temp files get created. By default, it uses the current working directory as the base.
  • --version โ€” Displays the version.
  • --provisioner CLOUDPROVIDER, -p CLOUDPROVIDER โ€” also accepted. The provisioner for cluster auto-scaling. Both AWS and GCE are currently supported.
  • --zone ZONE, -z ZONE โ€” also accepted. The availability zone of the leader. This can also be set via the TOIL_AWS_ZONE or TOIL_GCE_ZONE environment variables, or by the ec2_region_name parameter in your .boto file if you're using AWS. If you're using this utility on an existing EC2 instance, it's derived from the instance metadata instead.
  • --leaderNodeType LEADERNODETYPE โ€” The non-preemptable node type for the cluster leader.
  • --keyPairName KEYPAIRNAME โ€” The name of the AWS or ssh key pair to include on the instance ๐Ÿ”‘.
  • --owner OWNER โ€” The owner tag for all instances. If it isn't given, the value in TOIL_OWNER_TAG is used, or else the value of --keyPairName.
  • --boto BOTOPATH โ€” The path to the boto credentials directory. It gets transferred to all nodes so they can access the AWS jobStore from non-AWS instances.
  • --tag KEYVALUE, -t KEY=VALUE โ€” KEYVALUE is specified as KEY=VALUE. -t KEY=VALUE is also accepted. Tags get added to the AWS cluster for this node and all of its children. Tags look like -t key1=value1 --tag key2=value2. You can add multiple tags, but each one needs its own flag. By default, the cluster is tagged with: { "Name": clusterName, "Owner": IAM username } ๐Ÿท๏ธ.
  • --vpcSubnet VPCSUBNET โ€” The VPC subnet ID to launch the cluster leader in. It uses the default subnet if you don't specify one. This subnet needs to have auto assign IPs turned on.
  • --nodeTypes NODETYPES โ€” A comma-separated list of node types to create while launching the leader. The syntax for each node type depends on the provisioner you use. For the AWS provisioner, it's the name of an EC2 instance type, followed by a colon and the dollar price to bid for a spot instance, like 'c3.8xlarge:0.42'. You must also provide the --workers argument to say how many workers of each node type to create.
  • --workers WORKERS, -w WORKERS โ€” also accepted. A comma-separated list of how many workers of each node type to launch alongside the leader when the cluster is created. This is handy if you're running toil without auto-scaling but need more hardware support ๐Ÿ’ช.
  • --leaderStorage LEADERSTORAGE โ€” The size (in gigabytes) of the root volume for the leader instance. This is an EBS volume ๐Ÿ’พ.
  • --nodeStorage NODESTORAGE โ€” The size (in gigabytes) of the root volume for any worker instances created when using the -w flag. This is an EBS volume.
  • --nodeStorageOverrides NODESTORAGEOVERRIDES โ€” A comma-separated list of nodeType:nodeStorage pairs that override the default from --nodeStorage for the specified nodeType(s). This is super useful for heterogeneous jobs where some tasks need way more disk than others.
  • --allowFuse BOOL โ€” Whether to allow FUSE mounts for faster runtimes with Singularity. Heads up, this one is a lot ๐Ÿ‘‡.
Warning: Allowing FUSE mounts results in the Toil container running as privileged. For Kubernetes, pods will be asked to run as privileged. If this isn't allowed, Singularity containers will use sandbox directories instead ๐Ÿšจ.

๐Ÿ”ฎ Logging Options ๐Ÿ”ฎ

  • --logOff โ€” Same as --logCritical.
  • --logCritical โ€” Turns on logging at level CRITICAL and above. (default is INFO)
  • --logError โ€” Turns on logging at level ERROR and above. (default is INFO)
  • --logWarning โ€” Turns on logging at level WARNING and above. (default is INFO)
  • --logInfo โ€” Turns on logging at level INFO and above. (default is INFO)
  • --logDebug โ€” Turns on logging at level DEBUG and above. (default is INFO)
  • --logDebug โ€” Turns on logging at level TRACE and above. (default is INFO) ๐Ÿ™ˆ yes, --logDebug shows up twice in the original, and this second one is the TRACE one.
  • --logLevel LOGLEVEL โ€” Logs at the given level. It can be OFF (or CRITICAL), ERROR, WARN (or WARNING), INFO, DEBUG, or TRACE. (default is INFO)
  • --logFile LOGFILE โ€” The file to log in ๐Ÿ“.
  • --rotatingLogging โ€” Turns on rotating logging, which keeps log files from getting too big ๐Ÿ”„.

๐Ÿ’œ Ssh-Cluster Command ๐Ÿ’œ

Toil lets you ssh into the leader of the cluster. Here's how:

$ toil ssh-cluster CLUSTER-NAME-HERE

This opens a shell on the Toil leader, and it's where you start an Running a Workflow with Autoscaling (#autoscaling) run. Docker issues stop you from using screen and tmux when you ssh into the cluster, because the shell doesn't know it's a TTY, which means it can't allocate a new screen session ๐Ÿ˜ญ. You can work around this with:

$ script
$ screen

Just running screen inside script will get things working properly again โœจ.

Finally, you can run remote commands with this syntax:

$ toil ssh-cluster CLUSTER-NAME-HERE remoteCommand
Warning: It's not advised to run your Toil workflow with remote execution like this, unless you use a tool like nohup (https://linux.die.net/man/1/nohup). That keeps the process from dying if the SSH connection gets interrupted.

For an example, check out Running a Workflow with Autoscaling (#autoscaling) ๐ŸŽฌ.

๐Ÿงš Rsync-Cluster Command ๐Ÿงš

The most common use case for the rsync-cluster utility is deploying your workflow code to the Toil leader. The syntax is the same as traditional rsync (https://linux.die.net/man/1/rsync), except for the hostname before the colon. You don't need that in toil rsync-cluster, since Toil automatically figures out the hostname ๐Ÿซถ.

Here's an example of how it's used:

$ toil rsync-cluster CLUSTER-NAME-HERE \
      ~/localFile :/remoteDestination

๐Ÿงน Destroy-Cluster Command ๐Ÿงน

The destroy-cluster command is the advised way to get rid of any Toil cluster launched using the Launch-Cluster Command command. It makes sure all attached nodes, volumes, security groups, etc. get deleted. If you shut a node or cluster down using Amazon's online portal, residual resources may still be running in the background ๐Ÿ‘€. To delete a cluster, run:

$ toil destroy-cluster CLUSTER-NAME-HERE

๐Ÿซง Storage (Toil jobStore) ๐Ÿซง

Toil can use cloud storage, like AWS or Google buckets, to handle its storage needs โ˜๏ธ.

This is super useful when you run Toil in single machine mode on any cloud platform, because you get to use their integrated storage systems ๐Ÿ’–.

For an overview of the job store, peep Job Store (#jobstoreoverview) ๐Ÿ‘€โœจ that's the big-picture tea.

If you want the step-by-step for a specific job store, check these out:

  • AWS Job Store (#awsjobstore) ๐Ÿฆ‹
  • Google Job Store (#googlejobstore) ๐ŸŒˆ

โœจ CLOUD PLATFORMS โœจ

๐ŸŒธ Running on Kubernetes

Okay so Kubernetes (https://kubernetes.io/) is literally the most popular container orchestration tool, and it's basically become the de facto cross-cloud-provider API for getting at cloud resources. ๐Ÿ˜ญ Major providers like Amazon (https://aws.amazon.com/kubernetes/), Microsoft (https://azure.microsoft.com/en-us/overview/kubernetes-getting-started/), Kubernetes owner Google (https://cloud.google.com/kubernetes-engine/), and DigitalOcean (https://www.digitalocean.com/products/kubernetes/) have all put serious effort into making Kubernetes work well on their platforms. They wrote their own deployment docs and built provider-managed Kubernetes products. And if you want it on just one machine, minikube (https://github.com/kubernetes/minikube) can run Kubernetes on a single machine. Iconic. ๐Ÿ’…

Toil supports running Toil workflows against a Kubernetes cluster, either in the cloud or deployed on user-owned hardware. ๐Ÿซถ

๐Ÿงš Preparing your Kubernetes environment

1. Get a Kubernetes cluster

To run Toil workflows on Kubernetes, you need a Kubernetes cluster set up. This isn't covered here, but there are loads of options, and which one you pick depends on which cloud ecosystem you already use (if any) and on pricing. If you're just following along with the docs, use minikube on your local machine. ๐Ÿ“

Alternatively, Toil can set up a Kubernetes cluster for you with the Toil provisioner (#installprovisioner). Follow this guide (#provisioningwithkubernetes) to get started with a Toil-managed Kubernetes cluster on AWS. ๐ŸŽ€

Heads up, bestie ๐Ÿ’€: right now the only way to run a Toil workflow on Kubernetes is with the AWS Job Store. So your Kubernetes workflow has to store its data in Amazon's cloud no matter where you run it. This can result in significant egress charges from Amazon if you run it outside of Amazon.

Kubernetes Cluster Providers:

2. Get a Kubernetes context on your local machine

There are two main ways to run Toil workflows on Kubernetes. You can run the Toil leader on a machine outside the cluster, with jobs submitted to and run on the cluster, or you can submit the Toil leader itself as a job and let it run inside the cluster. Either way, your own machine needs to be set up so it can submit jobs to the Kubernetes cluster. Generally, that means creating and populating a file named .kube/config in your user's home directory, and specifying the cluster to connect to, the certificate and token info needed for mutual authentication, and the Kubernetes namespace to work within. However, Kubernetes configuration can also be picked up from other files in the .kube directory, environment variables, and the enclosing host when running inside a Kubernetes-managed container. ๐Ÿง 

You'll have to do different things here depending on where you got your Kubernetes cluster:

Toil's internal Kubernetes configuration logic mirrors that of the kubectl command. Toil workflows will use the current kubectl context to launch their Kubernetes jobs. โœจ

3. If running the Toil leader in the cluster, get a service account

If you're going to run your workflow's leader inside the Kubernetes cluster (see Option 1: Running the Leader Inside Kubernetes), you'll need a service account in your chosen Kubernetes namespace. Most namespaces should have one named default, which should work fine. If your cluster requires a different service account, get its name and use it when launching the Kubernetes job containing the Toil leader. ๐ŸŒˆ

4. Set up appropriate permissions

Your local Kubernetes context and/or the service account you're using to run the leader in the cluster need certain permissions to run the workflow. Toil has to be able to interact with jobs and pods in the cluster, and to retrieve pod logs. You as a user may need permission to set up an AWS credentials secret, if one isn't already available. Additionally, it's super useful for you to have permission to interact with nodes and to shell into pods. ๐Ÿ‘‘

The appropriate permissions may already be available to you and your service account by default, especially in managed or ease-of-use-optimized setups like EKS or minikube.

However, if the appropriate permissions aren't already available, you or your cluster administrator will have to grant them manually. The following Role (toil-user) and ClusterRole (node-reader), to be applied with kubectl apply -f filename.yaml, should grant sufficient permissions to run Toil workflows when bound to your account and the service account used by Toil workflows. Be sure to replace YOUR_NAMESPACE_HERE with the namespace you're running your workflows in.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: YOUR_NAMESPACE_HERE
  name: toil-user
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["explain", "get", "watch", "list", "describe", "logs", "attach", "exec", "port-forward", "proxy", "cp", "auth"]
- apiGroups: ["batch"]
  resources: ["*"]
  verbs: ["get", "watch", "list", "create", "run", "set", "delete"]
- apiGroups: [""]
  resources: ["secrets", "pods", "pods/attach", "podtemplates", "configmaps", "events", "services"]
  verbs: ["patch", "get", "update", "watch", "list", "create", "run", "set", "delete", "exec"]
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create"]

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "describe"]
- apiGroups: [""]
  resources: ["namespaces"]
  verbs: ["get", "list", "describe"]
- apiGroups: ["metrics.k8s.io"]
  resources: ["*"]
  verbs: ["*"]

To bind a user or service account to the Role or ClusterRole and actually grant the permissions, you'll need a RoleBinding and a ClusterRoleBinding, respectively. Make sure to fill in the namespace, username, and service account name, and add more user stanzas if your cluster is going to support multiple Toil users. ๐Ÿฆ‹

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: toil-developer-member
  namespace: toil
subjects:
- kind: User
  name: YOUR_KUBERNETES_USERNAME_HERE
  apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
  name: YOUR_SERVICE_ACCOUNT_NAME_HERE
  namespace: YOUR_NAMESPACE_HERE
roleRef:
  kind: Role
  name: toil-user
  apiGroup: rbac.authorization.k8s.io

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-nodes
subjects:
- kind: User
  name: YOUR_KUBERNETES_USERNAME_HERE
  apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
  name: YOUR_SERVICE_ACCOUNT_NAME_HERE
  namespace: YOUR_NAMESPACE_HERE
roleRef:
  kind: ClusterRole
  name: node-reader
  apiGroup: rbac.authorization.k8s.io

๐Ÿฆ‹ AWS Job Store for Kubernetes

Currently, the only job store that works with jobs running on Kubernetes is the AWS Job Store. The job store is what Toil uses to exchange data between jobs, and this one requires that the Toil leader and Kubernetes jobs be able to connect to and use Amazon S3 and Amazon SimpleDB. It also requires that you have an Amazon Web Services account. โ˜๏ธ

1. Get access to AWS S3 and SimpleDB

In your AWS account, you need to create an AWS access key. First, go to the IAM dashboard. For "us-west1", the link would be:

https://console.aws.amazon.com/iam/home?region=us-west-1#/home

Then create an access key, and save the Access Key ID and the Secret Key. As documented in the AWS documentation (https://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html):

  1. On the IAM Dashboard page, choose your account name in the navigation bar, and then choose My Security Credentials.
  2. Expand the Access keys (access key ID and secret access key) section.
  3. Choose Create New Access Key. Then choose Download Key File to save the access key ID and secret access key to a file on your computer. After you close the dialog box, you can't retrieve this secret access key again.
Make sure that, if your AWS infrastructure requires your user to authenticate with a multi-factor authentication (MFA) token, you obtain a second secret key and access key that don't have this requirement. The secret key and access key used to populate the Kubernetes secret that allows the jobs to contact the job store need to be usable without human intervention. ๐Ÿ™ˆ

2. Configure AWS access from the local machine

This only really needs to happen if you run the leader on the local machine. But we need the files in place to fill in the secret in the next step. Run:

$ aws configure

Then when it asks, punch in your secret key and access key ๐Ÿ”‘โœจ That should spit out a file at ~/.aws/credentials that looks like this:

[default]
aws_access_key_id =  BLAH
aws_secret_access_key =  blahblahblah
  1. Create a Kubernetes secret to give jobs access to AWS ๐Ÿ” Hop into the folder where your credentials file lives:
$ cd ~/.aws

Then make a Kubernetes secret that holds it. We're calling it aws-credentials ๐Ÿ’–

$ kubectl create secret generic aws-credentials --from-file credentials

โœจ Configuring Toil for your Kubernetes environment โœจ

Okay bestie, so to run your workflow on Kubernetes, you'll need to set up a bunch of environment variables ๐ŸŒธ and pass the --batchSystem kubernetes option too. Figuring out what values to use for these might mean chatting with your cluster provider, so don't be shy ๐Ÿซถ

  1. TOIL_AWS_SECRET_NAME is the MAIN one ๐Ÿ‘‘ It has to be set to the secret holding your AWS credentials file, if your cluster nodes can't already reach S3 and SimpleDB (like through IAM roles). It's required for the AWS job store to work, and that's currently the only job store you can use on Kubernetes. In this example we're using aws-credentials.
  2. TOIL_KUBERNETES_HOST_PATH lets Toil jobs on the same physical host share a cache ๐Ÿฆ‹ Set it to a path on the host where the shared cache should live. Inside the container it gets mounted as /var/lib/toil, or at TOIL_WORKDIR if you've specified that. The path has to already exist on the host, and it needs as much free space as your Kubernetes node offers to jobs. In this example we're using /data/scratch. To actually make use of caching, make sure you don't use --disableCaching.
  3. TOIL_KUBERNETES_OWNER should be the username of whoever is running the Toil workflow ๐Ÿ’… Toil's jobs include this name, so they're easy to spot and clean up if anything happens to the Toil leader. In this example we're using demo-user.
  4. TOIL_KUBERNETES_PRIVILEGED can be True or False ๐Ÿ”ฅ When it's True, pods are allowed to run as privileged, which enables FUSE mounts for Singularity for faster runtimes. If it isn't set to true, Singularity extracts images into sandbox directories instead. It's unset/False by default, except in Toil-managed clusters.
โš ๏ธ Heads up, bestie: Docker containers cannot be run inside unprivileged Kubernetes pods (which are themselves containers) ๐Ÿ’€ The Docker daemon doesn't (yet) support this. Other tools, like Singularity in its user-namespace mode, can run containers from within containers.

If you're using Singularity to run containerized tools and want downloaded container images to stick around between Toil jobs, you might need some setup ๐Ÿงš

On non-Toil managed clusters: You'll want to set TOIL_KUBERNETES_HOST_PATH too, and make sure Singularity downloads its containers under the Toil work directory (/var/lib/toil by default) by setting SINGULARITY_CACHEDIR.

On Toil-managed clusters: Clusters made with the launch-cluster command need no setup ๐ŸŽ€ TOIL_KUBERNETES_HOST_PATH is already set to /var/lib/toil, and SINGULARITY_CACHEDIR is set to /var/lib/toil/singularity, which is a shared location. You may still need to implement Singularity locking (shown below) or move the Singularity cache somewhere else.

If you're using toil-wdl-runner, all the necessary Singularity locking is already in place, so you shouldn't have to do anything ๐Ÿ™Œ Otherwise, for both Toil managed and non-Toil managed clusters, you need to make sure that no two jobs try to download the same container at the same time. Singularity has no synchronization or locking around its cache, and the cache isn't safe for simultaneous access by multiple Singularity invocations ๐Ÿ˜ญ Some Toil workflows use their own custom workaround for this; for example, see this section in toil-wdl-runner: https://github.com/DataBiosphere/toil/blob/1821782b9ec40431e8afa36030fb8ee5df943003/src/toil/wdl/wdltoil.py#L1675-L1679


โœจ Running workflows โœจ

To run the workflow, you'll need to run the Toil leader process somewhere ๐Ÿš€ It can either run inside Kubernetes as a Kubernetes job, or outside Kubernetes as a normal command.

โœจ Option 1: Running the Leader Inside Kubernetes โœจ

Once you've figured out your environment variable values for the workflow run, write a YAML file that defines a Kubernetes job to run your workflow with that configuration ๐Ÿ“ Some config items (like your username and the name of your AWS credentials secret) need to be written into the YAML so the leader can use them too.

The leader pod will need your workflow, its other dependencies, and Toil, all installed ๐Ÿ“ The easiest way to get Toil installed is to start from the Toil appliance image for the version of Toil you want. In this example we use quay.io/ucsc_cgl/toil:5.5.0.

Here's an example YAML file to run a test workflow ๐Ÿ‘‘

apiVersion: batch/v1
kind: Job
metadata:
  # It is good practice to include your username in your job name.
  # Also specify it in TOIL_KUBERNETES_OWNER
  name: demo-user-toil-test
# Do not try and rerun the leader job if it fails

spec:
 backoffLimit: 0
 template:
   spec:
     # Do not restart the pod when the job fails, but keep it around so the
     # log can be retrieved
     restartPolicy: Never
     volumes:
     - name: aws-credentials-vol
       secret:
         # Make sure the AWS credentials are available as a volume.
         # This should match TOIL_AWS_SECRET_NAME
         secretName: aws-credentials
     # You may need to replace this with a different service account name as
     # appropriate for your cluster.
     serviceAccountName: default
     containers:
     - name: main
       image: quay.io/ucsc_cgl/toil:5.5.0
       env:
       # Specify your username for inclusion in job names
       - name: TOIL_KUBERNETES_OWNER
         value: demo-user
       # Specify where to find the AWS credentials to access the job store with
       - name: TOIL_AWS_SECRET_NAME
         value: aws-credentials
       # Specify where per-host caches should be stored, on the Kubernetes hosts.
       # Needs to be set for Toil's caching to be efficient.
       - name: TOIL_KUBERNETES_HOST_PATH
         value: /data/scratch
       volumeMounts:
       # Mount the AWS credentials volume
       - mountPath: /root/.aws
         name: aws-credentials-vol
       resources:
         # Make sure to set these resource limits to values large enough
         # to accommodate the work your workflow does in the leader
         # process, but small enough to fit on your cluster.
         #
         # Since no request values are specified, the limits are also used
         # for the requests.
         limits:
           cpu: 2
           memory: "4Gi"
           ephemeral-storage: "10Gi"
       command:
       - /bin/bash
       - -c
       - |
         # This Bash script will set up Toil and the workflow to run, and run them.
         set -e
         # We make sure to create a work directory; Toil can't hot-deploy a
         # Python file from the root of the filesystem, which is where we start.
         mkdir /tmp/work
         cd /tmp/work
         # We make a virtual environment to allow workflow dependencies to be
         # hot-deployed.
         #
         # We don't really make use of it in this example, but for workflows
         # that depend on PyPI packages we will need this.
         #
         # We use --system-site-packages so that the Toil installed in the
         # appliance image is still available.
         virtualenv --python python3 --system-site-packages venv
         . venv/bin/activate
         # Now we install the workflow. Here we're using a demo workflow
         # from Toil itself.
         wget https://raw.githubusercontent.com/DataBiosphere/toil/releases/4.1.0/src/toil/test/docs/scripts/tutorial_helloworld.py
         # Now we run the workflow. We make sure to use the Kubernetes batch
         # system and an AWS job store, and we set some generally useful
         # logging options. We also make sure to enable caching.
         python3 tutorial_helloworld.py \
             aws:us-west-2:demouser-toil-test-jobstore \
             --batchSystem kubernetes \
             --realTimeLogging \
             --logInfo

Save this YAML as leader.yaml, then run it on your Kubernetes installation with:

$ kubectl apply -f leader.yaml

To keep an eye on the leader job's progress, read its logs ๐Ÿ‘€ If you're using a Kubernetes dashboard like k9s (https://github.com/derailed/k9s), just find the pod created for the job in the dashboard and view its logs there. If not, you'll have to locate the pod by hand ๐Ÿฆ‹

โœจ Monitoring and Debugging Kubernetes Jobs and Pods โœจ

These techniques are most useful for the pod that holds the Toil leader, but they also work on individual Toil jobs on Kubernetes, even when the leader is outside the cluster ๐Ÿ’œ

Kubernetes names pods for jobs by appending a short random string to the job's name. To find the name of your job's pod, do:

$ kubectl get pods | grep demo-user-toil-test
demo-user-toil-test-g5496                                         1/1     Running     0          2m

As long as you've set TOIL_KUBERNETES_OWNER correctly, you should be able to find all of your workflow's pods by searching for your username ๐Ÿ”

$ kubectl get pods | grep demo-user

If a pod's status is anything other than Pending, you can view its logs with:

$ kubectl logs demo-user-toil-test-g5496

This dumps the pod's logs from the beginning until now, then terminates. To follow along with the logs from a running pod, add the -f option ๐ŸŒˆ

$ kubectl logs -f demo-user-toil-test-g5496

Okay so if your pod is stuck in ImagePullBackoff ๐Ÿ˜ญ, that's giving "bestie, you asked for an image that doesn't exist." If you're looking at a leader, check the image section of your YAML. If you're dealing with a worker job, check the value of TOIL_APPLIANCE_SELF instead. Also check your Kubernetes node's Internet connectivity and DNS ๐ŸŒ. In Kubernetes, DNS depends on system-level pods, and those can get terminated or evicted when resources are oversubscribed, just like your own workloads. Not fair, but it's real ๐Ÿ’€.

If your pod seems stuck in Pending or ContainerCreating ๐Ÿฅบ, you can get the tea on what's wrong with kubectl describe pod:

$ kubectl describe pod demo-user-toil-test-g5496

Pay extra attention to the Events: section at the very end of the output. If you see FailedScheduling events, that means your job is too big for the nodes on your cluster, or your cluster is too busy for your jobs ๐Ÿ˜ฉ:

Type     Reason            Age                  From               Message
----     ------            ----                 ----               -------
Warning  FailedScheduling  13s (x79 over 100m)  default-scheduler  0/4 nodes are available: 1 Insufficient cpu, 1 Insufficient ephemeral-storage, 4 Insufficient memory.

If a pod is running but acting erratically, or looks stuck, you can shell in and snoop around ๐Ÿ•ต๏ธโ€โ™€๏ธ:

$ kubectl exec -ti demo-user-toil-test-g5496 /bin/bash

One super common reason pods get stuck is trying to use more memory than Kubernetes allows (or more than the Toil job's memory resource requirement), but in a way that doesn't trigger the Linux OOM killer to terminate the pod's processes. In that case, the pod can sit at nearly 100% memory usage more or less forever, and trying to shell in will fail, because starting a process inside the pod needs some of that memory too. The recommended fix is to kill the offending pod and increase its memory requirement (or its Toil job's), or reduce its memory needs by adapting your user code ๐Ÿง .


โœจ When Things Go Wrong โœจ

The Toil Kubernetes batch system has cleanup code that terminates worker jobs when the leader shuts down. But if the leader pod gets removed by Kubernetes, is forcibly killed, or otherwise suffers a sudden existence failure, it can vanish while its worker jobs keep living their best life ๐Ÿ™ƒ.

It is not recommended to restart a workflow in this state. Jobs from the previous invocation will remain running and will be trying to modify the job store concurrently with jobs from the new invocation. ๐Ÿšซ

To clean up dangling jobs, use this snippet:

$ kubectl get jobs | grep demo-user | cut -f1 -d' ' | xargs -n10 kubectl delete job

This deletes all jobs with demo-user's username in their names, in batches of 10. You can also put the UUID that Toil assigns to a particular workflow invocation in the filter, so you only clean up the jobs for that one invocation ๐Ÿงน.


โœจ Option 2: Running the Leader Outside Kubernetes โœจ

If you don't want to run your Toil leader inside Kubernetes, you can run it locally instead. This is super useful when developing a workflow, since files can be hot-deployed from your local machine straight to Kubernetes ๐Ÿš€. But your local machine needs access to AWS (ideally role-assumption- and MFA-free ๐Ÿ”) and access to Kubernetes too. Real time logging won't work unless your local machine can listen for incoming UDP packets on arbitrary ports on the address it uses to contact the IPv4 Internet. Toil does no NAT traversal or detection, so keep that in mind.

Note that if you set TOIL_WORKDIR when running your workflow like this, it needs to be a directory that exists both on the host and in the Toil appliance.

Here's an example of running our test workflow leader locally, outside of Kubernetes:

$ export TOIL_KUBERNETES_OWNER=demo-user  # This defaults to your local username if not set
$ export TOIL_AWS_SECRET_NAME=aws-credentials
$ export TOIL_KUBERNETES_HOST_PATH=/data/scratch
$ virtualenv --python python3 --system-site-packages venv
$ . venv/bin/activate
$ wget https://raw.githubusercontent.com/DataBiosphere/toil/releases/4.1.0/src/toil/test/docs/scripts/tutorial_helloworld.py
$ python3 tutorial_helloworld.py \
      aws:us-west-2:demouser-toil-test-jobstore \
      --batchSystem kubernetes \
      --realTimeLogging \
      --logInfo

โœจ Running CWL Workflows โœจ

Running CWL workflows on Kubernetes can be a lil' bit challenging ๐Ÿ˜ค, because executing CWL can require toil-cwl-runner to orchestrate containers of its own, inside a Kubernetes job that's running in the Toil appliance container.

Normally, running a CWL workflow should Just Work โœจ, as long as the workflow's Docker containers can be executed with Singularity, your Kubernetes cluster doesn't impose extra capability-based confinement (i.e. SELinux, AppArmor) that interferes with Singularity's use of user-mode namespaces, and you configure Toil so its workers know where to store their data within the Kubernetes pods (which is done for you if you're using a Toil-managed cluster). For example, you should be able to run a CWL workflow like this:

$ export TOIL_KUBERNETES_OWNER=demo-user  # This defaults to your local username if not set
$ export TOIL_AWS_SECRET_NAME=aws-credentials
$ export TOIL_KUBERNETES_HOST_PATH=/data/scratch
$ virtualenv --python python3 --system-site-packages venv
$ . venv/bin/activate
$ pip install toil[kubernetes,cwl]==5.8.0
$ toil-cwl-runner  \
     --jobStore  aws:us-west-2:demouser-toil-test-jobstore \
     --batchSystem kubernetes \
     --realTimeLogging \
     --logInfo \
     --disableCaching \
     path/to/cwl/workflow \
     path/to/cwl/input/object

Additional cwltool options that your workflow might require, such as --no-match-user, can be passed to toil-cwl-runner, which inherits most cwltool options ๐ŸŽ€.


โœจ AppArmor and Singularity โœจ

Kubernetes clusters based on Ubuntu hosts often have AppArmor enabled on the host. AppArmor is a capability-based security enhancement system that plugs into the Linux kernel to enforce lists of things programs may or may not do, called profiles. For example, an AppArmor profile could be applied to a web server process to stop it from using the mount() system call to manipulate the filesystem. It has no business doing that under normal circumstances, but it might try if hackers compromised it ๐Ÿ‘€.

Kubernetes clusters also often use Docker as the backing container runtime to run pod containers. When AppArmor is enabled, Docker loads an AppArmor profile and applies it to all of its containers by default, with the ability for the profile to be overridden on a per-container basis. Unfortunately, this profile blocks some of the mount() system calls that Singularity uses to set up user-mode containers from working inside the pod, even though these calls would be allowed for an unprivileged user under normal circumstances ๐Ÿ˜ญ.

On the UCSC Kubernetes cluster, we configure our Ubuntu hosts with an alternative default AppArmor profile for Docker containers (https://github.com/adamnovak/gi-kubernetes-autoscaling-config/blob/e1350ac9ad17d94b5073b20db3c75620957926e3/kubenode.ubuntu.cloud-config.yaml#L27-L67), which allows these calls. Other solutions include turning off AppArmor on the host, configuring Kubernetes with a container runtime other than Docker, or using Kubernetes's AppArmor integration (https://kubernetes.io/docs/tutorials/security/apparmor/) to apply a more permissive profile or the unconfined profile to pods that Toil launches.

Toil does not yet have a way to apply a container.apparmor.security.beta.kubernetes.io/runner-container: unconfined annotation to its pods, as described in the Kubernetes AppArmor documentation (https://kubernetes.io/docs/tutorials/security/apparmor/#securing-a-pod). This feature is tracked in issue #4331 (https://github.com/DataBiosphere/toil/issues/4331) ๐Ÿฆ‹.


โœจ Running in AWS โœจ

Toil jobs can be run on a variety of cloud platforms. Of these, Amazon Web Services (AWS) is currently the best-supported solution ๐Ÿ†. Toil provides the Toil Cluster Utilities (#clusterutils) to conveniently create AWS clusters, connect to the leader of the cluster, and then launch a workflow. The leader handles distributing the jobs over the worker nodes and autoscaling to optimize costs ๐Ÿ’ธ.

The Running a Workflow with Autoscaling section details how to create a cluster and run a workflow that will dynamically scale depending on the workflow's needs.

The Static Provisioning section explains how a static cluster (one that won't automatically change in size) can be created and provisioned (grown, shrunk, destroyed, etc.).


โœจ Preparing your AWS environment โœจ

To use Amazon Web Services (AWS) to run Toil, or just to use S3 to host the files during the computation of a workflow, first set up and configure an account with AWS ๐Ÿ’–:

  1. If necessary, create and activate an AWS account (https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/).
  2. Next, generate a key pair for AWS with this command (do NOT generate your key pair with the Amazon browser ๐Ÿ™…โ€โ™€๏ธ):
$ ssh-keygen -t rsa
  1. This should prompt you to save your key. Please save it in ~/.ssh/id_rsa.
  2. Now move it to where your OS can see it as an authorized key:
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
  1. Next, you'll need to add your key to the ssh-agent:
$ eval `ssh-agent -s`
$ ssh-add

If your key has a passphrase, you'll be prompted to enter it here once ๐Ÿ”‘.

  1. You'll also need to chmod your private key (good practice, but also enforced by AWS):
$ chmod 400 id_rsa
  1. Now you'll need to add the key to AWS via the browser. For example, on us-west1, this address would be accessible at:
https://us-west-1.console.aws.amazon.com/ec2/v2/home?region=us-west-1#KeyPairs:sort=keyName
  1. Now click on the "Import Key Pair" button to add your key. (The original page has a screenshot here titled Adding an Amazon Key Pair, linked at https://us-west-1.console.aws.amazon.com/ec2/v2/home?region=us-west-1#KeyPairs:sort=keyName.)
  2. Next, you need to create an AWS access key. First go back to the IAM dashboard. For "us-west1", the example link would be here:
https://console.aws.amazon.com/iam/home?region=us-west-1#/home
  1. The directions (transcribed from https://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html) are now:
    1. On the IAM Dashboard page, choose your account name in the navigation bar, and then choose My Security Credentials.
  2. Expand the Access keys section (that's your access key ID and secret access key) ๐Ÿ”‘
    1. Choose Create New Access Key. Then choose Download Key File to save the access key ID and secret access key to a file on your computer. ๐Ÿ’พ Once you close the dialog box, you can't retrieve this secret access key again.
๐Ÿšจ Bestie, listen: once that dialog closes, the secret access key is gone forever. Save the file before you close anything! ๐Ÿ˜ญ
  1. Okay, you should now have a brand new "AWS Access Key ID" and "AWS Secret Access Key" ๐Ÿฅณ Next we install the AWS CLI and make sure it has the proper credentials:
$ pip install awscli --upgrade --user
  1. Now configure your AWS credentials with:
$ aws configure
  1. Add your "AWS Access Key ID" and "AWS Secret Access Key" from earlier, plus your region and output format. โœจ
" AWS Access Key ID [****************Q65Q]: "
" AWS Secret Access Key [****************G0ys]: "
" Default region name [us-west-1]: "
" Default output format [json]: "

This creates the files ~/.aws/config and ~/.aws/credentials. ๐Ÿ—‚๏ธ

  1. If you haven't already, install toil ๐Ÿงฐ (this example uses version 5.12.0, but we recommend the latest release):
$ virtualenv venv
$ source venv/bin/activate
$ pip install toil[all]==5.12.0
  1. Now that toil is installed and you're running a virtualenv, here's an example of launching a toil leader node. ๐Ÿš€ Heads up: in this example we set TOIL_APPLIANCE_SELF to toil version 5.3.0, but please set the version to the one you actually have installed if you're using a different version. ๐Ÿ’…
$ toil launch-cluster <cluster-name> \
      --clusterType kubernetes \
      --leaderNodeType t2.medium \
      --nodeTypes t2.medium -w 1 \
      --zone us-west-1a \
      --keyPairName id_rsa

To break down each of these commands, bestie: ๐Ÿซถ

  • toil launch-cluster โ€” the base command for launching a cluster in toil. ๐Ÿš€
  • <cluster-name> โ€” just pick a name for your cluster. ๐Ÿท๏ธ
  • --clusterType kubernetes โ€” picks the type of cluster that coordinates and runs your workflow. Kubernetes is the recommended option. ๐Ÿ‘‘
  • --leaderNodeType t2.medium โ€” sets the leader node type. A t2.medium is 2CPU, 4Gb RAM, and $0.0464/Hour. ๐Ÿ’ฐ Here's the full list of available AWS instances: https://aws.amazon.com/ec2/pricing/on-demand/
  • --nodeTypes t2.medium -w 1 โ€” sets the worker node type and how many worker nodes to launch. A Kubernetes cluster needs at least 1 worker node. ๐Ÿ
  • --zone us-west-1a โ€” the AWS zone you want to launch the instance in. It has to share the same prefix as the zone in your awscli credentials (in this tutorial, that's us-west-1). ๐Ÿ“
  • --keyPairName id_rsa โ€” the name of your key pair. It should be id_rsa if you followed this tutorial. ๐Ÿ”‘
๐Ÿท๏ธ Tag it, bestie: you can set the TOIL_AWS_TAGS environment variable to a JSON object to add arbitrary tags to your AWS resources. For example, if you run export TOIL_AWS_TAGS='{"project-name": "variant-calling"}' in your shell before using Toil, any AWS resources Toil creates get a project-name tag with the value variant-calling. ๐Ÿฆ‹
๐Ÿณ Image swap: you can also set the TOIL_APPLIANCE_SELF environment variable to one of the Toil project's Docker images at https://quay.io/repository/ucsc_cgl/toil?tag=latest&tab=tags if you want to launch a cluster using a different version of Toil than the one you have installed. ๐ŸŒˆ

โœจ AWS Job Store โœจ

Using the AWS job store is super straightforward once you've finished Preparing your AWS environment (#awsprep). All you have to do is specify the prefix for the job store name. ๐Ÿซง

To run the sort example (#sortexample) with the AWS job store, you'd type:

$ python3 sort.py aws:us-west-2:my-aws-sort-jobstore

๐ŸŒธ Toil Provisioner ๐ŸŒธ

The Toil provisioner is the component responsible for creating resources in Amazon's cloud. โ˜๏ธ It's included in Toil alongside the [aws] extra, and it lets us spin up a cluster. ๐Ÿš€

Getting started with the provisioner is simple, I promise: ๐Ÿ’–

  1. Make sure you have Toil installed with the AWS extras. For detailed instructions, see Installing Toil with Extra Features (#extras).
  2. You'll need an AWS account, and you'll need to save your AWS credentials on your local machine. ๐Ÿ” For help setting up an AWS account, see here: http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-set-up.html. For setting up your AWS credentials, follow the instructions here: http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files.

The Toil provisioner makes heavy use of the Toil Appliance, a Docker image that bundles Toil and all its requirements (e.g. Kubernetes). ๐Ÿณ This makes deployment simple across platforms, and you can even simulate a cluster locally. (See Developing with Docker (#appliance-dev) for details.) ๐Ÿงš

๐ŸŽ€ Choosing Toil Appliance Image ๐ŸŽ€

When you use the Toil provisioner, the appliance image gets chosen automatically based on the pip-installed version of Toil on your system. ๐Ÿซถ You can override that choice by setting the environment variables TOIL_DOCKER_REGISTRY and TOIL_DOCKER_NAME or TOIL_APPLIANCE_SELF. See Environment Variables (#envars) for more information on these variables. If you're developing with autoscaling and want to test and build your own appliance, have a look at Developing with Docker (#appliance-dev).

For information on using the Toil Provisioner, have a look at Running a Workflow with Autoscaling. ๐ŸŒˆ


๐Ÿš€ Details about Launching a Cluster in AWS ๐Ÿš€

Using the provisioner to launch a Toil leader instance is simple with the launch-cluster command. For example, to launch a Kubernetes cluster named "my-cluster" with a t2.medium leader in the us-west-2a zone, run:

(venv) $ toil launch-cluster my-cluster \
             --clusterType kubernetes \
             --leaderNodeType t2.medium \
             --nodeTypes t2.medium -w 1 \
             --zone us-west-2a \
             --keyPairName <AWS-key-pair-name>

The cluster name uniquely identifies your cluster, and it's used to fill in the instance's Name tag. ๐Ÿท๏ธ The Toil provisioner also automatically tags your cluster with an Owner tag that matches your keypair name, which helps with cost tracking. ๐Ÿ’ธ On top of that, the ToilNodeType tag lets you filter "leader" vs. "worker" nodes in your cluster. ๐Ÿ”

The leaderNodeType is an EC2 instance type (https://aws.amazon.com/ec2/instance-types/). It only affects the leader node. ๐Ÿ‘‘

The --zone parameter specifies which EC2 availability zone to launch the cluster in. You can also set this with the TOIL_AWS_ZONE environment variable. ๐Ÿ“ Note: a zone is not the same thing as an EC2 region! ๐Ÿ™ˆ A region is a geographical area like us-west-2 (Oregon), and availability zones are partitions of that area, like us-west-2a.

By default, Toil creates an IAM role for each cluster with enough permissions to do cluster stuff (e.g. full S3, EC2, and SDB access). ๐Ÿ›ก๏ธ If the default permissions aren't enough for your use case (say you need access to ECR), you can create a custom IAM role with all the permissions you need and set the --awsEc2ProfileArn parameter when launching the cluster. Your custom role must at least have these permissions (#minawspermissions) for the Toil cluster to function properly.

Toil also creates a new security group with the same name as the cluster name, with default rules (e.g. it opens port 22 for SSH access). ๐Ÿ”“ If you need additional security groups, you can use the --awsEc2ExtraSecurityGroupId parameter when launching the cluster.

๐Ÿ’€ Danger zone, bestie: do not use the same name as the cluster name for your extra security groups! Any security group matching the cluster name will be deleted once the cluster is destroyed. ๐Ÿ˜ฑ

For more info on options, try:

(venv) $ toil launch-cluster --help

๐Ÿงš Static Provisioning ๐Ÿงš

Toil can manage a cluster in the cloud using the Toil Cluster Utilities (#clusterutils). The cluster utilities also make it super easy to run a toil workflow directly on that cluster. ๐Ÿซถ We call this static provisioning because the size of the cluster never changes. That's in contrast to Running a Workflow with Autoscaling. ๐Ÿ“

To launch worker nodes alongside the leader, use the -w option:

(venv) $ toil launch-cluster my-cluster \
             --clusterType kubernetes \
             --leaderNodeType t2.small -z us-west-2a \
             --keyPairName <AWS-key-pair-name> \
             --nodeTypes m3.large,t2.micro -w 1,4 \
             --zone us-west-2a

This spins up a t2.small leader node with five additional workers: one m3.large instance and four t2.micro. ๐Ÿ

Currently, static provisioning is only possible during the cluster's creation. ๐Ÿ™ƒ Adding and removing nodes through the native provisioner is still in development. Of course, you can always delete the cluster with the Destroy-Cluster Command (#destroycluster) utility. ๐Ÿ—‘๏ธ


๐Ÿ“ฆ Uploading Workflows ๐Ÿ“ฆ

Now that our cluster is launched, we use the Rsync-Cluster Command (#rsynccluster) utility to copy the workflow to the leader. For a simple workflow in a single file, it might look like this:

(venv) $ toil rsync-cluster -z us-west-2a my-cluster toil-workflow.py :/
๐Ÿ“š If your toil workflow has dependencies, have a look at the Auto-Deployment (#autodeploying) section for a detailed explanation of how to include them.

๐ŸŒˆ Running a Workflow with Autoscaling ๐ŸŒˆ

Toil can create an autoscaling Kubernetes cluster for you using the AWS provisioner. ๐Ÿคฉ Autoscaling is a feature of running Toil in the cloud where extra cloud instances get launched as needed to run the workflow. ๐Ÿ“ˆ

๐Ÿ› ๏ธ Make sure you've done the AWS setup in Preparing your AWS environment first!

To set up a Kubernetes cluster, just use the --clusterType=kubernetes command line option with toil launch-cluster. To make it autoscale, specify a range of possible node counts for a node type (such as -w 1-4). The cluster will automatically add and remove nodes within that range, depending on how many it needs to run the jobs submitted to the cluster. ๐Ÿฆ‹

For example, to launch a Toil cluster with a Kubernetes scheduler, run:

Okay so the full launch command looks like this, bestie ๐Ÿ’…

(venv) $ toil launch-cluster <cluster-name> \
        --provisioner=aws \
        --clusterType kubernetes \
        --zone us-west-2a \
        --keyPairName <AWS-key-pair-name> \
        --leaderNodeType t2.medium \
        --leaderStorage 50 \
        --nodeTypes t2.medium -w 1-4 \
        --nodeStorage 20 \
        --logDebug

Behind the scenes, Toil slides in kubeadm and sets up the kubelet on the Toil leader and every worker node ๐Ÿ”ง Once that's done, your cluster can schedule jobs with Kubernetes โœจ

Note: You need at least one worker node, or Kubernetes won't have anywhere to schedule any jobs ๐Ÿ˜ญ And yes, it's totally normal for this step to take a while.

For our demo we're bringing back sort.py ๐Ÿฆ‹ This time we run it on a Toil cluster with Kubernetes. First, download the file and drop it in your current working directory.

Next, copy the workflow file over and SSH into the cluster:

(venv) $ toil rsync-cluster -z us-west-2a <cluster-name> sort.py :/root
(venv) $ toil ssh-cluster -z us-west-2a <cluster-name>

Swap <cluster-name> for your real cluster name ๐Ÿ’– You can totally use your own cluster config and workflow files too. For more on this step, check the corresponding section of the Static Provisioning tutorial.

Important: There are some important caveats about kicking off a toil run through an ssh session. They're covered in the Ssh-Cluster Command section (#sshcluster), so go read that before you do anything wild ๐Ÿ™ˆ

Now that you're inside the cluster, a Kubernetes environment should already be configured and running โœจ To check, just run:

$ kubectl get nodes

You should see a leader node showing the Ready status. Depending on how many worker nodes you asked for upfront, you should see them listed here too ๐ŸŒธ

You can also check that the metrics server is running:

$ kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"

If you get a JSON response (kinda like the output below) and no errors, the metrics server is set up and running, and you're good to start running workflows ๐Ÿ’…

{"kind":"NodeMetricsList","apiVersion":"metrics.k8s.io/v1beta1", ...}
Note: All the nodes take a bit to get set up, so you might not see every single one running right away. You can start running workflows anyway, but Toil might throw a fit until the resources it needs are up and running ๐Ÿ™ƒ

Time to run the workflow:

$ python3 sort.py \
        --batchSystem kubernetes \
        aws:<region>:<job-store-name>

Make sure you replace <region> and <job-store-name> ๐Ÿซถ When you're using the Kubernetes batch system, you have to use a cloud-accessible job store, like AWS or Google.

The sort workflow should kick off on the Kubernetes cluster Toil set up for you โœจ This one takes a while to finish, so you can stick the job in the background and keep an eye on things with kubectl. For example, you can check out the pods that are running:

$ kubectl get pods

You should see something like this:

NAME                                                      READY   STATUS              RESTARTS   AGE
root-toil-a864e1b0-2e1f-48db-953c-038e5ad293c7-11-4cwdl   0/1     ContainerCreating   0          85s
root-toil-a864e1b0-2e1f-48db-953c-038e5ad293c7-14-5dqtk   0/1     Completed           0          18s
root-toil-a864e1b0-2e1f-48db-953c-038e5ad293c7-7-gkwc9    0/1     ContainerCreating   0          107s
root-toil-a864e1b0-2e1f-48db-953c-038e5ad293c7-9-t7vsb    1/1     Running             0          96s

If a pod fails for whatever reason, or you just want to make sure one isn't stuck, use kubectl describe pod <pod-name> or kubectl logs <pod-name> to inspect it ๐Ÿ”

If everything went well, you should see an output file from the sort workflow:

$ head sortedFile.txt

You can now run your own workflows! ๐ŸŽ€๐Ÿ‘‘


โœจ Preemptibility โœจ

Toil can run on a heterogeneous cluster that mixes preemptible and non-preemptible nodes ๐ŸŒˆ A preemptible node is basically one that can get shut down at any time, even while jobs are running. Those jobs can then be restarted later somewhere else ๐Ÿฆ‹

To make a node type preemptible, add a spot bid in dollars after a colon, right on its entry in the list of node types you pass to the --nodeTypes flag. The bid info lives at https://aws.amazon.com/ec2/spot/pricing/. If spot instance prices go above your bid, the preemptible nodes get shut down ๐Ÿ’€

For example, this cluster has both preemptible and non-preemptible nodes:

(venv) $ toil launch-cluster <cluster-name> \
        --provisioner=aws \
        --clusterType kubernetes \
        --zone us-west-2a \
        --keyPairName <AWS-key-pair-name> \
        --leaderNodeType t2.medium \
        --leaderStorage 50 \
        --nodeTypes t2.medium -w 1-4 \
        --nodeTypes t2.large:0.20 -w 1-4 \
        --nodeStorage 20 \
        --logDebug

Individual jobs can explicitly say whether they should run on preemptible nodes, using the boolean preemptible resource requirement in Toil's Python API ๐Ÿงš In CWL, this shows up as a hint https://doc.arvados.org/user/cwl/cwl-extensions.html called UsePreemptible in the http://arvados.org/cwl# namespace (usually imported as arv). In WDL, it's a runtime attribute https://cromwell.readthedocs.io/en/stable/RuntimeAttributes/#preemptible called preemptible, as recognized by Cromwell. Toil's Kubernetes batch system will prefer to put preemptible jobs on preemptible nodes ๐Ÿ’œ

If a job doesn't say it's preemptible, it won't run on preemptible nodes, even when they're available, unless you run the workflow with the --defaultPreemptible flag. That flag lets jobs without an explicit preemptible requirement run on preemptible machines. For example:

$ python3 /root/sort.py aws:us-west-2:<my-jobstore-name> \
        --batchSystem kubernetes \
        --defaultPreemptible
Specify Preemptibility Carefully ๐Ÿ˜ญ Make sure your choices for --nodeTypes and --maxNodes <> actually make sense for your workflow, or it could hang. The provisioner has to be able to create nodes big enough for the largest job in the workflow, and non-preemptible node types have to be allowed if the workflow has non-preemptible jobs.

โœจ Using MinIO and S3-Compatible object stores โœจ

Toil can access files stored in an S3-compatible object store, like https://en.wikipedia.org/wiki/Amazon_S3#S3_API_and_competing_services or https://min.io/ (MinIO) ๐ŸŒธ Use these environment variables to configure the S3 connection:

  • TOIL_S3_HOST โ€” the IP address or hostname to use for connecting to S3
  • TOIL_S3_PORT โ€” the port number to use for connecting to S3, if needed
  • TOIL_S3_USE_SSL โ€” turns SSL on or off for connecting to S3 (True by default)

Examples:

TOIL_S3_HOST=127.0.0.1
TOIL_S3_PORT=9010
TOIL_S3_USE_SSL=False

โœจ In-Workflow Autoscaling with Mesos โœจ

Instead of the usual Kubernetes-based autoscaling, you can use Toil's older Mesos-based method, where the scaling logic runs inside the Toil workflow itself ๐Ÿง  With this approach, a Toil cluster can only run one workflow at a time. It also doesn't work on the ARM architecture ๐Ÿ™ˆ

In this mode, the --preemptibleCompensation flag helps when preemptible nodes aren't available but your workflow needs them. With this flag on, the autoscaler tries to make up for a shortage of preemptible nodes of a certain type by creating non-preemptible nodes of that type, but only if non-preemptible nodes of that type were specified in --nodeTypes.

Note: This approach is deprecated, because the Mesos project isn't publishing up-to-date builds anymore ๐Ÿฅ€
  1. Download sort.py
  2. Launch a Mesos leader node in AWS using the Launch-Cluster Command (#launchcluster) command, without using any ranges of node counts:
(venv) $ toil launch-cluster <cluster-name> \
        --clusterType mesos \
        --keyPairName <AWS-key-pair-name> \
        --leaderNodeType t2.medium \
        --zone us-west-2a
  1. Copy the sort.py workflow up to the leader node:
(venv) $ toil rsync-cluster -z us-west-2a <cluster-name> sort.py :/root
  1. Log in to the leader node:
(venv) $ toil ssh-cluster -z us-west-2a <cluster-name>
  1. Run the workflow with in-workflow autoscaling, specifying a provisioner, node types, and counts as workflow arguments:
$ python3 /root/sort.py aws:us-west-2:<my-jobstore-name> \
        --provisioner aws \
        --nodeTypes c3.large \
        --maxNodes 2 \
        --batchSystem mesos
Note: In this example, the autoscaling Toil code creates up to two c3.large instances and launches Mesos agent containers inside them ๐Ÿซถ Those containers can then run the jobs defined by the sort.py workflow. Toil also creates an S3 bucket called aws:us-west-2:autoscaling-sort-jobstore to store intermediate job results. The Toil autoscaler can provision several different node types too, which is super useful for workflows with jobs that need different resources. For example, you could run the workflow with --nodeTypes c3.large,r3.xlarge --maxNodes 5,1, which lets the provisioner create up to five c3.large nodes and one r3.xlarge node for the memory-hungry jobs. In that case, the autoscaler holds off on creating the pricier r3.xlarge node until it's actually needed, and runs most jobs on the c3.large nodes ๐Ÿ’…
  1. View the generated file to sort:
$ head fileToSort.txt
  1. View the sorted file:
$ head sortedFile.txt

โœจ Dashboard โœจ

Toil has a dashboard for checking the RAM and CPU usage of each node, the number of issued jobs of each type, the number of failed jobs, and the size of the jobs queue ๐Ÿ“Š To launch it for a Toil workflow, pass the --metrics flag on the workflow's command line. Then, while you're connected to the leader node through toil ssh-cluster, you can view the dashboard in your browser at localhost:3000 ๐Ÿ‘‘

To change the default port, use the --grafana_port argument:

(venv) $ toil ssh-cluster -z us-west-2a --grafana_port 8000 <cluster-name>

On AWS, the dashboard is literally keeping tabs on every node in your cluster ๐Ÿ‘€ watching CPU and RAM usage like a hawk ๐Ÿฆ… But ngl, it also works when you're running a workflow on just one machine ๐Ÿ’… The dashboard uses Grafana as the front end for real-time plots โœจ and Prometheus for tracking the metrics toil exports ๐Ÿ“Š: [image]

Bestie, if you want the dashboard for a non-released toil version ๐Ÿ™ˆ you'll have to build the containers locally with make docker. The reason is that the prometheus, grafana, and mtail containers used in the dashboard are tied to a specific toil version ๐Ÿ”’


๐ŸŒธ Running in Google Compute Engine (GCE) ๐ŸŒธ

Okay so toil has a provisioner for Google ๐Ÿซถ and a Google Job Store too! To get started, follow the instructions for Preparing your Google environment.


๐Ÿ”‘ Preparing your Google environment

Toil supports using the Google Cloud Platform https://cloud.google.com/storage/. Setting this up is easy-peasy ๐Ÿงš

  1. Make sure the google extra (Installing Toil with Extra Features #extras) is installed
  2. Follow Google's Instructions (https://cloud.google.com/docs/authentication/getting-started) to download credentials and set the GOOGLE_APPLICATION_CREDENTIALS environment variable
  3. Create a new ssh key with the proper format. To make one, run this command:
$ ssh-keygen -t rsa -f ~/.ssh/id_rsa -C [USERNAME]

where [USERNAME] is something like jane@example.com. Make sure to leave your password blank.

Warning: This command could overwrite an old ssh key you may be using. If you have an existing ssh key you would like to use, it will need to be called id_rsa and it needs to have no password set.

Make sure only you can read the SSH keys ๐Ÿ”:

$ chmod 400 ~/.ssh/id_rsa ~/.ssh/id_rsa.pub
  1. Add your newly formatted public key to Google ๐Ÿ’œ Log into your Google Cloud account and head to the metadata section (https://console.cloud.google.com/compute/metadata) under the Compute tab. [image]

Near the top of the screen, click on 'SSH Keys', then edit, add item, and paste the key. Then save: [image]

For more details, look at Google's instructions for adding SSH keys (https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys).


๐Ÿ—๏ธ Google Job Store

To use the Google Job Store, you'll need to set GOOGLE_APPLICATION_CREDENTIALS by following Google's instructions (https://cloud.google.com/docs/authentication/getting-started).

Then, to run the sort example with the Google job store, you would type:

$ python3 sort.py google:my-project-id:my-google-sort-jobstore

๐Ÿš€ Running a Workflow with Autoscaling

Warning: Google Autoscaling is in beta!

The steps to run a GCE workflow are super similar to the AWS ones (Running a Workflow with Autoscaling #autoscaling), except you'll need to explicitly specify the --provisioner gce option. Otherwise it defaults to aws, so don't skip it ๐Ÿ™…โ€โ™€๏ธ

  1. Download sort.py
  2. Launch the leader node in GCE using the Launch-Cluster Command (#launchcluster) command:
(venv) $ toil launch-cluster <CLUSTER-NAME> \
             --provisioner gce \
             --leaderNodeType n1-standard-1 \
             --keyPairName <SSH-KEYNAME> \
             --zone us-west1-a

Where <SSH-KEYNAME> is the first part of [USERNAME] you used when setting up your ssh key. For example, if [USERNAME] was <jane@example.com>, then <SSH-KEYNAME> should be jane.

The --keyPairName option is for an SSH key that was added to the Google account. If your ssh key [USERNAME] was jane@example.com, then your key pair name will be just jane ๐Ÿ’–

  1. Upload the sort example and ssh into the leader:
(venv) $ toil rsync-cluster --provisioner gce <CLUSTER-NAME> sort.py :/root
(venv) $ toil ssh-cluster --provisioner gce <CLUSTER-NAME>
  1. Run the workflow ๐Ÿ”ฅ:
$ python3 /root/sort.py  google:<PROJECT-ID>:<JOBSTORE-NAME> \
      --provisioner gce \
      --batchSystem mesos \
      --nodeTypes n1-standard-2 \
      --maxNodes 2
  1. Clean up ๐Ÿงน:
$ exit  # this exits the ssh from the leader node
(venv) $ toil destroy-cluster --provisioner gce <CLUSTER-NAME>

โœจ HPC ENVIRONMENTS โœจ

Okay so Toil is a super flexible framework ๐Ÿ’… that can be used in a bunch of different environments, including high-performance computing (HPC) environments ๐Ÿ–ฅ๏ธ It supports a whole squad of batch systems, like Grid Engine (http://www.univa.com/oracle), Slurm (https://www.schedmd.com/), Torque (http://www.adaptivecomputing.com/products/open-source/torque/), and LSF (https://en.wikipedia.org/wiki/Platform_LSF). These are the popular schedulers you'll find in HPC land โœจ Toil also supports HTCondor (https://research.cs.wisc.edu/htcondor/), which is a fave for high-throughput computing (HTC) ๐Ÿงš To use one of these batch systems, specify the --batchSystem argument to the workflow.

Due to the cost and complexity of keeping support for these schedulers up, we currently consider everything except Slurm to be "community supported" ๐Ÿซถ That means the core dev team doesn't regularly test or develop support for them. BUT there are members of the Toil community deploying Toil in all kinds of HPC environments right now, and we 100% welcome external contributions ๐Ÿ’œ

Want to add support for a new or existing batch system? Then you'll be extending the abstract batch system class toil.batchSystems.abstractBatchSystem.AbstractBatchSystem ๐Ÿ”ฅ

๐ŸŒŠ Running on Slurm ๐ŸŒŠ

When you run Toil workflows on Slurm, you usually want to run the workflow itself from the head node ๐Ÿ‘‘ Toil takes care of running all the required sbatch commands for you. You probably do not want to submit the Toil workflow as a Slurm job with sbatch (although you can if you have a large number of workflows to run ๐Ÿ™ˆ). You also probably do not want to manually allocate resources with sallocate ๐Ÿ’€

To run a Toil workflow on Slurm, include --batchSystem slurm in your command line arguments. Slurm clusters generally have shared filesystems, which means the file job store would be appropriate ๐Ÿฆ‹ Just make sure your job store location is shared across your whole Slurm cluster. You'll also likely want another shared directory via the --batchLogsDir option, so Toil can retrieve the Slurm job logs if something goes wrong with a job ๐Ÿ“

For example, to run the sort example on Slurm (assuming you're in a shared directory), you'd type this on the cluster head node:

$ mkdir -p logs
$ python3 sort.py ./store --batchSystem slurm --batchLogsDir ./logs

By default, this does not include any time limit or particular Slurm partition. If your Slurm cluster requires time limits, add the --slurmTime option to set the time limit for jobs โฐ

If you do specify a time limit, a partition will be automatically selected that can fit jobs of that duration, and a partition will be automatically selected for jobs that need GPUs ๐ŸŽ€ To use a particular partition, use the --slurmPartition argument. If your GPU jobs need to go to a different partition, use the --slurmGPUPartition argument. For example, to run a WDL workflow from Dockstore using GPUs on Slurm, with a 4 hour time limit per job and partitions manually specified, you'd run:

$ toil-wdl-runner '#workflow/github.com/vgteam/vg_wdl/GiraffeDeepVariantFromGAF:gbz' \
  https://raw.githubusercontent.com/vgteam/vg_wdl/refs/heads/gbz/params/giraffe_and_deepvariant_gaf.json \
  --jobStore ./store --batchSystem slurm --batchLogsDir ./logs \
  --slurmTime 4:00:00 --slurmPartition medium --slurmGPUPartition gpu

Any extra sbatch arguments your cluster needs that Toil doesn't directly support can be passed via the Toil --slurmArgs option, or the TOIL_SLURM_ARGS environment variable ๐Ÿงš (Heads up: there's special handling for some Slurm options Toil needs to interact with, like --time or --partition, if they get passed this way โš ๏ธ)

๐Ÿ’… Slurm Tips ๐Ÿ’…

  1. If you're running containers with Singularity on Slurm (like in WDL workflows), make sure Singularity caching and Toil's MiniWDL caching use a shared directory across your cluster nodes ๐ŸŒˆ By default, Toil configures Singularity to cache per-workflow and per-node, but on Slurm a shared filesystem is almost always available. Assuming your home directory is shared, you can set this up like so:
$ echo 'export SINGULARITY_CACHEDIR="${HOME}/.singularity/cache"' >>~/.bashrc
$ echo 'export MINIWDL__SINGULARITY__IMAGE_CACHE="${HOME}/.cache/miniwdl"' >>~/.bashrc

Then log out and back in again so the setting takes effect ๐Ÿ”„

  1. If your home directory is not shared across the cluster nodes, make sure you've installed Toil in such a way that it's in your PATH on the cluster nodes ๐Ÿ—บ๏ธ
  2. Slurm sandboxing and resource limits do not apply to Docker containers ๐Ÿ’€ There's no relationship between the sandbox cgroup your Toil job runs in and the sandbox cgroup the Docker daemon creates for the container your job requested. If you want your Toil jobs' containers to actually live inside their Slurm job resource allocations, run containers with Singularity or another user-mode or daemon-less containerization system ๐Ÿฆ‹
  3. Slurm can sometimes report that a job has finished before that job's changes to the cluster's shared filesystem are visible to other nodes or the head node ๐Ÿ˜ญ Toil tries to anticipate and compensate for this, but there's no amount of waiting or retrying that could guarantee correct behavior in theory. In theory, the shared filesystem could be days or months behind! In practice the delay is usually no more than a few seconds, and Toil can handle that ๐Ÿ’– But if you're seeing odd behavior from Toil where files don't exist when they should, or still exist when they shouldn't, your cluster's filesystem might just be unusually slow to reach consistency across nodes ๐Ÿข
  4. If you see warnings about XDG_RUNTIME_DIR, your Slurm cluster might not be managing XDG login sessions correctly for Slurm jobs ๐Ÿฅบ Toil can work around this, but as a result the workaround might have trouble finding an appropriate "coordination directory" where it can store state files local to each Slurm node. If you're seeing unusual stuff like Toil jobs on one node waiting on operations on a different node, you can try giving Toil a path to a per-node, writable directory with the --coordinationDir option, so it knows exactly where to put those files ๐Ÿ—‚๏ธ
  5. With a shared filesystem, Toil's caching system is not necessarily going to help your workflow ๐Ÿคทโ€โ™€๏ธ Try running and timing test workflows with --caching true and with --caching false to figure out whether copying files from the shared filesystem to local storage on each node is worth it for your workload โฑ๏ธ
  6. If you're running CWL workflows on Slurm with a shared filesystem, you can try the --bypass-file-store option to toil-cwl-runner โœจ It may speed up your workflow, but you may also need to change Toil's work directory to a shared directory provided with the --workDir option so it works properly across machines ๐Ÿƒโ€โ™€๏ธ

๐Ÿ“‚ Standard Output/Error from Batch System Jobs ๐Ÿ“‚

Standard output and error from batch system jobs (except for the Mesos batch system) get redirected to files in the toil-<workflowID> directory, which is created inside the temporary directory specified by the --workDir option ๐Ÿง (See COMMANDLINE OPTIONS for more on that one ๐Ÿ’œ) Each file is named like this: toil_job_<Toil job ID>_batch_<name of batch system>_<job ID from batch system>_<file description>.log, where <file description> is std_output for standard output and std_error for standard error. HTCondor will also write job event log files, with <file description> set to job_events ๐Ÿ“œ

If you want to capture standard output and error, --workDir will generally need to be on a shared file system ๐Ÿ—„๏ธ Otherwise, if these get written to local temporary directories on each node (like /tmp), Toil won't be able to retrieve them ๐Ÿ˜ญ Alternatively, the --noStdOutErr option forces Toil to discard all standard output and error from batch system jobs ๐Ÿ—‘๏ธ


๐ŸŒ WORKFLOW EXECUTION SERVICE (WES) ๐ŸŒ

The GA4GH Workflow Execution Service (WES) is a standardized API for submitting and monitoring workflows ๐Ÿฆ‹ Toil has experimental support for setting up a WES server and executing CWL, WDL, and Toil workflows through the WES API ๐Ÿงš You can read more about the WES API specification here: https://ga4gh.github.io/workflow-execution-service-schemas/docs/

To get started with the Toil WES server, make sure the server extra is installed (see Installing Toil with Extra Features) ๐ŸŽ€

๐Ÿฐ Preparing your WES environment ๐Ÿฐ

The WES server needs Celery (https://docs.celeryproject.org/en/stable/getting-started/introduction.html) to distribute and execute workflows ๐Ÿ’– To set up Celery:

  1. Start RabbitMQ, which is the broker between the WES server and the Celery workers ๐Ÿ‡
docker run -d --name wes-rabbitmq -p 5672:5672 rabbitmq:3.9.5
  1. Start the Celery workers ๐Ÿ‘ทโ€โ™€๏ธ
celery -A toil.server.celery_app worker --loglevel=INFO

๐Ÿš€ Starting a WES server ๐Ÿš€

To start a WES server on the default port 8080, run the Toil command:

$ toil server

The WES API will be hosted at this URL:

http://localhost:8080/ga4gh/wes/v1

Want a different port, like 3000? Just specify the --port argument:

$ toil server --port 3000

There are lots of other command line options too ๐ŸŒธ To find help info, run this command:

$ toil server --help

Here's a detailed rundown of all the server-specific options ๐Ÿ‘‘

  • --debug โ€” Turns on debug mode ๐Ÿž
  • --bypass_celery โ€” Skips sending workflows to Celery and just runs them under the server. This one's for testing ๐Ÿงช
  • --host HOST โ€” The host interface the Toil server binds to (default: "127.0.0.1") ๐Ÿ 
  • --port PORT โ€” The port the Toil server listens on (default: 8080) ๐Ÿ”Œ
  • --swagger_ui โ€” If True, the swagger UI gets enabled and hosted at the {api_base_path}/ui endpoint (default: False) ๐Ÿ“–
  • --cors โ€” Enables Cross Origin Resource Sharing (CORS). Only turn this on if the server is meant to be used by a website or domain ๐ŸŒ (default: False).
  • --cors_origins CORS_ORIGIN โ€” Ignored if --cors is False. This sets the allowed origins for CORS. For details about CORS and its security risks, check the GA4GH docs on CORS at https://w3id.org/ga4gh/product-approval-support/cors โš ๏ธ (default: "*").
  • --workers WORKERS, -w WORKERS โ€” Ignored if --debug is True ๐Ÿ™ˆ Otherwise this sets how many worker processes the WSGI server launches. Default is 2 ๐Ÿ’–.
  • --work_dir WORK_DIR โ€” ๐Ÿ“ This is where your workflows get stored. Ideally the folder is empty, or only has old workflows in it ๐Ÿงน. Default is './workflows' ๐ŸŒธ.
  • --state_store STATE_STORE โ€” โ˜๏ธ The local path or S3 URL where workflow state metadata gets saved. Default is in --work_dir โœจ.
  • --opt OPT, -o OPT โ€” ๐ŸŽ€ Set the default parameters that get sent to the workflow engine for every run. Options that take arguments have to use = syntax. You can pass this more than once. Example: --opt=--logLevel=CRITICAL --opt=--workDir=/tmp ๐Ÿ’….
  • --dest_bucket_base DEST_BUCKET_BASE โ€” ๐Ÿชฃ Tells CWL workflows to save output files to dynamically generated unique paths under the URL you give. Supports AWS S3 ๐Ÿฆ‹.
  • --wes_dialect DIALECT โ€” ๐Ÿงš Limits WES responses to a dialect that works with clients that don't fully implement the WES standard. Default is 'standard' ๐Ÿ‘‘.

โœจ Running the Server with docker-compose โœจ

Instead of setting up the server pieces by hand (toil server, RabbitMQ, and Celery), you can use the docker-compose.yml file below to orchestrate and link them all together ๐Ÿซถ.

Make sure to change the credentials for basic authentication by updating the traefik.http.middlewares.auth.basicauth.users label ๐Ÿ”. You can generate the passwords with tools like htpasswd. Here's the guide: https://doc.traefik.io/traefik/v2.0/middlewares/basicauth/#configuration-examples. (Heads up: single $ signs need to be replaced with $$ in the yaml file ๐Ÿ™ˆ.)

When you're running on a host other than localhost, change the Host to your target host in the traefik.http.routers.wes.rule and traefik.http.routers.wespublic.rule labels ๐ŸŒˆ.

You can also change /tmp/toil-workflows if you want Toil workflows to live somewhere else. Just create the directory before starting the server ๐Ÿ“‚.

To run workflows that need Docker, the docker.sock socket has to be mounted as a volume for Celery ๐Ÿณ. Also, the TOIL_WORKDIR directory (defaults to: /var/lib/toil) and /var/lib/cwl (if you're running CWL workflows with DockerRequirement) should exist on the host and get mounted as volumes too ๐Ÿ’œ.

๐Ÿšจ Run this behind a firewall, bestie! It opens up the Toil server on port 8080 to anyone who connects. Not a vibe ๐Ÿ’€.
# docker-compose.yml
version: "3.8"

services:
  rabbitmq:
    image: rabbitmq:3.9.5
    hostname: rabbitmq
  celery:
    image: ${TOIL_APPLIANCE_SELF}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker:/var/lib/docker
      - /var/lib/toil:/var/lib/toil
      - /var/lib/cwl:/var/lib/cwl
      - /tmp/toil-workflows:/tmp/toil-workflows
    command: celery --broker=amqp://guest:guest@rabbitmq:5672// -A toil.server.celery_app worker --loglevel=INFO
    depends_on:
      - rabbitmq
  wes-server:
    image: ${TOIL_APPLIANCE_SELF}
    volumes:
      - /tmp/toil-workflows:/tmp/toil-workflows
    environment:
      - TOIL_WES_BROKER_URL=amqp://guest:guest@rabbitmq:5672//
    command: toil server --host 0.0.0.0 --port 8000 --work_dir /tmp/toil-workflows
    expose:
      - 8000
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wes.rule=Host(`localhost`)"
      - "traefik.http.routers.wes.entrypoints=web"
      - "traefik.http.routers.wes.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=test:$$2y$$12$$ci.4U63YX83CwkyUrjqxAucnmi2xXOIlEF6T/KdP9824f1Rf1iyNG"
      - "traefik.http.routers.wespublic.rule=Host(`localhost`) && Path(`/ga4gh/wes/v1/service-info`)"
    depends_on:
      - rabbitmq
      - celery
  traefik:
    image: traefik:v2.2
    command:
      - "--providers.docker"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:8080"
    ports:
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

Want more customization? Go for it ๐Ÿ’…. For example, if you have a domain, you can set up HTTPS with Let's Encrypt. The guide is here: https://doc.traefik.io/traefik/user-guides/docker-compose/acme-http/ ๐Ÿ”’.

Once everything is configured, just run docker-compose up to start the containers ๐Ÿš€. Run docker-compose down to stop and remove all of them ๐Ÿงน.

๐Ÿ“ Note: docker-compose is not installed on the Toil appliance by default. Check out the next section to set up the WES server on a Toil cluster ๐Ÿซถ.

โœจ Running on a Toil cluster โœจ

To run the server on a Toil leader instance on EC2:

  1. Launch a Toil cluster with the toil launch-cluster command with the AWS provisioner ๐Ÿš€.
  2. SSH into your cluster with the --sshOption=-L8080:localhost:8080 option to forward port 8080 ๐Ÿฆ‹.
  3. Install Docker Compose by running the following commands from the Docker docs. The guide is here: https://docs.docker.com/compose/install/#install-compose ๐Ÿณ.
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

# check installation
docker-compose --version

Or, want a different version of Docker Compose? Just change "1.29.2" to whatever version you want ๐ŸŒˆ.

  1. Copy the docker-compose.yml file from (Running the Server with docker-compose) into an empty directory, then tweak the configuration as needed ๐Ÿ’–.
  2. Now run docker-compose up -d to start the WES server in detach mode on the Toil appliance ๐ŸŒ™.
  3. To stop the server, run docker-compose down ๐Ÿ›‘.

โœจ WES API Endpoints โœจ

The GA4GH WES API spec defines these endpoints, all with base path ga4gh/wes/v1/, and Toil supports every single one ๐Ÿ‘‘:

  • GET /service-info โ€” โ„น๏ธ Get info about the Workflow Execution Service.
  • GET /runs โ€” ๐Ÿ“‹ List the workflow runs.
  • POST /runs โ€” ๐Ÿš€ Run a workflow. This creates a new workflow run and returns a run_id so you can keep an eye on its progress ๐Ÿ‘€.
  • GET /runs/{run_id} โ€” ๐Ÿ” Get detailed info about a workflow run.
  • POST /runs/{run_id}/cancel โ€” ๐Ÿ›‘ Cancel a running workflow.
  • GET /runs/{run_id}/status โ€” ๐Ÿšฆ Get the status (overall state) of a workflow run.

When you run the WES server with the docker-compose setup above, most endpoints (everything except GET /service-info) are protected with basic authentication ๐Ÿ”. Make sure to set the Authorization header with the correct credentials when you submit or retrieve a workflow ๐Ÿ’œ.


โœจ Submitting a Workflow โœจ

Now that the WES API is up and running, you can submit and monitor workflows remotely with the WES API endpoints ๐Ÿงš. Submit a workflow for execution with the POST /runs endpoint ๐Ÿƒโ€โ™€๏ธ.

As a quick example, we can submit the example CWL workflow from Running a basic CWL workflow to our WES API ๐ŸŽ€:

# example.cwl
cwlVersion: v1.0
class: CommandLineTool
baseCommand: echo
stdout: output.txt
inputs:
 message:
   type: string
   inputBinding:
     position: 1
outputs:
 output:
   type: stdout

Using cURL ๐ŸŒธ:

$ curl --location --request POST 'http://localhost:8080/ga4gh/wes/v1/runs' \
    --user test:test \
    --form 'workflow_url="example.cwl"' \
    --form 'workflow_type="cwl"' \
    --form 'workflow_type_version="v1.0"' \
    --form 'workflow_params="{\"message\": \"Hello world!\"}"' \
    --form 'workflow_attachment=@"./toil_test_files/example.cwl"'
{
  "run_id": "4deb8beb24894e9eb7c74b0f010305d1"
}

The --user argument attaches your basic authentication credentials to the request ๐Ÿ”‘. Make sure to change test:test to the username and password you configured for your WES server ๐Ÿซถ. Or, if you'd rather, set the Authorization header yourself as "Authorization: Basic base64_encoded_auth" ๐Ÿ’….

If the workflow gets submitted successfully, you'll get back a JSON object containing a run_id ๐ŸŽ‰. That run_id is a unique identifier for your requested workflow, and you can use it to monitor or cancel the run ๐Ÿฆ‹.

There are a few required parameters that have to be set for every workflow submission, so don't skip any of them, bestie ๐ŸŽ€

  • workflow_url โ€” the URL of the workflow you want to run. It can point to a file from workflow_attachment ๐Ÿ”—
  • workflow_type โ€” the workflow language. Toil currently supports "CWL", "WDL", or "py". If you're running a Toil Python workflow, set this to "py" ๐Ÿ
  • workflow_type_version โ€” the version of the workflow language. To see which versions your WES server supports, check the GET /service-info endpoint โœจ
  • workflow_params โ€” a JSON object that specifies the inputs of the workflow ๐Ÿ’–

Then there are some optional parameters you can add too ๐Ÿ’…

  • workflow_attachment โ€” a list of files tied to the workflow run ๐Ÿ“Ž
  • workflow_engine_parameters โ€” a JSON key-value map of workflow engine parameters that gets sent to the runner. Example: {"--logLevel": "INFO", "--workDir": "/tmp/"} ๐Ÿฆ‹
  • tags โ€” a JSON key-value map of metadata attached to the workflow ๐Ÿท๏ธ

For the full scoop on these parameters, check out the Run Workflow section of the WES API spec at https://ga4gh.github.io/workflow-execution-service-schemas/docs/#operation/RunWorkflow ๐Ÿ“š

โœจ Upload multiple files โœจ

Okay so, look at the body of the request from the previous example. The workflow_url is a relative URL that points at the example.cwl file, which gets uploaded from the local path ./toil_test_files/example.cwl ๐Ÿ“‚

If you want to choose the file name (or subdirectory) of the remote destination file, set the filename field in the Content-Disposition header. You can also upload more than one file by passing the workflow_attachment parameter multiple times, each with a different file. It's giving organized ๐ŸŒธ

Here's what that looks like:

$ curl --location --request POST 'http://localhost:8080/ga4gh/wes/v1/runs' \
    --user test:test \
    --form 'workflow_url="example.cwl"' \
    --form 'workflow_type="cwl"' \
    --form 'workflow_type_version="v1.0"' \
    --form 'workflow_params="{\"message\": \"Hello world!\"}"' \
    --form 'workflow_attachment=@"./toil_test_files/example.cwl"' \
    --form 'workflow_attachment=@"./toil_test_files/2.fasta";filename=inputs/test.fasta' \
    --form 'workflow_attachment=@"./toil_test_files/2.fastq";filename=inputs/test.fastq'

On the server, the execution directory ends up with this structure after that request ๐Ÿงš

execution/
โ”œโ”€โ”€ example.cwl
โ”œโ”€โ”€ inputs
โ”‚     โ”œโ”€โ”€ test.fasta
|     โ””โ”€โ”€ test.fastq
โ””โ”€โ”€ wes_inputs.json

โœจ Specify Toil options โœจ

To pass Toil-specific parameters to the workflow, include the workflow_engine_parameters parameter with your request ๐ŸŽ€

For example, if you want to set the logging level to INFO and change the working directory of the workflow, just add this as your workflow_engine_parameters:

{"--logLevel": "INFO", "--workDir": "/tmp/"}

These options get appended to the end of the existing parameters during command construction, which means they override the default parameters if you provide them. (Default parameters that can be passed multiple times won't be overridden ๐Ÿ™ˆ)

โœจ Monitoring a Workflow โœจ

Once you submit a workflow, you get back a run_id. With that, you can check the status or pull the full logs of the workflow run ๐Ÿ‘€

โœจ Checking the state โœจ

The GET /runs/{run_id}/status endpoint gives you a simple result with the overall state of your run ๐Ÿ’œ

$ curl --user test:test http://localhost:8080/ga4gh/wes/v1/runs/4deb8beb24894e9eb7c74b0f010305d1/status
{
  "run_id": "4deb8beb24894e9eb7c74b0f010305d1",
  "state": "RUNNING"
}

The possible states are: QUEUED, INITIALIZING, RUNNING, COMPLETE, EXECUTOR_ERROR, SYSTEM_ERROR, CANCELING, and CANCELED ๐ŸŒˆ

โœจ Getting the full logs โœจ

To get the detailed info about a workflow run, hit the GET /runs/{run_id} endpoint ๐Ÿ“

$ curl --user test:test http://localhost:8080/ga4gh/wes/v1/runs/4deb8beb24894e9eb7c74b0f010305d1
{
  "run_id": "4deb8beb24894e9eb7c74b0f010305d1",
  "request": {
    "workflow_attachment": [
      "example.cwl"
    ],
    "workflow_url": "example.cwl",
    "workflow_type": "cwl",
    "workflow_type_version": "v1.0",
    "workflow_params": {
      "message": "Hello world!"
    }
  },
  "state": "RUNNING",
  "run_log": {
    "cmd": [
      "toil-cwl-runner --outdir=/home/toil/workflows/4deb8beb24894e9eb7c74b0f010305d1/outputs --jobStore=file:/home/toil/workflows/4deb8beb24894e9eb7c74b0f010305d1/toil_job_store /home/toil/workflows/4deb8beb24894e9eb7c74b0f010305d1/execution/example.cwl /home/workflows/4deb8beb24894e9eb7c74b0f010305d1/execution/wes_inputs.json"
    ],
    "start_time": "2021-08-30T17:35:50Z",
    "end_time": null,
    "stdout": null,
    "stderr": null,
    "exit_code": null
  },
  "task_logs": [],
  "outputs": {}
}

โœจ Canceling a run โœจ

Want to stop a run? Use the POST /runs/{run_id}/cancel endpoint ๐Ÿ›‘

$ curl --location --request POST 'http://localhost:8080/ga4gh/wes/v1/runs/4deb8beb24894e9eb7c74b0f010305d1/cancel' \
      --user test:test
{
  "run_id": "4deb8beb24894e9eb7c74b0f010305d1"
}

โœจ DEVELOPING A PYTHON WORKFLOW โœจ

This tutorial walks you through the Toil features you need to develop a workflow with the Toil Python API. ๐Ÿ๐Ÿ’–

โœจ Scripting Quick Start โœจ

To start, check out this short Toil Python workflow, which shows how to define a workflow ๐Ÿ‘‘

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

def helloWorld(message):
    return f"Hello, world!, here's a message: {message}"

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_quickstart")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "OFF"
    options.clean = "always"

    hello_job = Job.wrapFn(helloWorld, "Woot")

    with Toil(options) as toil:
        print(toil.start(hello_job))  # prints "Hello, world!, ..."

This workflow is made up of a single job. You can (optionally) set that job's resource requirements with the keyword arguments memory, cores, and disk. The workflow runs through toil.job.Job.Runner.getDefaultOptions() ๐ŸŒŸ We'll break down the components of this code in detail below.

โœจ Job Basics โœจ

The atomic unit of work in a Toil workflow is a Job. Your code extends this base class, or uses helper methods like toil.job.Job.addChildJobFn(), to define units of work. For example, here's a longer, class-based version of the job from the quick start example ๐Ÿฆ‹

from toil.job import Job

class HelloWorld(Job):
    def __init__(self, message):
        Job.__init__(self,  memory="2G", cores=2, disk="3G")
        self.message = message

    def run(self, fileStore):
        return f"Hello, world! Here's a message: {self.message}"

In this example, a class called HelloWorld is defined. The constructor requests 2 gigabytes of memory, 2 cores, and 3 gigabytes of local disk to complete the work ๐Ÿ’œ

The toil.job.Job.run() method is the function you override to get work done. Here, it just returns a message ๐Ÿซถ

You can also log a message using toil.job.Job.log(), which gets registered in the log output of the leader process of the workflow ๐Ÿ“

...
    def run(self, fileStore):
        self.log(f"Hello, world! Here's a message: {self.message}")

โœจ Invoking a Workflow โœจ

okay so we can take the previous example and make it a whole complete workflow ๐Ÿ’… by adding the function calls that create a HelloWorld instance and run it as a workflow with one single job. like this:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

class HelloWorld(Job):
    def __init__(self, message):
        Job.__init__(self)
        self.message = message

    def run(self, fileStore):
        return f"Hello, world!, here's a message: {self.message}"

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_invokeworkflow")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "OFF"
    options.clean = "always"

    hello_job = HelloWorld("Woot")

    with Toil(options) as toil:
        print(toil.start(hello_job))
๐Ÿ™ˆ Heads up, bestie: Do not include a . in the name of your python script (besides .py at the end). This is so toil can import the types and functions defined in your file while starting a new process.

This uses the toil.common.Toil class, and it's the thing that actually runs and resumes Toil workflows ๐Ÿฆ‹. You use it as a context manager, and it lets you do preliminary setup, like staging files into the job store on the leader node. You make an instance of it by handing it an options object. Then you invoke the actual workflow by calling toil.common.Toil.start() and passing it the root job. But if a workflow is being restarted, you use toil.common.Toil.restart() instead. Also, the context manager should have explicit if else branches for the restart and non-restart cases, and the boolean for those branches is toil.options.restart ๐Ÿซถ.

Here's how that looks:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

class HelloWorld(Job):
    def __init__(self, message):
        Job.__init__(self)
        self.message = message

    def run(self, fileStore):
        return f"Hello, world!, I have a message: {self.message}"

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_invokeworkflow2")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        if not toil.options.restart:
            job = HelloWorld("Woot!")
            output = toil.start(job)
        else:
            output = toil.restart()
    print(output)

The call to toil.job.Job.Runner.getDefaultOptions() is giving main character energy ๐Ÿ‘‘, because it creates a whole set of default options for the workflow. The only argument is a description of how to store the workflow's state in what we call a job-store. In this example the job-store lives in a directory inside the current working directory called "toilWorkflowRun". You can also make this string encode other ways to store the necessary state, like an S3 bucket object store location ๐Ÿ“. By default, the job-store gets deleted if the workflow completes successfully.

The workflow runs on the final line, where we make a HelloWorld and run it as a workflow. Every Toil workflow starts from a single starting job, called the root job ๐ŸŒธ. The return value of the root job becomes the result of the completed workflow. (Check out promises below to see why this is so useful!)


โœจ Specifying Commandline Arguments โœจ

If you want to control the options from the command line, you can use toil.job.Job.Runner.getDefaultArgumentParser() to make a configargparse.ArgParser object. That object can parse command line options for a Toil Python workflow, and it's honestly so clean ๐Ÿงš. Here's an example:

from toil.common import Toil
from toil.job import Job

class HelloWorld(Job):
    def __init__(self, message):
        Job.__init__(self)
        self.message = message

    def run(self, fileStore):
        return "Hello, world!, here's a message: %s" % self.message

if __name__ == "__main__":
    parser = Job.Runner.getDefaultArgumentParser()
    options = parser.parse_args()
    options.logLevel = "OFF"
    options.clean = "always"

    hello_job = HelloWorld("Woot")

    with Toil(options) as toil:
        print(toil.start(hello_job))

This makes a fully fledged Toil Python workflow with every option Toil exposes as a command line argument. Running this program with --help will print the full list of options ๐Ÿ’–.

Alternatively, any existing argparse.ArgumentParser object (see /usr/share/doc/python3/html/library/argparse.html#argparse.ArgumentParser) can get Toil command line options added to it with the toil.job.Job.Runner.addToilOptions() method. BUT ๐Ÿ˜ญ if it isn't also a configargparse.ArgParser, it won't read the Toil config file or the environment variables that Toil uses as alternatives to command-line options, and that can lead to unexpected behavior. Don't be that person ๐Ÿ’€.


โœจ Resuming a Workflow โœจ

Sometimes a workflow fails. Maybe a job had a programmatic error, or maybe a node died. Either way, the workflow can be resumed ๐Ÿ”ฅ. The only time it can't be reliably resumed is if the job-store itself becomes corrupt.

Here's the critical part: jobs have to be rerunnable, even if they look like they finished successfully. Put simply, a user-defined job should never corrupt its input arguments. That way, no matter whether a node, the network or the leader fails, the job can restart and the workflow can pick back up ๐Ÿฆ‹.

To resume, specify the "restart" option in the options object you pass to toil.common.Toil.start(). If you expect node failures, it can also help to use the integer "retryCount" option, which tries to rerun a job retryCount number of times before marking it fully failed.

If a small subset of jobs fails (retry attempts included), Toil keeps running the other jobs until it can't do anything else. At that point, toil.common.Toil.start() raises a toil.exceptions.FailedJobsException exception โญ. Usually this is when you decide whether to fix the script and resume, or delete the job-store manually and rerun the whole workflow from scratch.


โœจ Functions and Job Functions โœจ

Making jobs out of class definitions means writing a constructor every single time, and ugh, boilerplate ๐Ÿ™„. So to skip that, toil.job.FunctionWrappingJob and toil.job.JobFunctionWrappingTarget let you turn plain functions straight into jobs. Here's the quick start example, repeated for your viewing pleasure:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

def helloWorld(message):
    return f"Hello, world!, here's a message: {message}"

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_quickstart")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "OFF"
    options.clean = "always"

    hello_job = Job.wrapFn(helloWorld, "Woot")

    with Toil(options) as toil:
        print(toil.start(hello_job))  # prints "Hello, world!, ..."

This is basically the same as the previous example, just using a function to define the job โœจ.

The function call that does the wrapping is:

Job.wrapFn(helloWorld, "Woot")

It creates an instance of the toil.job.FunctionWrappingTarget that wraps the function ๐Ÿงš.

The keyword arguments memory, cores and disk let you set resource requirements, same as before. Even if they aren't in the function header as keyword arguments, you can still pass them when you wrap the function as a job, and they'll be used to set the resource requirements ๐Ÿ’….

You can also wrap a job function, which is a function whose first argument is a reference to the wrapping job. Just like a self argument in a class, this gives you access to the methods of the wrapping job (see toil.job.JobFunctionWrappingTarget). Here's an example:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

def helloWorld(job, message):
    job.log(f"Hello world, I have a message: {message}")

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_jobfunctions")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    hello_job = Job.wrapJobFn(helloWorld, "Woot!")

    with Toil(options) as toil:
        toil.start(hello_job)

Here helloWorld() is a job function. It uses toil.job.Job.log() to log a message that gets printed to the output console ๐ŸŽ€. The only subtle difference to note is this line:

hello_job = Job.wrapJobFn(helloWorld, "Woot")

It uses toil.job.Job.wrapJobFn() to wrap the job function, instead of toil.job.Job.wrapFn(), which wraps a vanilla function ๐Ÿ”ฅ.


โœจ Workflows with Multiple Jobs โœจ

A parent job can have child jobs and follow-on jobs ๐ŸŒˆ. These relationships get set up with methods on the job class, like toil.job.Job.addChild() and toil.job.Job.addFollowOn().

Think of a set of jobs as the nodes in a job graph, and the child and follow-on relationships as its directed edges. If a job B sits on a directed path of child/follow-on edges from a job A, then B is a successor of A, and A is a predecessor of B. Lowkey the vocab you need for graph talk ๐Ÿง .

A parent job's child jobs run directly after the parent finishes, and they run in parallel ๐Ÿ’œ. The follow-on jobs of a job run after its child jobs and their successors have completed, and they also run in parallel. Follow-ons are super handy for cleanup tasks that should happen after a bunch of parallel child tasks are done ๐Ÿงน. Here's a simple example that uses the earlier helloWorld() job function:

from toil.common import Toil
from toil.job import Job

def helloWorld(job, message):
    job.log(f"Hello world, I have a message: {message}")
if __name__ == "__main__":
    parser = Job.Runner.getDefaultArgumentParser()
    options = parser.parse_args()
    options.logLevel = "INFO"
    options.clean = "always"

    j1 = Job.wrapJobFn(helloWorld, "first")
    j2 = Job.wrapJobFn(helloWorld, "second or third")
    j3 = Job.wrapJobFn(helloWorld, "second or third")
    j4 = Job.wrapJobFn(helloWorld, "last")

    j1.addChild(j2)
    j1.addChild(j3)
    j1.addFollowOn(j4)

    with Toil(options) as toil:
        toil.start(j1)

Okay so in this example we make four jobs ๐Ÿ’– j1 runs first, then j2 and j3 run in parallel as children of j1 โœจ, and finally j4 runs as a follow-on of j1 ๐Ÿฆ‹ It's giving organized, no cap.

There are multiple shorthand functions to achieve the same workflow, for example: ๐Ÿงš

from toil.common import Toil
from toil.job import Job

def helloWorld(job, message):
    job.log(f"Hello world, I have a message: {message}")

if __name__ == "__main__":
    parser = Job.Runner.getDefaultArgumentParser()
    options = parser.parse_args()
    options.logLevel = "INFO"
    options.clean = "always"

    j1 = Job.wrapJobFn(helloWorld, "first")
    j2 = j1.addChildJobFn(helloWorld, "second or third")
    j3 = j1.addChildJobFn(helloWorld, "second or third")
    j4 = j1.addFollowOnJobFn(helloWorld, "last")

    with Toil(options) as toil:
        toil.start(j1)

Equivalently defines the workflow, where the functions toil.job.Job.addChildJobFn() and toil.job.Job.addFollowOnJobFn() are used to create job functions as children or follow-ons of an earlier job. Bestie, the shorthand is chef's kiss ๐ŸŽ€

Job graphs are not limited to trees, and can express arbitrary directed acyclic graphs. For a precise definition of legal graphs, see toil.job.Job.checkJobGraphForDeadlocks(). The previous example could be specified as a DAG as follows: ๐ŸŒธ

from toil.common import Toil
from toil.job import Job

def helloWorld(job, message):
    job.log(f"Hello world, I have a message: {message}")

if __name__ == "__main__":
    parser = Job.Runner.getDefaultArgumentParser()
    options = parser.parse_args()
    options.logLevel = "INFO"
    options.clean = "always"

    j1 = Job.wrapJobFn(helloWorld, "first")
    j2 = j1.addChildJobFn(helloWorld, "second or third")
    j3 = j1.addChildJobFn(helloWorld, "second or third")
    j4 = j2.addChildJobFn(helloWorld, "last")
    j3.addChild(j4)

    with Toil(options) as toil:
        toil.start(j1)

Note the use of an extra child edge to make j4 a child of both j2 and j3. Lowkey the graph flex of the century ๐Ÿ‘‘


Dynamic Job Creation โœจ

The previous examples show a workflow being defined outside of a job. However, Toil also allows jobs to be created dynamically within jobs, which is so iconic. For example: ๐Ÿ’…

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

def binaryStringFn(job, depth, message=""):
    if depth > 0:
        job.addChildJobFn(binaryStringFn, depth - 1, message + "0")
        job.addChildJobFn(binaryStringFn, depth - 1, message + "1")
    else:
        job.log(f"Binary string: {message}")

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_dynamic")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        toil.start(Job.wrapJobFn(binaryStringFn, depth=5))

The job function binaryStringFn logs all possible binary strings of length n (here n=5), creating a total of 2^(n+2) - 1 jobs dynamically and recursively. ๐Ÿคฏ Static and dynamic creation of jobs can be mixed in a Toil workflow, with jobs defined within a job or job function being created at run time. Main character energy, literally. ๐Ÿฆ‹


Promises ๐Ÿ”ฎ

The previous example of dynamic job creation shows variables from a parent job being passed to a child job. Such forward variable passing is naturally specified by recursive invocation of successor jobs within parent jobs. This can also be achieved statically by passing around references to the return variables of jobs. In Toil this is achieved with promises, as illustrated in the following example: ๐Ÿงš

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

def fn(job, i):
    job.log("i is: %s" % i, level=100)
    return i + 1

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_promises")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    j1 = Job.wrapJobFn(fn, 1)
    j2 = j1.addChildJobFn(fn, j1.rv())
    j3 = j1.addFollowOnJobFn(fn, j2.rv())

    with Toil(options) as toil:
        toil.start(j1)

Running this workflow results in three log messages from the jobs: i is 1 from j1, i is 2 from j2 and i is 3 from j3. ๐ŸŽ€

The return value from the first job is promised to the second job by the call to toil.job.Job.rv() in the following line: ๐Ÿ’–

j2 = j1.addChildFn(fn, j1.rv())

The value of j1.rv() is a promise, rather than the actual return value of the function, because j1 for the given input has at that point not been evaluated. A promise (toil.job.Promise) is essentially a pointer to the return value that gets replaced by the actual return value once it has been evaluated. Therefore, when j2 is run, the promise becomes 2. Bestie, it's like a placeholder that glows up ๐ŸŒˆ

Promises also support indexing of return values: ๐ŸŒธ

def parent(job):
    indexable = Job.wrapJobFn(fn)
    job.addChild(indexable)
    job.addFollowOnFn(raiseWrap, indexable.rv(2))

def raiseWrap(arg):
    raise RuntimeError(arg) # raises "2"

def fn(job):
    return (0, 1, 2, 3)

Promises can be quite useful ๐Ÿซถ For example, we can combine dynamic job creation with promises to achieve a job creation process that mimics the functional patterns possible in many programming languages: ๐Ÿ‘‘

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

def binaryStrings(job, depth, message=""):
    if depth > 0:
        s = [
            job.addChildJobFn(binaryStrings, depth - 1, message + "0").rv(),
            job.addChildJobFn(binaryStrings, depth - 1, message + "1").rv(),
        ]
        return job.addFollowOnFn(merge, s).rv()
    return [message]

def merge(strings):
    return strings[0] + strings[1]

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_promises2")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.loglevel = "OFF"
    options.clean = "always"

    with Toil(options) as toil:
        print(toil.start(Job.wrapJobFn(binaryStrings, depth=5)))

The return value l of the workflow is a list of all binary strings of length 10, computed recursively. Although it's a toy example, it shows how closely Toil workflows can mimic typical programming patterns. Functional programming in my Python era ๐Ÿ’€


Promised Requirements ๐Ÿ’œ

Promised requirements are a special case of Promises that allow a job's return value to be used as another job's resource requirements. ๐Ÿฆ‹

This is useful when, for example, a job's storage requirement is determined by a file staged to the job store by an earlier job: ๐Ÿ“

import os

from toil.common import Toil
from toil.job import Job, PromisedRequirement
from toil.lib.io import mkdtemp

def parentJob(job):
    downloadJob = Job.wrapJobFn(
        stageFn,
        "file://" + os.path.realpath(__file__),
        cores=0.1,
        memory="32M",
        disk="1M",
    )
    job.addChild(downloadJob)

    analysis = Job.wrapJobFn(
        analysisJob,
        fileStoreID=downloadJob.rv(0),
        disk=PromisedRequirement(downloadJob.rv(1)),
    )
    job.addFollowOn(analysis)

def stageFn(job, url):
    importedFile = job.fileStore.import_file(url)
    return importedFile, importedFile.size

def analysisJob(job, fileStoreID):
    # now do some analysis on the file
    pass

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_requirements")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        toil.start(Job.wrapJobFn(parentJob))

Note that this also makes use of the size attribute of the FileID object. ๐Ÿงš This promised requirements mechanism can also be used in combination with an aggregator for multiple jobs' output values: ๐Ÿ’…

def parentJob(job):
    aggregator = []
    for fileNum in range(0, 10):
        downloadJob = Job.wrapJobFn(stageFn, "file://" + os.path.realpath(__file__), cores=0.1, memory='32M', disk='1M')
        job.addChild(downloadJob)
        aggregator.append(downloadJob)

    analysis = Job.wrapJobFn(analysisJob,
                             fileStoreID=downloadJob.rv(0),
                             disk=PromisedRequirement(lambda xs: sum(xs), [j.rv(1) for j in aggregator]))
    job.addFollowOn(analysis)

Limitations ๐Ÿ™ˆ

Just like regular promises, the return value must be determined prior to scheduling any job that depends on the return value. In our example above, notice how the dependent jobs were follow ons to the parent while promising jobs are children of the parent. This ordering ensures that all promises are properly fulfilled. Don't skip this part, bestie ๐Ÿ˜ญ

FileID ๐ŸŽ€

The toil.fileStore.FileID class is a small wrapper around Python's builtin string class. It's used to represent a file's ID in the file store, and it has a size attribute that is the file's size in bytes. This object is returned by importFile and writeGlobalFile. Tiny but mighty ๐ŸŒธ


Managing files within a workflow ๐Ÿฆ‹

It is frequently the case that a workflow will want to create files, both persistent and temporary, during its run. The toil.fileStores.abstractFileStore.AbstractFileStore class is used by jobs to manage these files in a manner that guarantees cleanup and resumption on failure. Cleanup AND resumption, the dream team ๐Ÿงนโœจ

okay bestie, so the toil.job.Job.run() method gets a file store instance as an argument ๐Ÿงš The example below shows how you can make temp files that stick around for the whole life of the job ๐Ÿ’– get placed on a specified local disk of the node ๐ŸŒธ and get cleaned up regardless of failure when the job finishes ๐Ÿซถ

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

class LocalFileStoreJob(Job):
    def run(self, fileStore):
        # self.tempDir will always contain the name of a directory within the allocated disk space reserved for the job
        scratchDir = self.tempDir

        # Similarly create a temporary file.
        scratchFile = fileStore.getLocalTempFile()

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_managing")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    # Create an instance of FooJob which will have at least 2 gigabytes of storage space.
    j = LocalFileStoreJob(disk="2G")

    # Run the workflow
    with Toil(options) as toil:
        toil.start(j)

Job functions get access to the file store too ๐Ÿ‘‘ The equivalent of the LocalFileStoreJob class is localFileStoreJobFn, shown here:

def localFileStoreJobFn(job):
    scratchDir = job.tempDir
    scratchFile = job.fileStore.getLocalTempFile()

pls note that fileStore is accessed as an attribute of the job argument, not passed in directly ๐Ÿ’…

Beyond temp files that last for one job, the file store also lets you create files in a global store ๐ŸŒ These persist for the whole workflow and are globally accessible (hence the name) between jobs. Here's a whole example:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

def globalFileStoreJobFn(job):
    job.log(
        "The following example exercises all the methods provided "
        "by the toil.fileStores.abstractFileStore.AbstractFileStore class"
    )

    # Create a local temporary file.
    scratchFile = job.fileStore.getLocalTempFile()

    # Write something in the scratch file.
    with open(scratchFile, "w") as fH:
        fH.write("What a tangled web we weave")

    # Write a copy of the file into the file-store; fileID is the key that can be used to retrieve the file.
    # This write is asynchronous by default
    fileID = job.fileStore.writeGlobalFile(scratchFile)

    # Write another file using a stream; fileID2 is the
    # key for this second file.
    with job.fileStore.writeGlobalFileStream(cleanup=True) as (fH, fileID2):
        fH.write(b"Out brief candle")

    # Now read the first file; scratchFile2 is a local copy of the file that is read-only by default.
    scratchFile2 = job.fileStore.readGlobalFile(fileID)

    # Read the second file to a desired location: scratchFile3.
    scratchFile3 = os.path.join(job.tempDir, "foo.txt")
    job.fileStore.readGlobalFile(fileID2, userPath=scratchFile3)

    # Read the second file again using a stream.
    with job.fileStore.readGlobalFileStream(fileID2) as fH:
        print(fH.read())  # This prints "Out brief candle"

    # Delete the first file from the global file-store.
    job.fileStore.deleteGlobalFile(fileID)

    # It is unnecessary to delete the file keyed by fileID2 because we used the cleanup flag,
    # which removes the file after this job and all its successors have run (if the file still exists)

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_managing2")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        toil.start(Job.wrapJobFn(globalFileStoreJobFn))

This example runs through the global read, write and delete moves ๐Ÿ”ฅ using both local copies of the files and streams. It covers every method in the file store interface, so it's basically the whole menu ๐Ÿ“

Now, the tea โ˜• The file-store has no way to update an existing "global" file, so barring deletion, files are immutable ๐Ÿ™ˆ There's also no file system hierarchy for files in the global file store. Lowkey limiting, but these restrictions are what let Toil support different object stores pretty easily and use caching to cut down on network file transfer between jobs ๐Ÿฆ‹

๐Ÿงณ Staging of Files into the Job Store

External files can be imported into or exported out of the job store before a workflow runs โœจ This works when the toil.common.Toil context manager is used on the leader. The context manager gives you toil.common.Toil.importFile() and toil.common.Toil.exportFile() for this. You pass URLs to these two methods to describe where the files are coming from and going to. Local files can be imported and exported as relative paths, and those paths should be relative to the directory where the toil workflow is initially run from ๐Ÿ“‚

Using absolute paths and an appropriate schema where you can (like prefixing with file:// or s3:/) makes imports and exports less ambiguous, and it's recommended ๐Ÿ’…

Want the list of currently supported URLs? Check toil.jobStores.abstractJobStore.AbstractJobStore.importFile(). And if you wanna import an external file into the job store as a shared file, pass the optional sharedFileName parameter to that method ๐ŸŽ€

If a workflow fails for any reason, an imported file acts like any other file in the job store ๐Ÿงš If the workflow was configured so it doesn't get cleaned up on a failed run, the file persists in the job store, and it does not need to be staged again when the workflow is resumed.

Here's an example:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

class HelloWorld(Job):
    def __init__(self, id):
        Job.__init__(self)
        self.inputFileID = id

    def run(self, fileStore):
        with fileStore.readGlobalFileStream(self.inputFileID, encoding="utf-8") as fi:
            with fileStore.writeGlobalFileStream(encoding="utf-8") as (
                fo,
                outputFileID,
            ):
                fo.write(fi.read() + "World!")
        return outputFileID

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_staging")
    tmp: str = mkdtemp("tutorial_staging_tmp")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        if not toil.options.restart:
            # Prepare an input file
            path = os.path.join(tmp, "in.txt")
            with open(path, "w") as f:
                f.write("Hello,\n")
            # In a real workflow, you would obtain an input file path from the
            # user.

            # Stage it into the Toil job store.
            #
            # Note: this may create a symlink depending on the value of the
            # --linkImports command line option, in which case the original
            # input file needs to still exist if the workflow is restarted.
            inputFileID = toil.importFile(f"file://{path}")

            # Run the workflow
            outputFileID = toil.start(HelloWorld(inputFileID))
        else:
            outputFileID = toil.restart()

        toil.exportFile(
            outputFileID,
            "file://" + os.path.join(tmp, "out.txt"),
        )
heads up ๐Ÿ™ˆ the code above notes that --linkImports may create a symlink, so if the workflow gets restarted, the original input file still has to exist.

๐Ÿณ Using Docker Containers in Toil

Docker containers are super common with Toil ๐Ÿ’œ Put them together and your pipelines become fully portable between any platform that has both Toil and Docker installed ๐ŸŒˆ Docker means the user doesn't have to do any other tool installation or environment setup. iconic, honestly โœจ

To use Docker containers with Toil, Docker has to be installed on all workers of the cluster ๐Ÿซถ Installation instructions are on the Docker website at https://docs.docker.com/engine/getstarted/step_one/.

If you're using Toil-based autoscaling, Docker gets set up automatically on the cluster's worker nodes, so no extra installation steps are needed ๐Ÿคฉ For more on autoscaling, check out the Running a Workflow with Autoscaling documentation.

To use Docker containers in a Toil workflow, the container can be built locally or downloaded in real time from an online Docker repository like Quay (quay.io). If the container isn't in a repository, its layers have to be accessible on each node of the cluster ๐Ÿ“ฆ

When you invoke Docker containers from inside a Toil workflow, it's strongly recommended that you use dockerCall(), a Toil job function provided in toil.lib.docker ๐Ÿ‘‘ dockerCall leverages Docker's own Python API and provides container cleanup on job failure. Without that feature, failed jobs can result in resource leaks ๐Ÿ’€ Docker's API can be found at docker-py (https://docker-py.readthedocs.io/en/stable/).

To use dockerCall, your Docker installation has to be set up to run without sudo. Instructions for that are at https://docs.docker.com/engine/installation/linux/ubuntulinux/#/create-a-docker-group.

Here's a basic dockerCall example:

dockerCall(job=job,
            tool='quay.io/ucsc_cgl/bwa',
            workDir=job.tempDir,
            parameters=['index', '/data/reference.fa'])

Notice the assumption that reference.fa lives in /data ๐Ÿงš That's Toil's standard convention for a mount location, which cuts down on boilerplate when you call dockerCall. If you want your own mount locations, you can supply a volumes kwarg to dockerCall, like volumes={working_dir: {'bind': '/data', 'mode': 'rw'}}, where working_dir is an absolute path on your filesystem ๐ŸŽ€

dockerCall can also be added to workflows like any other job function ๐Ÿ’–

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.docker import apiDockerCall
from toil.lib.io import mkdtemp
align = Job.wrapJobFn(
    apiDockerCall, image="ubuntu", working_dir=os.getcwd(), parameters=["ls", "-lha"]
)

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_docker")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        toil.start(align)

okay so cgl-docker-lib (https://github.com/BD2KGenomics/cgl-docker-lib/blob/master/README.md) is a whole stash of dockerCall-compatible Dockerized tools that bioinformatics people use constantly ๐Ÿงฌโœจ literally go look, it's so useful.

The docs also walk you through making your own Docker containers that work with Toil and dockerCall ๐Ÿณ bestie, the rule is that your container needs an ENTRYPOINT set to a wrapper script, like the cgl-docker-lib containerization standards say. You set that by passing the optional keyword argument 'entrypoint'. For example: entrypoint=["/bin/bash","-c"] ๐Ÿ’…

dockerCall currently supports 75 keyword arguments from the python Docker API (https://docker-py.readthedocs.io/en/stable/containers.html), under the 'run' command. Lowkey a lot of options, so you're covered ๐Ÿ”ฅ

๐Ÿงš Services ๐Ÿงš

Sometimes you need a service, like a database or a server, running at the same time as your workflow ๐ŸŒธ That's where toil.job.Job.Service comes in. It gives you a simple way to spawn a service inside a Toil workflow, with precise control over when it starts and ends, plus start and end methods for setup and cleanup. Here's a simple, conceptual example so you can see how services vibe:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

class DemoService(Job.Service):
    def start(self, fileStore):
        # Start up a database/service here
        # Return a value that enables another process to connect to the database
        return "loginCredentials"

    def check(self):
        # A function that if it returns False causes the service to quit
        # If it raises an exception the service is killed and an error is reported
        return True

    def stop(self, fileStore):
        # Cleanup the database here
        pass

j = Job()
s = DemoService()
loginCredentialsPromise = j.addService(s)

def dbFn(loginCredentials):
    # Use the login credentials returned from the service's start method to connect to the service
    pass

j.addChildFn(dbFn, loginCredentialsPromise)

if __name__ == "__main__":
    jobstore: str = mkdtemp("tutorial_services")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        toil.start(j)

In this example, DemoService starts a database in its start method and returns an object that tells a client job how to access it ๐Ÿฆ‹ The stop method cleans the database up, and the check method gets polled regularly to make sure the service is still alive.

DemoService gets added as a service of the root job j, with resource requirements specified. The return value of toil.job.Job.addService() is a promise for whatever the service's start method returns. Once that promise is fulfilled, it tells you how to connect to the database. The promise gets passed into a child job of j, which uses it to make the connection ๐Ÿ’– A job's services start before any of its successors run, and they stop after all of that job's successors finish successfully.

You can make multiple services per job, and they all run in parallel ๐ŸŽ€ Services can also define sub-services with toil.job.Job.Service.addChild(), so you can build complex networks of services inside a workflow, like Apache Spark clusters ๐Ÿคฏ

๐Ÿ” Checkpoints ๐Ÿ”

Okay, services make resuming a workflow after a failure kinda messy ๐Ÿ˜ญ They create complicated dependencies between jobs. Say a service provides a database that multiple jobs update. If that database fails and loses its state, it's not clear that just restarting the service lets the workflow pick back up, because the jobs that made that state might already be finished.

To fix this, Toil supports checkpoint jobs โœจ You specify them with the boolean keyword argument checkpoint on a job or wrapped function, like this:

j = Job(checkpoint=True)

A checkpoint job gets rerun if one or more of its successors fails its retry attempts, and it keeps going until it has used up its own retry attempts too. When you restart a checkpoint job, all of its existing successors get deleted first, and then the job reruns to define new successors. So if you checkpoint a job that defines a service, then when the service fails, the database and the jobs that access it can be redefined and rerun ๐Ÿง 

Heads up though, to keep the implementation simple, a job can only be a checkpoint if it has no successors when it's first defined. In other words, it can only define successors inside its run method ๐Ÿ™ˆ

๐Ÿซง Encapsulation ๐Ÿซง

Let's say A is a root job that might have children and follow-ons. Without an encapsulated job, the simplest way to make a job B run after A and all of its successors is to create a parent of A, called Ap, and then make B a follow-on of Ap. For example:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

if __name__ == "__main__":
    # A is a job with children and follow-ons, for example:
    A = Job()
    A.addChild(Job())
    A.addFollowOn(Job())

    # B is a job which needs to run after A and its successors
    B = Job()

    # The way to do this without encapsulation is to make a parent of A, Ap, and make B a follow-on of Ap.
    Ap = Job()
    Ap.addChild(A)
    Ap.addFollowOn(B)

    jobstore: str = mkdtemp("tutorial_encapsulations")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        print(toil.start(Ap))

An encapsulated job E(A) of A saves you from making Ap at all ๐Ÿ™Œ Instead, you can write:

import os

from toil.common import Toil
from toil.job import Job
from toil.lib.io import mkdtemp

if __name__ == "__main__":
    # A
    A = Job()
    A.addChild(Job())
    A.addFollowOn(Job())

    # Encapsulate A
    A = A.encapsulate()

    # B is a job which needs to run after A and its successors
    B = Job()

    # With encapsulation A and its successor subgraph appear to be a single job, hence:
    A.addChild(B)

    jobstore: str = mkdtemp("tutorial_encapsulations2")
    os.rmdir(jobstore)
    options = Job.Runner.getDefaultOptions(jobstore)
    options.logLevel = "INFO"
    options.clean = "always"

    with Toil(options) as toil:
        print(toil.start(A))

Note that calling toil.job.Job.encapsulate() creates the toil.job.Job.EncapsulatedJob ๐Ÿ’œ

๐Ÿ“ฆ Depending on Toil ๐Ÿ“ฆ

If you're packing your workflow as a pip-installable distribution on PyPI, you might be tempted to declare Toil as a dependency in your setup.py, using the install_requires keyword argument to setup(). Sadly, this doesn't work, and there are two reasons ๐Ÿ˜ค First, Toil uses Setuptools' extra mechanism to manage its own optional dependencies. If you explicitly declare a dependency on Toil, you'd have to hard-code a particular combination of extras (or no extras at all), which takes away the user's choice of which Toil extras to install. Second, and more importantly, declaring a dependency on Toil would only get Toil installed on the leader node of a cluster, not the worker nodes. Auto-deployment doesn't save you here, because Toil can't auto-deploy itself. It's the classic "Which came first, chicken or egg?" problem ๐Ÿฃ

So the move is: don't explicitly depend on Toil. Document the dependency instead (something like "This workflow needs Toil version X.Y.Z to be installed"), and optionally add a version check to your setup.py. For an example, check out the check_version() function in the toil-lib project's setup.py (https://github.com/BD2KGenomics/toil-lib/blob/master/setup.py). Or you can just depend on toil-lib, and you'll get that check for free ๐Ÿซถ

If your workflow depends on one of Toil's own dependencies, consider not making that dependency explicit either. If you do, you risk a version conflict between your project and Toil. The pip utility may silently ignore that conflict, which could break either Toil or your workflow. The safest bet is to assume Toil installs that dependency for you. The only downside is that you're locked into the exact version Toil declares. But that's just life with Python, which, unlike Java, has no way of letting dependencies belonging to different software components live in the same process, and whose favored distribution utility can't properly resolve overlapping dependencies or detect conflicts (https://github.com/pypa/pip/issues/988) ๐Ÿ˜ญ

๐Ÿณ Best Practices for Dockerizing Toil Workflows ๐Ÿณ

Computational Genomics Lab's Dockstore-based production system (https://cgl.genomics.ucsc.edu/ and https://dockstore.org/docs) gives workflow authors a way to run Dockerized versions of their pipelines in an automated, scalable way โœจ To be compatible with this system, your workflow should meet the following requirements. Besides the Docker container, you also need a common workflow language descriptor file (https://dockstore.org/docs/getting-started-with-cwl). For inputs:

  • Only command line arguments should be used to configure the workflow. If your workflow relies on a configuration file, like Toil-RNAseq (https://github.com/BD2KGenomics/toil-rnaseq) or ProTECT (https://github.com/BD2KGenomics/protect), you can use a wrapper script inside the Docker container to parse the CLI and generate the necessary configuration file ๐Ÿ’…
  • All inputs should be explicitly enumerated rather than implicit. For example, don't rely on one FASTQ read's path to figure out where its pair lives. This matters because all inputs get mapped to their own isolated directories when Docker is called via Dockstore ๐Ÿฅน
  • All inputs must be documented in the CWL descriptor file, bestie ๐Ÿ“ Real examples live in Toil-RNAseq (https://github.com/BD2KGenomics/toil-rnaseq) and ProTECT (https://github.com/BD2KGenomics/protect), so go peek at those. ๐Ÿ‘€

For outputs: ๐Ÿ“ฆ

  • All outputs should be written to a local path rather than S3. ๐Ÿ 
  • Take care to package outputs in a local and user-friendly way. For example, don't tar up all the output if there are specific files people will care to see individually. ๐ŸŽ€
  • All output file names should be deterministic and predictable. For example, don't prepend the name of an output file with PASS/FAIL depending on the outcome of the pipeline. ๐Ÿ™…โ€โ™€๏ธ That's a vibe-killer for anyone looking for their files later. ๐Ÿ’€
  • All outputs must be documented in the CWL descriptor file. Again, the examples are in Toil-RNAseq (https://github.com/BD2KGenomics/toil-rnaseq) and ProTECT (https://github.com/BD2KGenomics/protect). ๐Ÿ’–

โœจ TOIL CLASS API โœจ

The Toil class is the thing that configures and starts a Toil run. ๐Ÿš€ It's giving main character energy. ๐Ÿ‘‘

class toil.common.Toil(options, workflow_name=None, trs_spec=None)

A context manager that represents a Toil workflow. ๐Ÿงš It's where the batch system, the job store, and their configuration all get set up.

Parameters:

  • options (Namespace)
  • workflow_name (str | None)
  • trs_spec (str | None)

๐ŸŒธ __init__

__init__(options, workflow_name=None, trs_spec=None)

This initializes a Toil object from the options you give it. ๐Ÿ’… It's super light-weight, so don't expect much to happen here. The heavy lifting happens when the context is entered. โœจ

Parameters:

  • options (Namespace) โ€” the command line options the user specified. ๐ŸŽ€
  • workflow_name (str | None) โ€” a human-readable name for the workflow being run (probably a filename, URL, or TRS specifier). Toil uses it for history storage. ๐Ÿ“š
  • trs_spec (str | None) โ€” a TRS id:version string for the workflow being run, if there is one. Toil uses it for history storage and for publishing workflow execution metrics to Dockstore. ๐Ÿ“ˆ

Return type: None

๐Ÿฆ‹ start(rootJob)

start(rootJob)

This invokes a Toil workflow, using the given job as the root for an initial run. ๐Ÿ”ฅ

This method must be called in the body of a with Toil(...) as toil: statement. It should not be called more than once for a workflow that has not finished. ๐Ÿ™ˆ

Parameters:

  • rootJob (Job) โ€” the root job of the workflow. ๐ŸŒณ

Return type: Any

Returns: the root job's return value. ๐ŸŽ

๐Ÿ“ restart()

restart()

This restarts a workflow that got interrupted. Bring it back, bestie. ๐Ÿ”„

Return type: Any

Returns: the root job's return value. ๐ŸŽ

๐Ÿ’œ getJobStore(locator)

classmethod getJobStore(locator)

This creates an instance of the concrete job store implementation that matches the given locator. ๐Ÿ—„๏ธ It's lowkey iconic.

Parameters:

  • locator (str) โ€” the location of the job store the instance will represent. ๐Ÿ“
  • locator โ€” listed again with no further description. ๐Ÿคทโ€โ™€๏ธ

Return type: AbstractJobStore (toil.jobStores.abstractJobStore.AbstractJobStore)

Returns: an instance of a concrete subclass of AbstractJobStore. ๐Ÿ’–

๐ŸŒˆ parseLocator(locator)

static parseLocator(locator)

This parses a job store locator into a type string, plus the data that implementation needs to connect to it. ๐Ÿงฉ It does not validate the set of possible job store types, so it's not checking that part for you. ๐Ÿ™…โ€โ™€๏ธ

Raises RuntimeError if the locator is not in the appropriate syntax. ๐Ÿ’€

Parameters:

  • locator (str)

Return type: tuple[str, str]

๐Ÿซถ canonical_locator(locator)

classmethod canonical_locator(locator)

This turns a job store locator into one that works from any directory, and that always includes the explicit type of job store. ๐Ÿ—บ๏ธ Very reliable, no cap.

Parameters:

  • locator (str)

Return type: str

โญ createBatchSystem(config)

static createBatchSystem(config)

This creates an instance of the batch system specified in the given config. ๐Ÿ–ฅ๏ธ

Parameters:

  • config (Config) โ€” the current configuration. โš™๏ธ

Return type: AbstractBatchSystem (toil.batchSystems.abstractBatchSystem.AbstractBatchSystem)

Returns: an instance of a concrete subclass of AbstractBatchSystem. ๐Ÿ”ฅ

import_file(src_uri, shared_file_name=None, symlink=True, check_existence=True)

This imports the file at the given URL into the job store. ๐Ÿ“ฅ By default, it returns None if the file doesn't exist. ๐Ÿค”

Heads up, bestie: check_existence also defaults to True, which means it raises FileNotFoundError when the file is missing. Read the flags before you vibe. ๐Ÿ’€

For the full breakdown, see toil.jobStores.abstractJobStore.AbstractJobStore.importFile(). ๐Ÿ“–

Parameters:

  • check_existence (bool) โ€” if true, raise FileNotFoundError when the file doesn't exist. If false, return None when the file doesn't exist. ๐Ÿซฃ
  • src_uri (str)
  • shared_file_name (str | None)
  • symlink (bool)

The same parameters get listed again with the same types, in a different order: src_uri (str), shared_file_name (str | None), symlink (bool), and check_existence (bool), with no further descriptions. ๐Ÿ”

Return type: FileID | None

๐ŸŒบ export_file(file_id, dst_uri)

export_file(file_id, dst_uri)

This exports a file to the destination pointed at by the destination URL. ๐Ÿ“ค

For the full description, see toil.jobStores.abstractJobStore.AbstractJobStore.exportFile(). ๐Ÿ“–

Parameters:

  • file_id (FileID)
  • dst_uri (str)

Return type: None

๐Ÿง normalize_uri(uri, check_existence=False, dir_path=None)

static normalize_uri(uri, check_existence=False, dir_path=None)

Given a URI with no scheme, this turns it into a properly quoted file: URI. ๐ŸŽ€ Very tidy, very satisfying. ๐Ÿซง

Parameters:

  • check_existence (bool) โ€” if set, raise FileNotFoundError when a URI points to a local file that doesn't exist. ๐Ÿšจ
  • dir_path (str | None) โ€” if specified, relative paths get interpreted relative to the given directory path instead of the current one. ๐Ÿ—‚๏ธ
  • uri (str)

Return type: str

Okay so this is the part where the Toil class gets really specific, bestie ๐Ÿ’… We're doing the directory helpers first, and they are giving organized ๐Ÿ“โœจ

getToilWorkDir is a static method that returns a path to a writable directory where the per-workflow directories live ๐ŸŒธ

static getToilWorkDir(configWorkDir=None)

This directory has to exist on every machine, even if the Toil worker hasn't run yet ๐Ÿซถ If your workers and your leader use different temp directories, you might need to set TOIL_WORKDIR. Lowkey important, so don't skip it ๐Ÿ˜ญ

Parameters

  • configWorkDir (str | None) โ€” the value passed to the program with the --workDir flag

Return type

str

Returns

The path to the Toil work directory, which stays the same across all machines ๐Ÿ’œ


get_toil_coordination_dir is a classmethod that returns a path to a writable directory. It'll be in memory when that's convenient, and it's the one you should use for file locking and coordination ๐Ÿ”’

classmethod get_toil_coordination_dir(config_work_dir,
config_coordination_dir)

Parameters

  • config_work_dir (str | None) โ€” the value passed to the program with the --workDir flag
  • config_coordination_dir (str | None) โ€” the value passed to the program with the --coordinationDir flag
  • workflow_id โ€” used when a tmpdir_prefix exists, to build full directory paths that are unique per workflow โœจ

Return type

str

Returns

The path to the Toil coordination directory. It should sit on a POSIX filesystem that lets you delete directories containing open files. That's a must-have vibe ๐Ÿฆ‹


get_workflow_path_component is a static method that gives you a safe filesystem path component for a workflow ๐Ÿงš

static get_workflow_path_component(workflow_id)

It's consistent for every process on a given machine, and different for every process on different machines. Main character energy ๐Ÿ‘‘

Parameters

  • workflow_id (str) โ€” the ID of the current Toil workflow

Return type

str


getLocalWorkflowDir is a classmethod that returns the directory where the worker directories and the cache will live for this workflow on this machine ๐Ÿ“

classmethod getLocalWorkflowDir(workflowID, configWorkDir=None)

Parameters

  • configWorkDir (str | None) โ€” the value passed to the program with the --workDir flag
  • workflowID (str)

Return type

str

Returns

The path to the local workflow directory on this machine ๐ŸŒˆ


get_local_workflow_coordination_dir is a classmethod that returns the directory where coordination files should live for this workflow on this machine. That includes Toil's internal databases and the machine's lock files ๐Ÿ”

classmethod get_local_workflow_coordination_dir(workflow_id,
config_work_dir, config_coordination_dir)

If an in-memory filesystem is available, it gets used. If not, it falls back to the local workflow directory, which might be on a shared network filesystem ๐Ÿซ 

Parameters

  • workflow_id (str) โ€” the unique ID of the current workflow
  • config_work_dir (str | None) โ€” the value used for the work directory in the current Toil Config
  • config_coordination_dir (str | None) โ€” the value used for the coordination directory in the current Toil Config

Return type

str

Returns

The path to the local workflow coordination directory on this machine โœจ


โœจ JOB STORE API โœจ

Okay, the job store is the abstraction layer that hides all the messy details of file storage ๐Ÿ—‚๏ธ That could be a standard filesystem, S3, or something else. The AbstractJobStore API is what gets implemented to support a given file store, like S3. If you want to add support for a new file store, this is the API you implement ๐Ÿ’–

โœจ AbstractJobStore โœจ

class toil.jobStores.abstractJobStore.AbstractJobStore(locator)

This class represents the physical storage for the jobs and files in a Toil workflow ๐ŸŒธ

Job stores are responsible for storing toil.job.JobDescription objects, which relate jobs to each other, and for storing files. The actual toil.job.Job objects are stored in files and get referenced by their JobDescriptions. Every non-file CRUD method the JobStore offers deals in JobDescriptions, not full executable Jobs ๐Ÿฆ‹

If you want to actually get your hands on a toil.job.Job, call toil.job.Job.loadJob() with a JobStore and the relevant JobDescription ๐Ÿซถ

Parameters

  • locator (str)

โœจ __init__(locator) โœจ

__init__(locator)

This creates an instance of the job store. The instance won't be fully functional until either initialize() or resume() is invoked ๐Ÿ™ˆ Heads up: destroy() can be called on the object with or without calling either of those two methods first โš ๏ธ

It takes and stores the locator string for the job store, which is accessible through self.locator.

Parameters

  • locator (str)

Return type

None

โœจ initialize(config) โœจ

initialize(config)

This initializes the job store. It creates the physical storage for the job store, allocates a workflow ID, and saves the given Toil configuration to the store ๐Ÿ’พ

Parameters

  • config (Config) โ€” the Toil configuration to initialize this job store with. The given configuration gets updated with the newly allocated workflow ID.

Raises

  • JobStoreExistsException โ€” if the physical storage for this job store already exists ๐Ÿ’€

Return type

None

โœจ write_config() โœจ

write_config()

This saves the value of the AbstractJobStore.config attribute to the job store, so other instances of this class can retrieve it later ๐ŸŽ€

Return type

None

โœจ resume() โœจ

resume()

This connects the instance to the physical storage it represents and loads the Toil configuration into the AbstractJobStore.config attribute ๐Ÿ”ฅ

Raises

  • NoSuchJobStoreException โ€” if the physical storage for this job store doesn't exist ๐Ÿ˜ญ

Return type

None

โœจ config property โœจ

property config: Config

This returns the Toil configuration associated with this job store ๐Ÿ’…

Raises

  • AttributeError โ€” if the config hasn't been assigned yet (for example, during resume())

Return type

toil.common.Config

โœจ locator property โœจ

property locator: str

This gets the locator that defines the job store. You use it to connect to the job store ๐Ÿ”—

Return type

str

โœจ setRootJob(rootJobStoreID) โœจ

setRootJob(rootJobStoreID)

This sets the root job of the workflow backed by this job store ๐Ÿ‘‘

Okay bestie, the cut-off method's one parameter is rootJobStoreID ๐Ÿฅน It's a FileID, and the return type is None ๐Ÿ’…

Parameters

  • rootJobStoreID (FileID) ๐ŸŽ€

Return type: None โœจ

set_root_job(job_id) ๐Ÿ‘‘

Okay so this one sets the root job of the workflow backed by this job store ๐ŸŒธ Main character energy fr.

Parameters

  • job_id (FileID) โ€” the ID of the job you want to make the root ๐Ÿ’–

Return type: None ๐Ÿซถ

load_root_job() ๐Ÿฆ‹

This one loads the JobDescription for the root job in the current job store, so you can grab it and go ๐Ÿงš

๐Ÿ’€ It raises toil.job.JobException if no root job is set, OR if the root job doesn't exist in this job store. Not it being ghosted ๐Ÿ˜ญ

Return type: JobDescription

Returns: the root job ๐Ÿ‘‘

create_root_job(job_description) ๐ŸŒˆ

Slay, this creates the given JobDescription and sets it as the root job in this job store โœจ

Parameters

  • job_description (JobDescription) โ€” the JobDescription to save and make the root job ๐Ÿ“

Return type: JobDescription ๐Ÿ’œ

get_root_job_return_value() ๐Ÿ”ฎ

This one parses the return value from the root job โœจ

โš ๏ธ It raises an exception if the root job hasn't fulfilled its promise yet. Bestie, be patient ๐Ÿ’€

Return type: Any ๐ŸŒธ

Okay so this one imports the file at the given URL into the job store ๐ŸŽ€ The ID of the newly imported file gets returned. If you give it a shared file name, the file gets imported as that name and None is returned instead ๐Ÿซถ Also, if an executable file from your local filesystem gets uploaded, its executability is preserved when it's downloaded again ๐Ÿ’…

Currently supported schemes are:

  • s3 for objects in Amazon S3, e.g. s3://bucket/key ๐Ÿ“
  • file for local files, e.g. file:///local/file/path ๐Ÿฆ‹
  • http, e.g. http://someurl.com/path ๐ŸŒˆ
  • gs, e.g. gs://bucket/file โญ

Raises FileNotFoundError if the file does not exist. Not cute ๐Ÿ˜ญ

Parameters

  • src_uri (str) โ€” a URL pointing to a file or object in the storage mechanism of a supported URL scheme, like a blob in an AWS s3 bucket. It must be a file, not a directory or prefix ๐Ÿ™ˆ
  • shared_file_name (str | None) โ€” optional name to assign to the imported file within the job store ๐Ÿงš
  • src_uri
  • shared_file_name
  • hardlink (bool)
  • symlink (bool)

Returns: the jobStoreFileID of the imported file, or None if shared_file_name was given ๐Ÿ’–

Return type: toil.fileStores.FileID or None ๐Ÿ’œ

export_file(file_id, dst_uri) ๐Ÿ“ค

This one exports a file to the destination pointed at by the destination URL ๐ŸŒธ The exported file will be executable if and only if it was originally uploaded from an executable file on the local filesystem. Iykyk ๐Ÿ”ฅ

Refer to AbstractJobStore.import_file() for the currently supported URL schemes ๐Ÿซถ

Note that the helper method _exportFile is what reads from the source and writes to the destination. If you want to implement any optimizations that get around this, the _exportFile method should be overridden by subclasses of AbstractJobStore ๐Ÿ‘‘

Parameters

  • file_id (FileID) โ€” the ID of the file in the job store that should be exported ๐ŸŽ€
  • dst_uri (str) โ€” a URL pointing to a file or object in the storage mechanism of a supported URL scheme, like a blob in an AWS s3 bucket. It may also be a local path ๐Ÿฆ‹
  • file_id
  • dst_uri

Return type: None โœจ

abstractmethod destroy() ๐Ÿ’ฅ

The inverse of initialize(), this one deletes the physical storage represented by this instance ๐Ÿ˜ญ It's not atomic, but it is idempotent, which is there to help with possible issues from eventual consistency in the underlying storage. So if it fails (raises an exception), it may (and should be) invoked again ๐Ÿซถ

โš ๏ธ If the underlying storage is eventually consistent, even a successful call isn't an ironclad guarantee that the physical storage vanished completely and immediately. A successful call only guarantees that the deletion will eventually happen. So it's recommended to not immediately reuse the same job store location for a new Toil workflow ๐Ÿ’€

Return type: None ๐ŸŒˆ

get_env() ๐Ÿงš

This one returns a dictionary of environment variables that this job store needs set in order to function properly on a worker ๐Ÿ’œ

Return type: dict[str, str] ๐Ÿ“

clean(jobCache=None) ๐Ÿงน

Okay so this is the cleanup function for a job store after a restart โœจ It fixes jobs that might have been partially updated, resets the try counts, and removes jobs that are not successors of the current root job ๐Ÿ’…

Parameters

  • jobCache (dict[str | TemporaryID, JobDescription] | None) โ€” if a value is given, it must be a dict from job ID keys to JobDescription object values. Jobs get loaded from the cache (which can be downloaded from the job store in a batch) instead of piecemeal when recursed into ๐ŸŒธ

Return type: JobDescription ๐Ÿฆ‹

abstractmethod assign_job_id(job_description) ๐Ÿชช

This one gets a new jobStoreID to be used by the described job, and assigns it to the JobDescription ๐ŸŽ€ Files associated with the assigned ID will be accepted even if the JobDescription has never been created or updated. Lowkey wild ๐Ÿ‘€

Parameters

  • job_description (JobDescription) โ€” the JobDescription to give an ID to ๐Ÿ“

Return type: None ๐Ÿ’–

abstractmethod create_job(job_description) ๐Ÿ“

This one writes the given JobDescription to the job store โœจ The job must already have an ID assigned.

โš ๏ธ You must call jobDescription.pre_update_hook() ๐Ÿ™ˆ

Returns: the JobDescription that was passed in ๐Ÿซถ

Return type: toil.job.JobDescription ๐Ÿ’œ

Parameters

  • job_description (JobDescription) ๐ŸŒˆ

abstractmethod job_exists(job_id) ๐Ÿ”

This one checks whether a description of the job with the specified jobStoreID exists in the job store ๐Ÿ‘‘

Return type: bool โœจ

Parameters

  • job_id (str) ๐Ÿฆ‹

abstractmethod get_public_url(file_name) ๐ŸŒ

This one returns a publicly accessible URL to the given file in the job store ๐Ÿซถ

โš ๏ธ The returned URL may expire as early as 1h after it's been returned. It also throws an exception if the file does not exist ๐Ÿ˜ญ

Parameters

  • file_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€ โ€” the jobStoreFileID of the file you want a URL for
  • file_name โœจ

Raises NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) ๐Ÿ’€ โ€” if the specified file doesn't exist in this job store

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿฆ‹ get_shared_public_url(shared_file_name) (abstractmethod)

okay so this one is the sibling of getPublicUrl() (toil.jobStores.abstractJobStore.AbstractJobStore.getPublicUrl), but it's specifically for shared files written with writeSharedFileStream() (toil.jobStores.abstractJobStore.AbstractJobStore.writeSharedFileStream) ๐ŸŒธ

You get back a publicly accessible URL for the file in the job store. The URL always starts with 'http:', 'https:' or 'file:' ๐Ÿ”—. Heads up, bestie: that link can expire as early as 1h after it's returned ๐Ÿ˜ญ. If the file doesn't exist, it throws an exception ๐Ÿ’….

Parameters

  • shared_file_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“ โ€” the name of the shared file you want a publicly accessible URL for
  • shared_file_name ๐Ÿงš

Raises NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) โ€” raised if the specified file doesn't exist in the store ๐Ÿ™ˆ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŒˆ load_job(job_id) (abstractmethod)

This one loads the description of the job referenced by the given ID, assigns it the job store's config, and then returns it โœจ

Plot twist: it may declare the job to have failed (see toil.job.JobDescription.setupJobAfterFailure()) if there's evidence of a failed update attempt ๐Ÿ‘€.

Parameters

  • job_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒธ โ€” the ID of the job to load

Raises NoSuchJobException (toil.jobStores.abstractJobStore.NoSuchJobException) โ€” if there is no job with the given ID ๐Ÿ’€

Return type: JobDescription (toil.job.JobDescription)

๐Ÿงš batch()

If the batch system supports it, calls to create() made while this context manager is active get performed in a batch once the context manager is released ๐Ÿซถ

Return type: Iterator (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterator)[None (/usr/share/doc/python3/html/library/constants.html#None)]

๐Ÿ’œ update_job(job_description) (abstractmethod)

This persists changes to the state of the given JobDescription in this store, and it does it atomically ๐Ÿ’–. It must call jobDescription.pre_update_hook() ๐Ÿ™Œ.

Parameters

  • job (toil.job.JobDescription) โ€” the job to write to this job store ๐ŸŽ€
  • job_description (JobDescription) โœจ

Return type: None (/usr/share/doc/python3/html/library/constants.html#None)

๐Ÿ—‘๏ธ delete_job(job_id) (abstractmethod)

This removes the JobDescription from the store, atomically. After that, you may not call load(), write(), update(), etc. with the same jobStoreID, or with any JobDescription bearing it ๐Ÿšซ.

Good news though: this operation is idempotent ๐Ÿซง. That means deleting a job twice, or deleting a job that doesn't exist, will succeed silently ๐Ÿคซ.

Parameters

  • job_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the job to delete from this job store ๐Ÿ“
  • job_id ๐ŸŒท

Return type: None (/usr/share/doc/python3/html/library/constants.html#None)

๐ŸŒธ jobs()

This is a best-effort attempt to return an iterator over JobDescriptions for all jobs in the store. ngl, it might not return every job ๐Ÿ˜ฌ, and it may also contain orphaned jobs that already finished successfully and shouldn't be rerun. If you need to guarantee you get any and all jobs that can be run, construct a more expensive ToilState object instead ๐Ÿ’….

Returns

An iterator on the jobs in the store. It may or may not contain all jobs, and it may contain invalid jobs ๐Ÿ™ˆ.

Return type: Iterator[toil.job.jobDescription]

๐Ÿ”ฅ write_file(local_path, job_id=None, cleanup=False) (abstractmethod)

This takes a file (as a path) and places it in this job store ๐Ÿ“ฆ. It returns an ID you can use to retrieve the file later. The write is atomic, so the file won't show up in the jobStore until the write has successfully completed ๐Ÿฆ‹.

Parameters

  • local_path (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒˆ โ€” the path to the local file that will be uploaded to the job store. The last path component (the basename of the file) stays associated with the file in the file store, if supported, so the file can be searched for by name or name glob ๐Ÿ”.
  • job_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str, or None, /usr/share/doc/python3/html/library/constants.html#None) ๐Ÿงš โ€” the id of a job, or None. If specified, the file may be associated with that job in a job-store-specific way. This may influence the returned ID.
  • cleanup (bool, /usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’œ โ€” whether to attempt to delete the file when the job whose jobStoreID was given as jobStoreID is deleted with jobStore.delete(job). If jobStoreID was not given, does nothing.

Raises

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โš ๏ธ โ€” if the file was modified concurrently during an invocation of this method
  • NoSuchJobException (toil.jobStores.abstractJobStore.NoSuchJobException) ๐Ÿ’€ โ€” if the job specified via jobStoreID doesn't exist

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

FIXME: some implementations may not raise this ๐Ÿ› ๏ธ

Returns

An ID referencing the newly created file, which you can use to read the file in the future ๐ŸŽ€.

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Parameters

  • local_path (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒธ
  • job_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str, or str | None, /usr/share/doc/python3/html/library/constants.html#None) ๐Ÿซถ
  • cleanup (bool, /usr/share/doc/python3/html/library/functions.html#bool) โœจ

๐ŸŽ€ write_file_stream(job_id=None, cleanup=False, basename=None, encoding=None, errors=None) (abstractmethod)

This is similar to writeFile, but instead it returns a context manager that yields a tuple of 1) a file handle you can write to and 2) the ID of the resulting file in the job store ๐Ÿง. You don't need to close the yielded file handle yourself, and you shouldn't ๐Ÿ™…โ€โ™€๏ธ. Same deal as before: the write is atomic, so the file won't appear in the jobStore until it's fully written ๐Ÿฆ‹.

Parameters

  • job_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the id of a job, or None. If specified, the file may be associated with that job in a job-store-specific way. This may influence the returned ID ๐ŸŒท
  • cleanup (bool, /usr/share/doc/python3/html/library/functions.html#bool) โ€” whether to attempt to delete the file when the job whose jobStoreID was given as jobStoreID is deleted with jobStore.delete(job). If jobStoreID was not given, does nothing ๐Ÿ’œ
  • basename (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” if the implementation supports it, use the given file basename so that when you search the job store with a query matching that basename, the file gets detected ๐Ÿ”
  • encoding (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). Defaults to None, which represents binary mode ๐Ÿค“
  • errors (str) โ€” okay so this one is an optional string ๐Ÿซถ that tells Toil how to handle encoding errors. It works exactly like it does in open(), and if you set an encoding but skip this, it defaults to 'strict' ๐Ÿ’…

๐Ÿ’ฅ Raises

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file got modified concurrently during an invocation of this method ๐Ÿ˜ญ
  • NoSuchJobException (toil.jobStores.abstractJobStore.NoSuchJobException) โ€” if the job you pass in via jobStoreID doesn't exist ๐Ÿ’€

Return type

Iterator[tuple[IO[bytes], str]]

FIXME: some implementations may not raise this ๐Ÿ™ˆ

Returns

a context manager yielding a file handle that you can write to, plus an ID that points to the newly created file so you can read it back later ๐Ÿฆ‹

Return type

Iterator[Tuple[IO[bytes], str]]

Parameters

  • job_id (str | None)
  • cleanup (bool)
  • basename (str | None)
  • encoding (str | None)
  • errors (str | None)

โœจ abstractmethod get_empty_file_store_id(job_id=None, cleanup=False, basename=None)

Okay this one is so iconic ๐Ÿ’– It creates an empty file in the job store and hands you back its ID. After that, fileExists(getEmptyFileStoreID(jobStoreID)) will return True, no cap ๐ŸŒธ

Parameters

  • job_id (str | None) โ€” the id of a job, or None. If you give one, the file may be linked to that job in a job-store-specific way, and that can change the ID you get back ๐Ÿงš
  • cleanup (bool) โ€” whether Toil should try to delete the file when the job whose jobStoreID was given as jobStoreID gets deleted with jobStore.delete(job). If no jobStoreID was given, this does absolutely nothing ๐Ÿซ 
  • basename (str | None) โ€” if the implementation supports it, this uses the basename you gave, so when you search the job store with a query matching that basename, the file shows up ๐Ÿ”ฅ

Returns

a jobStoreFileID that points to the newly created file, so you can reference it later ๐ŸŽ€

Return type

str


Bestie, this one is a whole vibe ๐Ÿฆ‹ It copies or hard links the file referenced by jobStoreFileID to your local file path. The version you get matches the last copy that was written or updated. If the job store file gets changed later via updateFile or updateFileStream, whether those writes show up at localFilePath is up to each implementation ๐Ÿคทโ€โ™€๏ธ

The copy happens atomically, so the file won't show up in your local file system until the copy is totally done ๐Ÿ’…

The file at the given local path may not be modified after this method returns! ๐Ÿšซ
Note! Implementations of readFile need to respect/provide the executable attribute on FileIDs. ๐Ÿ”ฅ

Parameters

  • file_id (str) โ€” the ID of the file you want copied ๐Ÿ’œ
  • local_path (str) โ€” the local path that tells Toil where to put the contents of the file from the job store ๐Ÿ—บ๏ธ
  • symlink (bool) โ€” whether the reader can handle a symlink. If you set this to true, the job store might make a symlink instead of a full copy, or a hard link โœจ
  • file_id
  • local_path
  • symlink

Return type

None


โœจ abstractmethod read_file_stream(file_id, encoding=None, errors=None)

This is basically readFile's cute cousin ๐ŸŒˆ It returns a context manager that gives you a file handle you can read from. You don't need to close the handle yourself, and you actually shouldn't ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • file_id (FileID | str) โ€” the ID of the file you want a readable file handle for ๐Ÿ“
  • encoding (str | None) โ€” the name of the encoding used to decode the file. Encodings work the same as they do for decode(). It defaults to None, which means binary mode ๐Ÿค“
  • errors (str | None) โ€” an optional string that tells Toil how to handle encoding errors. Errors work the same as they do for open(), and it defaults to 'strict' when you set an encoding ๐Ÿ’–
  • file_id
  • encoding
  • errors

Returns

a context manager that gives you a file handle you can read from ๐Ÿ“–

Return type

Iterator[Union[IO[bytes], IO[str]]]


โœจ abstractmethod delete_file(file_id)

Deleting a file from the job store is idempotent, which means deleting it twice, or deleting something that doesn't exist, just succeeds silently ๐Ÿซถ No drama, no errors, just vibes โœจ

Parameters

  • file_id (str) โ€” the ID of the file to delete ๐Ÿ—‘๏ธ
  • file_id

Return type

None


โœจ fileExists(jobStoreFileID)

Checks whether a file exists in this job store ๐Ÿ‘€

Parameters

jobStoreFileID (str)

Return type

bool


โœจ abstractmethod file_exists(file_id)

Same energy as fileExists, but this version is the abstract one ๐Ÿงš It checks whether a file exists in this job store ๐Ÿ”

Parameters

  • file_id (str) โ€” an ID that references the file you want to check ๐Ÿ’œ

Return type

bool


โœจ getFileSize(jobStoreFileID)

Gets the size of the given file in bytes ๐Ÿ“ Lowkey the easiest one of the whole bunch ๐ŸŒธ

Parameters

jobStoreFileID (str)

Return type

int

๐Ÿ’– get_file_size(file_id)

abstractmethod get_file_size(file_id)

Okay so this one gets the size of a file in bytes ๐Ÿ“. If the file doesn't exist when you ask, you get 0 instead. Lowkey iconic.

ngl, job stores that encrypt files might give you overestimates of the size ๐Ÿ™ˆ. The encrypted file may have been padded out to the nearest block, and an initialization vector may have been tacked on, etc.

Parameters ๐ŸŽ€

  • file_id (str) โ€” an ID referencing the file to be checked
  • file_id

Return type โœจ int

๐Ÿฆ‹ updateFile(jobStoreFileID, localFilePath)

updateFile(jobStoreFileID, localFilePath)

This one replaces the existing version of a file in the job store. Bestie, it's giving "overwrite the old one" energy ๐Ÿ’….

Parameters ๐ŸŽ€

  • jobStoreFileID (str)
  • localFilePath (str)

Return type โœจ None

๐ŸŒธ update_file(file_id, local_path)

abstractmethod update_file(file_id, local_path)

Same vibe as updateFile, just with the newer snake_case name ๐Ÿ. It replaces the existing version of a file in the job store, and it throws an exception if the file does not exist ๐Ÿ’€. So make sure the file is actually there before you try.

Parameters ๐ŸŽ€

  • file_id (str) โ€” the ID of the file in the job store to be updated
  • local_path (str) โ€” the local path to a file that will overwrite the current version in the job store

Raises ๐Ÿ˜ญ

  • ConcurrentFileModificationException โ€” if the file was modified concurrently during an invocation of this method
  • NoSuchFileException โ€” if the specified file does not exist

Return type โœจ None

๐Ÿงš update_file_stream(file_id, encoding=None, errors=None)

abstractmethod update_file_stream(file_id, encoding=None, errors=None)

This is giving write_shared_file_stream realness, but for replacing a file that already exists ๐Ÿซถ. It replaces the existing version of a file in the job store, and it returns a context manager that yields a file handle you can write to.

Important bestie moment ๐Ÿšจ: the yielded file handle does not need to be closed explicitly, and it should not be closed explicitly. Don't do it!!

Parameters ๐ŸŽ€

  • file_id (str) โ€” the ID of the file in the job store to be updated
  • encoding (str | None) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). Defaults to None, which means binary mode.
  • errors (str | None) โ€” an optional string that tells Python how to handle encoding errors. Errors work the same as for open(). Defaults to 'strict' when an encoding is specified.
  • file_id
  • encoding
  • errors

Raises ๐Ÿ˜ญ

  • ConcurrentFileModificationException โ€” if the file was modified concurrently during an invocation of this method
  • NoSuchFileException โ€” if the specified file does not exist

Return type โœจ Iterator[IO[Any]]

๐Ÿ”ฅ write_shared_file_stream(shared_file_name, encrypted=None, encoding=None, errors=None)

abstractmethod write_shared_file_stream(shared_file_name, encrypted=None, encoding=None, errors=None)

This one returns a context manager that yields a writable file handle to the global file referenced by the name you give it ๐Ÿ“. The file gets created in an atomic manner, which means it's all or nothing, no half-written messes ๐Ÿ‘‘.

Parameters ๐ŸŽ€

  • shared_file_name (str) โ€” a file name matching AbstractJobStore.fileNameRegex, and it has to be unique within this job store
  • encrypted (bool | None) โ€” True if the file must be encrypted, None if it may or may not be encrypted, or False if it must be stored in the clear
  • encoding (str | None) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). Defaults to None, which means binary mode.
  • errors (str | None) โ€” an optional string that tells Python how to handle encoding errors. Errors work the same as for open(). Defaults to 'strict' when an encoding is specified.
  • shared_file_name
  • encrypted
  • encoding
  • errors

Raises ๐Ÿ˜ญ

  • ConcurrentFileModificationException โ€” if the file was modified concurrently during an invocation of this method

Returns ๐Ÿ’œ a context manager yielding a writable file handle

Return type โœจ Iterator[IO[bytes]]

๐ŸŒˆ read_shared_file_stream(shared_file_name, encoding=None, errors=None)

abstractmethod read_shared_file_stream(shared_file_name, encoding=None, errors=None)

The reading buddy of the one above ๐Ÿ“–. It returns a context manager that yields a readable file handle to the global file referenced by the given name.

Parameters ๐ŸŽ€

  • shared_file_name (str) โ€” a file name matching AbstractJobStore.fileNameRegex, and it has to be unique within this job store
  • encoding (str | None) โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which means binary mode.
  • errors (str | None) โ€” an optional string that tells Python how to handle encoding errors. Errors work the same as for open(). Defaults to 'strict' when an encoding is specified.
  • shared_file_name
  • encoding
  • errors

Return type โœจ Iterator[IO[str]] | Iterator[IO[bytes]]

Returns ๐Ÿ’œ a context manager yielding a readable file handle

๐Ÿ“ write_logs(msg)

abstractmethod write_logs(msg)

Slay, this one stores a message as a log in the jobstore ๐Ÿ“‹. It's the place to drop your notes so future-you can find them ๐Ÿงš.

Parameters ๐ŸŽ€

  • msg (str) โ€” the string to be written
  • msg

Raises ๐Ÿ˜ญ

  • ConcurrentFileModificationException โ€” if the file was modified concurrently during an invocation of this method

Return type โœจ None

abstractmethod read_logs(callback, read_all=False)

okay so this one is the log reader ๐Ÿ“–๐Ÿ’… It reads the logs that write_logs() has been stacking up. For each log, it calls your callback function with the message as an argument. It won't hand you the logs back directly, bestie ๐Ÿ™…โ€โ™€๏ธ you have to pass in a callback that processes the messages โœจ.

Only unread logs get read, unless you set the read_all parameter ๐Ÿ‘€

Parameters

  • callback (Callable[..., Any]) โ€” a function to be applied to each of the stats file handles found ๐Ÿ’–
  • read_all (bool) โ€” a boolean that decides whether the already processed stats files get read too, on top of the unread ones ๐ŸŒธ
  • callback
  • read_all

Raises toil.jobStores.abstractJobStore.ConcurrentFileModificationException โ€” if the file got modified concurrently during an invocation of this method ๐Ÿ˜ญ

Returns the number of stats files processed ๐ŸŽ€

Return type int


write_leader_pid() ๐Ÿงš

Writes the pid of this process to a file in the job store.

Overwriting the current contents of pid.log is a feature, not a bug ๐Ÿ’œ Other methods rely on always having the most current pid available. So far there's no reason to store any old pids.

Return type None

read_leader_pid() ๐Ÿฆ‹

Reads the pid of the leader process from a file in the job store.

Raises toil.jobStores.abstractJobStore.NoSuchFileException โ€” if the PID file doesn't exist ๐Ÿ’€

Return type int

write_leader_node_id() ๐ŸŒˆ

Writes the leader node id to the job store. This should only be called by the leader ๐Ÿ‘‘

Return type None

read_leader_node_id() ๐Ÿซถ

Reads the leader node id stored in the job store.

Raises toil.jobStores.abstractJobStore.NoSuchFileException โ€” if the node ID file doesn't exist ๐Ÿ˜ญ

Return type str

write_kill_flag(kill=False) ๐Ÿšจ

Writes a file inside the job store that acts as a kill flag โœจ

The initialized file contains the characters "NO". This should only be changed when the user runs the "toil kill" command. Changing the file to "YES" triggers a kill of the leader process, and the workers are expected to be cleaned up by the leader ๐Ÿ”ฅ

Parameters

  • kill (bool)

Return type None

read_kill_flag() ๐Ÿ™ˆ

Reads the kill flag from the job store. Returns True if the leader has been killed, and False otherwise.

Return type bool

default_caching() ๐Ÿ“

The job store's preference on caching: whether it likes caching or doesn't care either way. Some job stores benefit from caching, but on some local configurations it can be flaky ๐Ÿฅฒ

see https://github.com/DataBiosphere/toil/issues/4218

Return type bool


๐Ÿ‘‘ TOIL JOB API ๐Ÿ‘‘

Functions to wrap jobs and return values (promises). Main character energy ๐Ÿ’…โœจ

๐ŸŽ€ FunctionWrappingJob ๐ŸŽ€

The subclass of Job for wrapping user functions.

class toil.job.FunctionWrappingJob(userFunction, *args, **kwargs)

A job used to wrap a function. In its run method, the wrapped function gets called ๐Ÿฆ‹

Parameters

  • userFunction (Callable[..., Any])
  • args (Any)
  • kwargs (Any)

__init__(userFunction, *args, **kwargs) ๐ŸŒธ

Parameters

  • userFunction (callable) โ€” the function to wrap. It will be called with *args and **kwargs as arguments ๐Ÿ’–
  • args (Any)
  • kwargs (Any)

Return type None

The keywords memory, cores, disk, accelerators, preemptible and checkpoint are reserved keyword arguments. If you specify them, they get used to determine the resources the job requires, same as toil.job.Job.__init__() ๐Ÿง  If they're keyword arguments to the function, they'll be pulled out of the function definition, but you can override them (as you would expect, obviously) ๐Ÿ’…

Parameters

  • userFunction (Callable[..., Any])
  • args (Any)
  • kwargs (Any)

Return type None

run(fileStore) ๐Ÿงšโ€โ™€๏ธ

Override this function to perform work and dynamically create successor jobs โœจ

Parameters

  • fileStore (AbstractFileStore) โ€” used to create local and globally sharable temporary files, and to send log messages to the leader process ๐Ÿซถ (the full name is toil.fileStores.abstractFileStore.AbstractFileStore)

Return type Any

Returns The return value of the function can be passed to other jobs by means of toil.job.Job.rv() ๐ŸŒˆ

๐Ÿ’œ JobFunctionWrappingJob ๐Ÿ’œ

The subclass of FunctionWrappingJob for wrapping user job functions. It's giving organized ๐Ÿ“

class toil.job.JobFunctionWrappingJob(userFunction, *args, **kwargs)

A job function is a function whose first argument is a Job instance, which is the wrapping job for the function. This lets the function add successor jobs and use everything the Job class provides ๐Ÿ‘‘

To give the job function access to the toil.fileStores.abstractFileStore.AbstractFileStore instance (see toil.job.Job.run()), it's made into a variable of the wrapping job called fileStore ๐Ÿฆ‹

To specify a job's resource requirements, these default keyword arguments are available:

  • memory
  • disk
  • cores
  • accelerators
  • preemptible

For example, to wrap a function into a job, you'd call:

Job.wrapJobFn(myJob, memory='100k', disk='1M', cores=0.1)

Parameters

  • userFunction (Callable[..., Any])
  • args (Any)
  • kwargs (Any)

run(fileStore) โœจ

Override this function to perform work and dynamically create successor jobs ๐Ÿ’…

Parameters

  • fileStore (AbstractFileStore) โ€” used to create local and globally sharable temporary files, and to send log messages to the leader process ๐Ÿซถ (the full name is toil.fileStores.abstractFileStore.AbstractFileStore)

Return type Any

Okay so the return value of your function can be passed along to other jobs using toil.job.Job.rv(), which means it's basically a gift for your downstream jobs ๐ŸŽโœจ

๐ŸŒธ EncapsulatedJob

EncapsulatedJob is the Job subclass for wrapping up a job, so a whole subgraph of jobs can act like one single job ๐Ÿซถ

๐Ÿ’– class toil.job.EncapsulatedJob(job, unitName=None)

This is a convenience Job class that makes a job subgraph look like a single job. Bestie, it's giving main character energy ๐Ÿ‘‘

Say A is the root job of a subgraph and B is another job we want to run after A and all of its successors are finished. Here's how you encapsulate it:

#  Job A and subgraph, Job B
A, B = A(), B()
Aprime = A.encapsulate()
Aprime.addChild(B)
#  B will run after A and all its successors have completed, A and its subgraph of
# successors in effect appear to be just one job.

If the job being encapsulated has predecessors (so it isn't the root job), the encapsulated job inherits those predecessors. But if predecessors get added to the job being encapsulated after the encapsulated job is created, the encapsulating job will NOT inherit them automatically ๐Ÿ˜ญ So make sure the encapsulated job has the right set of predecessors, ngl this part matters a lot.

๐Ÿ™ˆ Watch out: predecessors added after the encapsulated job exists are not inherited automatically. Double-check the predecessor set yourself!

The return value of an encapsulated job (the one you get from toil.job.Job.rv()) is the return value of the root job. So A().encapsulate().rv() and A().rv() resolve to the same value once A or A.encapsulate() has run. Iconic consistency ๐Ÿ’…

Parameters

  • job (Job | None)
  • unitName (str | None)

๐ŸŒท __init__(job, unitName=None)

Parameters

  • job (Job | None) โ€” the job to encapsulate.
  • unitName (str | None) โ€” a human-readable name to identify this job instance.

Return type: None

๐Ÿ’… addChild(childJob)

Adds a childJob to be run as a child of this job. Child jobs run directly after this job's toil.job.Job.run() method has finished, so they're up next once the run is done โœจ

Return type: Job

Returns: childJob, for call chaining ๐Ÿ”—

Parameters:

  • childJob (Job)

๐Ÿงš addService(service, parentService=None)

Adds a service. The toil.job.Job.Service.start() method of the service gets called after the run method has completed but before any successors run. The service's toil.job.Job.Service.stop() method gets called once the job's successors have run ๐ŸŒˆ

Services are how things like databases and servers get started up and accessed by jobs in a workflow. Lowkey so useful ๐Ÿ“

โš ๏ธ Raises toil.job.JobException: if the service has already been made the child of a job or of another service.

Parameters

  • service โ€” the Service to add.
  • parentService โ€” the Service that will be started before service is started. This lets you build trees of services. parentService must be a service of this job.

Returns: a promise that will be replaced with the return value from toil.job.Job.Service.start() of service in any successor of the job ๐Ÿฆ‹

๐ŸŽ€ addFollowOn(followOnJob)

Adds a follow-on job. Follow-on jobs run after the child jobs and their successors have been run, so they're the last to slay the stage ๐Ÿ‘‘

Return type: Job

Returns: followOnJob, for call chaining

Parameters:

  • followOnJob (Job)

๐Ÿซง rv(*path)

Creates a promise (toil.job.Promise). This is the "promise" that represents a return value of the job's run method or, if it's a function-wrapping job, the wrapped function's return value ๐ŸŽ

Parameters:

  • path (Any) โ€” optional path for selecting a component of the promised return value. If it's absent or empty, the entire return value gets used. Otherwise, the first element of the path selects an individual item from the return value. For that to work, the return value must be a list, dictionary, or any other type implementing the __getitem__() magic method. If the selected item is another composite value, the second element of the path can select an item from it, and so on. For example, if the return value is [6,{'a':42}], .rv(0) would select 6, rv(1) would select {'a':3}, and rv(1,'a') would select 3. To select a slice from a return value that's sliceable (like a tuple or list), the path element should be a slice object. For example, if the return value is [6, 7, 8, 9], then .rv(slice(1, 3)) would select [7, 8]. Note that slicing really only makes sense at the end of the path ๐Ÿ”ช

Return type: Promise

Returns: a promise representing the return value of this job's toil.job.Job.run() method ๐ŸŒธ

๐Ÿฆ„ prepareForPromiseRegistration(jobStore)

Sets things up so this job's promises can register themselves. This prepares this job (the promisor) so its promises can register with it when the jobs they're promised to (the promisees) get serialized ๐Ÿงฉ

The promisee holds the reference to the promise, usually as part of its job arguments. When it's being pickled, so are the promises it refers to. Pickling a promise triggers it to register with the promisor. It's a whole chain reaction ๐Ÿ’–

๐ŸŽ Promise

Promise is the class used to reference return values of jobs and services that haven't run or started yet ๐Ÿ”ฎ

๐Ÿ’œ class toil.job.Promise(job, path)

This references a return value from a method as a promise before that method has actually run. Specifically, it covers a return value from a toil.job.Job.run() or toil.job.Job.Service.start() method ๐ŸŒ™

Let T be a job. Instances of Promise (called a promise) are returned by T.rv(), which references the return value of T's run function. When the promise is passed to the constructor (or as an argument to a wrapped function) of a different, successor job, the promise gets replaced by the actual referenced return value. This is the magic that lets one job's run method return value be an input argument to a job before that first job's run function has executed. Big brain energy ๐Ÿง 

Parameters

  • job (Job)
  • path (Any)

Return type: Promise

๐ŸŒŸ filesToDelete = {}

A set of IDs of files containing promised values, for when we know we won't need them anymore ๐Ÿ—‘๏ธ

๐Ÿช„ __init__(job, path)

Initializes this promise.

Parameters

  • job (Job) โ€” the job whose return value this promise references.
  • path (Any) โ€” see Job.rv().

๐Ÿฆ‹ class toil.job.PromisedRequirement(valueOrCallable, *args)

This is a class for dynamically allocating a job function's resource requirements, and it involves toil.job.Promise instances. Use it when resource requirements depend on the return value of a parent function ๐Ÿ’…

A PromisedRequirement can be modified by passing in a function that takes the Promise as input.

For example, let f, g, and h be functions. Then a Toil workflow can be defined like this:

A = Job.wrapFn(f)
B = A.addChildFn(g, cores=PromisedRequirement(A.rv())
C = B.addChildFn(h, cores=PromisedRequirement(lambda x: 2*x, B.rv()))

Parameters

  • valueOrCallable (Any)
  • args (Any)

๐ŸŽ€ __init__(valueOrCallable, *args)

Initializes this Promised Requirement.

Parameters

  • valueOrCallable (Any) โ€” a single Promise instance or a function that takes args as input parameters. ๐Ÿซถ

๐ŸŽ€ Part 39: Promises, Job Methods, and the Goodies ๐ŸŽ€

  • args (int (/usr/share/doc/python3/html/library/functions.html#int) or .Promise): a variable-length argument list, so you can toss in as many as you need ๐Ÿงšโœจ

Return type None

๐ŸŒธ getValue()

Okay, this one's simple and it slays ๐Ÿ’… getValue() gives you back the PromisedRequirement value.

Return type Any (/usr/share/doc/python3/html/library/typing.html#typing.Any)

๐Ÿซถ static convertPromises(kwargs)

Bestie, this one checks whether a reserved resource keyword is a Promise or PromisedRequirement instance. If it is, it returns True. It also converts a Promise instance into a PromisedRequirement, so it's doing the most ๐Ÿ’–

Parameters

  • kwargs (dict (/usr/share/doc/python3/html/library/stdtypes.html#dict)[str (/usr/share/doc/python3/html/library/stdtypes.html#str), Any (/usr/share/doc/python3/html/library/typing.html#typing.Any)]): the function keyword arguments ๐ŸŒˆ

Return type bool (/usr/share/doc/python3/html/library/functions.html#bool)


โœจ JOB METHODS API โœจ

Okay, this section is the heart of it all ๐Ÿซถ Jobs are the units of work in Toil, and workflows are built by composing them together. Main character energy ๐Ÿ‘‘

๐Ÿงš toil.job.Job

class toil.job.Job(memory=None, cores=None, disk=None,
accelerators=None, preemptible=None, preemptable=None, unitName='',
checkpoint=False, displayName='', descriptionClass=None, local=None,
files=None)

This class represents a unit of work in Toil. It's the building block, iykyk ๐Ÿงฑ

Parameters

  • memory (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | int (/usr/share/doc/python3/html/library/functions.html#int) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • cores (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | int (/usr/share/doc/python3/html/library/functions.html#int) | float (/usr/share/doc/python3/html/library/functions.html#float) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • disk (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | int (/usr/share/doc/python3/html/library/functions.html#int) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • accelerators (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | int (/usr/share/doc/python3/html/library/functions.html#int) | Mapping (/usr/share/doc/python3/html/library/typing.html#typing.Mapping)[str (/usr/share/doc/python3/html/library/stdtypes.html#str), Any (/usr/share/doc/python3/html/library/typing.html#typing.Any)] | AcceleratorRequirement (#toil.job.AcceleratorRequirement) | Sequence (/usr/share/doc/python3/html/library/typing.html#typing.Sequence)[str (/usr/share/doc/python3/html/library/stdtypes.html#str) | int (/usr/share/doc/python3/html/library/functions.html#int) | Mapping (/usr/share/doc/python3/html/library/typing.html#typing.Mapping)[str (/usr/share/doc/python3/html/library/stdtypes.html#str), Any (/usr/share/doc/python3/html/library/typing.html#typing.Any)] | AcceleratorRequirement (#toil.job.AcceleratorRequirement)] | None (/usr/share/doc/python3/html/library/constants.html#None))
  • preemptible (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | int (/usr/share/doc/python3/html/library/functions.html#int) | bool (/usr/share/doc/python3/html/library/functions.html#bool) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • preemptable (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | int (/usr/share/doc/python3/html/library/functions.html#int) | bool (/usr/share/doc/python3/html/library/functions.html#bool) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • unitName (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • checkpoint (bool (/usr/share/doc/python3/html/library/functions.html#bool) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • displayName (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • descriptionClass (type (/usr/share/doc/python3/html/library/functions.html#type) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • local (bool (/usr/share/doc/python3/html/library/functions.html#bool) | None (/usr/share/doc/python3/html/library/constants.html#None))
  • files (set (/usr/share/doc/python3/html/library/stdtypes.html#set)[FileID (#toil.fileStores.FileID)] | None (/usr/share/doc/python3/html/library/constants.html#None))

๐Ÿฆ‹ __init__

__init__(memory=None, cores=None, disk=None, accelerators=None,
preemptible=None, preemptable=None, unitName='',
checkpoint=False, displayName='', descriptionClass=None,
local=None, files=None)

This is the Job initializer, so it's where the magic starts โœจ Any overriding constructor must call this method, no exceptions ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • memory (int (/usr/share/doc/python3/html/library/functions.html#int) or a string convertible by toil.lib.conversions.human2bytes to an int): the maximum number of bytes of memory the job will need to run ๐Ÿง 
  • cores (float (/usr/share/doc/python3/html/library/functions.html#float), int (/usr/share/doc/python3/html/library/functions.html#int), or a string convertible by toil.lib.conversions.human2bytes to an int): the number of CPU cores required ๐Ÿ’ช
  • disk (int (/usr/share/doc/python3/html/library/functions.html#int) or a string convertible by toil.lib.conversions.human2bytes to an int): the amount of local disk space the job needs, expressed in bytes ๐Ÿ’พ
  • accelerators (int (/usr/share/doc/python3/html/library/functions.html#int), string, dict (/usr/share/doc/python3/html/library/stdtypes.html#dict), or list (/usr/share/doc/python3/html/library/stdtypes.html#list) of those. Strings and dicts must be parseable by parse_accelerator): the computational accelerators the job needs. If it's a string, it can be a string of a number, or a string naming a model, brand, or API (with an optional colon-delimited count) ๐Ÿš€
  • preemptible (bool (/usr/share/doc/python3/html/library/functions.html#bool), int in {0, 1}, or string in {'false', 'true'} in any case): whether the job can run on a preemptible node ๐ŸŒ€
  • preemptable (str (/usr/share/doc/python3/html/library/stdtypes.html#str) | int (/usr/share/doc/python3/html/library/functions.html#int) | bool (/usr/share/doc/python3/html/library/functions.html#bool) | None (/usr/share/doc/python3/html/library/constants.html#None)): a legacy preemptible parameter, kept for backwards compatibility with workflows that don't use the preemptible keyword ๐Ÿ•ฐ๏ธ
  • unitName (str (/usr/share/doc/python3/html/library/stdtypes.html#str)): a human-readable name for this instance of the job ๐Ÿท๏ธ
  • checkpoint (bool (/usr/share/doc/python3/html/library/functions.html#bool)): if any of this job's successor jobs completely fails and exhausts all their retries, remove those successor jobs and rerun this job to restart the subtree. The job must be a leaf vertex in the job graph when it's initially defined. See toil.job.Job.checkNewCheckpointsAreCutVertices() ๐Ÿ”
  • displayName (str (/usr/share/doc/python3/html/library/stdtypes.html#str)): a human-readable display name for the job type ๐ŸŽ€
  • descriptionClass (class): an override for the JobDescription class used to describe the job ๐Ÿ“‹
  • local (bool (/usr/share/doc/python3/html/library/functions.html#bool) | None (/usr/share/doc/python3/html/library/constants.html#None)): whether the job can run on the leader ๐Ÿ‘‘
  • files (set (/usr/share/doc/python3/html/library/stdtypes.html#set)[FileID (#toil.fileStores.FileID)] | None (/usr/share/doc/python3/html/library/constants.html#None)): a set of Files the job will want to use ๐Ÿ“

Return type None

๐Ÿ’œ check_initialized()

This one double-checks that Job.__init__() has been called by any subclass __init__(). It works because the self._description instance variable should always be set after __init__(). If __init__() never got called, it raises an error, so no sneaky skipping ๐Ÿ™…โ€โ™€๏ธ

Return type None (/usr/share/doc/python3/html/library/constants.html#None)

๐ŸŽ€ property jobStoreID: str | TemporaryID

okay so this one hands you the ID of this Job ๐Ÿ†”โœจ main character ID energy fr

Return type: Union[str, TemporaryID]

๐ŸŒธ property description: JobDescription

this gives you the JobDescription that describes this job ๐Ÿ‘€๐Ÿซถ you can literally peek behind the curtain

Return type: JobDescription

๐Ÿ’พ property disk: int

the maximum number of bytes of disk the job needs to run. it's giving "bring enough snacks for the trip" ๐Ÿ“

Return type: int

๐Ÿง  property memory: int

the maximum number of bytes of memory the job needs to run. no cap, same energy as disk but for RAM ๐Ÿ’œ

Return type: int

๐Ÿ‘‘ property cores: int | float

the number of CPU cores required. sometimes a whole number, sometimes a float, we don't judge ๐Ÿฆ‹

Return type: Union[int, float]

๐Ÿ”ฅ property accelerators: list[AcceleratorRequirement]

any accelerators the job needs, like GPUs. the glow-up hardware ๐Ÿ’…โญ

Return type: list[AcceleratorRequirement]

๐Ÿฆ‹ property preemptible: bool

whether the job is allowed to run on a preemptible node. bestie, this is the "okay you can get kicked off but we'll still vibe" setting ๐ŸŒˆ

Return type: bool

๐Ÿงš property checkpoint: bool

figures out whether the job is a checkpoint job or not. iykyk ๐Ÿ™ˆ

Return type: bool

โœจ assignConfig(config)

assigns the given config object, and then the various actions inside the Job class get to use it. it's the group chat that everyone reads from ๐Ÿ’–

Parameters

  • config (Config) โ€” the config object to query

Return type: None

๐ŸŒˆ run(fileStore)

this is the one you override when you want the job to actually do the work and dynamically create successor jobs. main character moment ๐Ÿ”ฅ๐Ÿ‘‘

Parameters

  • fileStore (AbstractFileStore) โ€” this is what you use to make local and globally sharable temporary files, and to send log messages to the leader process ๐Ÿ“

Return type: Any

Returns

The return value of the function can be passed to other jobs using toil.job.Job.rv(). passing the tea along ๐Ÿซ–๐Ÿ’…

๐ŸŒธ addChild(childJob)

adds a childJob to run as a child of this job. child jobs run right after this job's toil.job.Job.run() method finishes, so no waiting around ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

Return type: Job

Returns

childJob, so you can keep chaining calls ๐Ÿ”—

Parameters

  • childJob (Job)

๐Ÿฆ‹ hasChild(childJob)

checks whether childJob is already a child of this job. no double-booking the vibes ๐Ÿ™…โ€โ™€๏ธ

Return type: bool

Returns

True if childJob is a child of the job, otherwise False ๐Ÿ’œ

Parameters

  • childJob (Job)

๐Ÿ“ addFollowOn(followOnJob)

adds a follow-on job. follow-ons run after the child jobs and their successors have all run, so they're the encore ๐ŸŽคโœจ

Return type: Job

Returns

followOnJob, for call chaining ๐Ÿ”—

Parameters

  • followOnJob (Job)

๐Ÿซถ hasPredecessor(job)

checks whether a given job is already a predecessor of this job. the family tree check ๐ŸŒณ

Parameters

  • job (Job)

Return type: bool

๐Ÿ’– hasFollowOn(followOnJob)

checks whether the given job is already a follow-on of this job. lowkey the same energy as hasChild, just for encores ๐ŸŽถ

Return type: bool

Returns

True if followOnJob is a follow-on of this job, otherwise False โœจ

Parameters

  • followOnJob (Job)

๐ŸŽ€ addService(service, parentService=None)

adds a service. the service's toil.job.Job.Service.start() method gets called after run finishes but before any successors run, and its toil.job.Job.Service.stop() method gets called once the successors of the job have run ๐Ÿง˜โ€โ™€๏ธ

services are how you get things like databases and servers started up and accessed by jobs in a workflow. the backstage crew ๐ŸŽญ๐ŸŒŸ

heads up: if the service has already been made the child of a job or another service, this raises toil.job.JobException. no stealing other people's services bestie ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’€

Parameters

  • service (Service) โ€” the service to add ๐Ÿ’…
  • parentService (Service | None) โ€” a service that gets started before service is started. this is how you build trees of services ๐ŸŒณ the parentService has to be a service of this job

Return type: Promise

Returns

a promise that gets replaced with the return value from toil.job.Job.Service.start() of service in any successor of the job ๐Ÿฆ‹

๐ŸŒˆ hasService(service)

returns True if the given Service is a service of this job, and False otherwise. yes or no, no vibes-based answers ๐Ÿ’…

Parameters

  • service (Service)

Return type: bool

๐Ÿงš addChildFn(fn, *args, **kwargs)

adds a function as a child job ๐ŸŒธ

Parameters

  • fn (Callable) โ€” the function to run as a child job, with *args and **kwargs passed in as its arguments. check out toil.job.FunctionWrappingJob for the reserved keyword arguments you use to set resource requirements ๐Ÿ“ฆ

Return type: FunctionWrappingJob

Returns

the new child job that wraps fn ๐Ÿ‘‘

๐Ÿ“ addFollowOnFn(fn, *args, **kwargs)

adds a function as a follow-on job, same vibe as addChildFn but for the encore slot ๐ŸŽค

Parameters

  • fn (Callable) โ€” the function to run as a follow-on job, with *args and **kwargs passed in as its arguments. the reserved keyword arguments for resource requirements live in toil.job.FunctionWrappingJob ๐Ÿ’…

Return type: FunctionWrappingJob

Returns

the new follow-on job that wraps fn โœจ

๐Ÿฆ‹ addChildJobFn(fn, *args, **kwargs)

adds a job function as a child job. if you're wondering what a job function is, peep toil.job.JobFunctionWrappingJob for the full definition ๐Ÿซถ

Parameters

  • fn (Callable) โ€” the job function to run as a child job, with *args and **kwargs passed in as its arguments. the reserved keyword arguments for resource requirements are covered in toil.job.JobFunctionWrappingJob ๐ŸŒˆ

Return type: FunctionWrappingJob

Returns

the new child job that wraps fn ๐Ÿ’–

๐Ÿ’œ addFollowOnJobFn(fn, *args, **kwargs)

adds a follow-on job function. for the official definition of a job function, check out toil.job.JobFunctionWrappingJob. it's giving encore with a job function twist ๐ŸŽถ๐Ÿ’…

Okay so this first bit is about follow-on jobs ๐Ÿฆ‹ You hand it a job function, and it runs right after as a follow-on, with your *args and **kwargs going straight into that function โœจ

Parameters

  • fn (Callable) โ€” the job function you want to run as a follow-on, with *args and **kwargs as its arguments ๐Ÿ’– For the reserved keyword arguments that set resource requirements, peek at toil.job.JobFunctionWrappingJob ๐ŸŽ€

Return type: FunctionWrappingJob

Returns: the brand new follow-on job that wraps fn ๐ŸŒธ


property tempDir: str

This one is a shortcut for job.fileStore.getLocalTempDir() ๐Ÿงš The temp dir gets created on the very first call, and that same dir comes back for that call and every call after it โœจ

Returns: the path to the tempDir. See job.fileStore.getLocalTempDir ๐Ÿ—‚๏ธ

Return type: str


log(text, level=20)

Logs stuff using fileStore.log_to_leader() ๐Ÿ“ฃ

Parameters

  • text (str)

Return type: None


static wrapFn(fn, *args, **kwargs)

Turns a plain function into a Job ๐Ÿ“ It's a convenience wrapper for the constructor of toil.job.FunctionWrappingJob ๐Ÿ’…

Parameters

  • fn โ€” the function to run, with *args and **kwargs as its arguments. For reserved keyword arguments that set resource requirements, check out toil.job.JobFunctionWrappingJob ๐ŸŽ€

Return type: FunctionWrappingJob

Returns: the new function that wraps fn ๐Ÿฆ‹


static wrapJobFn(fn, *args, **kwargs)

Turns a job function into a Job ๐Ÿ‘‘ Another convenience wrapper, this time for the constructor of toil.job.JobFunctionWrappingJob ๐Ÿ’–

Parameters

  • fn โ€” the job function to run, with *args and **kwargs as its arguments. Reserved keyword arguments for setting resource requirements are described in toil.job.JobFunctionWrappingJob ๐ŸŒˆ

Return type: JobFunctionWrappingJob

Returns: the new job function that wraps fn โœจ


encapsulate(name=None)

Encapsulates the job, see toil.job.EncapsulatedJob ๐Ÿซถ It's a convenience function for the constructor of toil.job.EncapsulatedJob ๐Ÿ’œ

Parameters

  • name (str | None) โ€” a human-readable name for the encapsulated job ๐Ÿท๏ธ

Return type: EncapsulatedJob

Returns: an encapsulated version of this job ๐ŸŽ


rv(*path)

This makes a promise (toil.job.Promise) ๐Ÿ”ฎ The promise stands in for the return value of the job's run method, or, if it's a function-wrapping job, the wrapped function's return value ๐Ÿง 

Parameters

  • path (Any) โ€” an optional path for picking out a piece of the promised return value ๐ŸŽฏ If it's absent or empty, you get the whole return value. Otherwise, the first element of the path picks out one item of the return value. For that to work, the return value has to be a list, a dictionary, or any other type that implements the __getitem__() magic method. If the picked item is another composite value, the second element of the path can pick an item from that, and so on. For example, if the return value is [6,{'a':42}], .rv(0) selects 6, rv(1) selects {'a':3}, and rv(1,'a') selects 3. To grab a slice from a slicable return value, like a tuple or list, the path element should be a slice object. For example, if the return value is [6, 7, 8, 9], then .rv(slice(1, 3)) selects [7, 8].
Heads up bestie: slicing only really makes sense at the end of the path ๐Ÿ™ˆ

Return type: Promise

Returns: a promise representing the return value of this job's toil.job.Job.run() method ๐Ÿ’…


prepareForPromiseRegistration(jobStore)

This sets things up so this job's promises can register themselves with it ๐Ÿฆ‹ It preps this job (the promisor) so its promises can sign up with it when the jobs they're promised to (the promisees) get serialized ๐ŸŒธ

The promisee holds the reference to the promise, usually inside its job arguments. When it gets pickled, so do the promises it refers to, and pickling a promise triggers it to register with the promisor ๐Ÿ“ฆ

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore), which you'll see as AbstractJobStore ๐Ÿ’พ

Return type: None


checkJobGraphForDeadlocks()

This makes sure a graph of Jobs (one that hasn't been saved to the JobStore yet) doesn't have any pathological relationships that would cause deadlocks if we tried to run the jobs ๐Ÿ’€ Not on my watch ๐Ÿ˜ค

For more info, see toil.job.Job.checkJobGraphConnected(), toil.job.Job.checkJobGraphAcyclic() and toil.job.Job.checkNewCheckpointsAreLeafVertices() ๐Ÿ”

Raises: toil.job.JobGraphDeadlockException if the job graph is cyclic, contains multiple roots, or has checkpoint jobs that aren't leaf vertices when they're defined (see toil.job.Job.checkNewCheckpointsAreLeaves()) ๐Ÿšจ


getRootJobs()

This returns the set of root job objects that contain this job ๐Ÿ‘‘ A root job is a job with no predecessors, meaning it isn't a child, follow-on, or service of anything ๐ŸŒฑ

It only deals with jobs created right here, not jobs loaded from the job store ๐Ÿซถ

Return type: set[Job]


checkJobGraphConnected()

Raises: toil.job.JobGraphDeadlockException if toil.job.Job.getRootJobs() doesn't contain exactly one root job ๐Ÿ˜ฌ

Return type: None

Execution always starts from one root job, so having multiple root jobs will cause a deadlock to occur.

Warning: multiple root jobs = deadlock ๐Ÿ’€ Keep it to exactly one root, periodt ๐Ÿ’…

It only deals with jobs created here, not jobs loaded from the job store ๐ŸŒธ

Return type: None


checkJobGraphAcylic()

Raises: toil.job.JobGraphDeadlockException if the connected component of jobs containing this job has any cycles of child/followOn dependencies in the augmented job graph (see below) ๐Ÿ” Cycles like that aren't allowed in valid job graphs, so don't even try ๐Ÿ™…โ€โ™€๏ธ

Return type: None

Here's the vibe on implied edges: a follow-on edge (A, B) between two jobs A and B is equivalent to adding a child edge to B from (1) A, (2) each child of A, and (3) the successors of each child of A. We call each of those an "implied" edge ๐Ÿงฉ The augmented job graph is a job graph that includes all the implied edges โœจ

For a job graph G = (V, E), the algorithm is O(|V|^2). It's O(|V| + |E|) for a graph with no follow-ons. The former follow-on case could be improved! ๐Ÿ“ˆ

It only deals with jobs created here, not jobs loaded from the job store ๐Ÿซถ

Return type: None


checkNewCheckpointsAreLeafVertices()

So a checkpoint job is one that gets restarted if it fails, or if any of its successors completely fails and exhausts their retries ๐Ÿ”„

A job is a leaf if it has no successors ๐Ÿƒ

A checkpoint job has to be a leaf when it's first added to the job graph. Once its run method is invoked, it can then create direct successors. This restriction is there to simplify the implementation ๐Ÿงš

Only works on connected components of jobs that haven't been added to the JobStore yet, bestie ๐Ÿ’…

  • Raises toil.job.JobGraphDeadlockException ๐Ÿ˜ญ โ€” if there's a job being added to the graph where checkpoint=True and it's not a leaf.

Return type: None ๐Ÿซถ


โœจ defer(function, *args, **kwargs) โœจ

okay so this one registers a deferred function, which is just a callable that gets invoked after the current attempt at running this job wraps up ๐Ÿฆ‹ An attempt is considered concluded when the job function (or the toil.job.Job.run() method for class-based jobs) returns, raises an exception, or after the process running it terminates abnormally. Main character energy for cleanup ๐Ÿ’–

A deferred function gets called on the node that tried to run the job, even if a later attempt happens on another node ๐ŸŒธ It should be idempotent, because it may be called multiple times on the same node or even in the same process. So make sure running it twice is totally fine ๐Ÿ™ˆ

You can register more than one deferred function per job attempt by calling this method repeatedly with different arguments. If the same function is registered twice with the same or different arguments, it'll be called twice per job attempt ๐Ÿ’€

Examples of deferred functions are ones that handle cleanup of resources external to Toil, like Docker containers, files outside the work directory, etc. ๐Ÿงนโœจ

Parameters

  • function (callable) ๐ŸŽ€ โ€” the function to be called after this job concludes.
  • args (list) ๐ŸŒˆ โ€” the arguments to the function.
  • kwargs (dict) ๐Ÿ“ โ€” the keyword arguments to the function.

Return type: None ๐Ÿ’…


โœจ getTopologicalOrderingOfJobs() โœจ

Return type: list[Job] ๐Ÿ‘‘

Returns: a list of jobs such that for all pairs of indices i, j for which i < j, the job at index i can be run before the job at index j. It's giving ordering ๐Ÿ’œ

This only considers jobs in this job's subgraph that are newly added, not loaded from the job store. And it ignores service jobs ๐Ÿ™ˆ


โœจ saveBody(jobStore) โœจ

this saves the execution data for just this job to the JobStore, and fills in the JobDescription with the information needed to retrieve it later ๐Ÿฆ‹

Heads up: the Job's JobDescription must have already been given a real jobStoreID first, or this won't work ๐Ÿ˜ญ

It does not save the JobDescription itself ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • jobStore (AbstractJobStore) ๐Ÿงš โ€” the job store to save the job body into.

Return type: None โœจ


โœจ saveAsRootJob(jobStore) โœจ

this saves the job to the given jobStore as the root job of the workflow ๐Ÿ‘‘ The main character of the whole thing ๐Ÿ’…

Return type: JobDescription ๐ŸŒธ

Returns: the JobDescription describing this job.

Parameters

  • jobStore (AbstractJobStore) ๐Ÿ“

โœจ classmethod loadJob(job_store, job_description) โœจ

this retrieves a toil.job.Job instance from a JobStore, so it's basically the reverse of saving ๐Ÿช„

Parameters

  • job_store (AbstractJobStore) ๐ŸŒˆ โ€” the job store.
  • job_description (JobDescription) ๐Ÿซถ โ€” the JobDescription of the job to retrieve.

Return type: Job ๐Ÿ’–

Returns: the job referenced by the JobDescription.


โœจ set_debug_flag(flag) โœจ

turns on the given debug option for the job ๐Ÿ”ฅ

Parameters

  • flag (str) ๐Ÿ’œ

Return type: None ๐ŸŽ€


โœจ has_debug_flag(flag) โœจ

returns true if the given debug flag is set, so you can check before you do something ๐Ÿ‘€

Parameters

  • flag (str) ๐ŸŒธ

Return type: bool ๐Ÿ’…


โœจ files_downloaded_hook(host_and_job_paths=None) โœจ

this is a function subclasses can call once they've downloaded their input files ๐Ÿ“ฅ

โš ๏ธ If the "download_only" debug flag is set, this will abort the job. Be careful with that one, bestie ๐Ÿ˜ญ

It can also be hinted a list of file path pairs, one outside and one inside the job container, in which case the container environment can be reconstructed ๐Ÿงฉ

Parameters

  • host_and_job_paths (list[tuple[str, str]] | None) ๐Ÿฆ‹

Return type: None โœจ


๐Ÿ’– JobDescription ๐Ÿ’–

okay this is the class used to store all the information that the Toil Leader ever needs to know about a Job ๐Ÿ‘‘

class toil.job.JobDescription(requirements, jobName, unitName='', displayName='', local=None, files=None)

It stores all the info the Toil Leader could ever want, which includes:

  • Resource requirements. ๐Ÿ’ช
  • Which jobs are children, follow-ons, or predecessors of this job. ๐ŸŒณ
  • A reference to the Job object in the job store. ๐Ÿ—„๏ธ

It can be obtained from an actual (executable) Job object, and it can be used to get the Job object back from the JobStore ๐Ÿ”„

It never contains other Jobs or JobDescriptions. Everything is referenced by ID, no cap ๐Ÿซถ It also gets subclassed into variants for checkpoint jobs and service jobs, each with their own specific parameters ๐ŸŒˆ

Parameters

  • requirements (Mapping[str, int | str | float | bool | list]) ๐ŸŽ€
  • jobName (str) ๐ŸŒธ
  • unitName (str | None) ๐Ÿ“
  • displayName (str | None) ๐Ÿงš
  • local (bool | None) ๐Ÿฆ‹
  • files (set[FileID] | None) ๐Ÿ’œ

โœจ __init__(requirements, jobName, unitName='', displayName='', local=None, files=None) โœจ

this creates a new JobDescription ๐ŸŽ‰

Parameters

  • requirements (Mapping[str, int | str | float | bool | list]) ๐Ÿ’… โ€” a dict from string to number, string, or bool describing the resource requirements of the job. The 'cores', 'memory', 'disk', and 'preemptible' fields, if set, get parsed and broken out into properties. If unset, the relevant property is unspecified, and it gets pulled from the assigned Config object when queried (see toil.job.Requirer.assignConfig()) ๐Ÿ”ฅ
  • jobName (str) โ€” ๐Ÿ’– the kind of job this is! It's used in job store IDs and logging, and the cluster scaler uses it to learn how long this kind of job takes. If there's no real user-defined name, it ought to be the job class's name โœจ
  • unitName (str | None) โ€” the name of this particular instance of the job type. It can show up next to jobName in logs ๐Ÿฆ‹
  • displayName (str | None) โ€” a human-readable name for this specific job instance ๐ŸŒธ If there's no real user-defined name, it ought to be the job class's name.
  • local (bool | None) โ€” ๐Ÿƒ if True, the job uses minimal resources but is sensitive to latency, so the leader should run it.
  • files (set[FileID] | None) โ€” a set of FileID objects the job plans to use ๐Ÿ“

Return type: None

get_names()

Gets the names and ID of this job as a named tuple ๐Ÿท๏ธ

Return type: Names

get_chain()

Gets every job that ran in this job's chain, in order, so you can see the whole lineup ๐Ÿ‘‘

For each job, you get a named tuple with its various names and its original job store ID. The jobs are listed in execution order. If the job hasn't run yet or it didn't chain, you just get a one-item list.

Return type: list[Names]

serviceHostIDsInBatches()

Finds all the batches of service host job IDs that can start at the same time ๐Ÿงš

Batches come back in the order they need to start in.

Return type: Iterator[list[str]]

successorsAndServiceHosts()

Gives you an iterator over all child, follow-on, and service job IDs ๐Ÿ’…

Return type: Iterator[str]

allSuccessors()

Gives you an iterator over all child, follow-on, and chained, inherited successor job IDs โœจ Follow-ons come before children.

Return type: Iterator[str]

successors_by_phase()

Gives you an iterator over all child, follow-on, and chained inherited successor job IDs, plus their phase number on the stack ๐Ÿฆ‹

Phases run from higher numbers down to lower numbers.

Return type: Iterator[tuple[int, str]]

services (property)

Gets a collection of the IDs of service host jobs for this job, in arbitrary order ๐ŸŒˆ It's empty if the job has no unfinished services.

has_body()

Returns True if a job body is attached, and False otherwise ๐Ÿซถ

Return type: bool

attach_body(file_store_id, user_script)

Attaches a job body to this JobDescription ๐ŸŽ€

It takes the file store ID that the body is stored at, plus the required user script module. The file store ID can also be "firstJob" for the root job, which is stored as a shared file instead.

Parameters:

  • file_store_id (str)
  • user_script (ModuleDescriptor)

Return type: None

detach_body()

Drops the body reference from a JobDescription ๐Ÿ™ˆ

Return type: None

get_body()

Gets the info needed to load the job body ๐Ÿ”ฅ

Return type: tuple[str, ModuleDescriptor]

Returns: a file store ID (or the magic shared file name "firstJob") and a user script module.

โš ๏ธ This one fails if no body is attached, so check has_body() first, bestie!

nextSuccessors()

Returns the collection of job IDs for this job's successors that are ready to run ๐ŸŒธ Just because they're ready doesn't mean they're free, though. If they have multiple predecessor relationships, they may still be blocked on other jobs.

It returns None when we're at the final phase (all successors are done). It returns an empty collection if there are more phases but they can't be entered yet, like when we're waiting for the job itself to run.

Return type: set[str] | None

filterSuccessors(predicate)

Keeps only the successor jobs that the given predicate function approves ๐Ÿ’…

The predicate is called with each job's ID. Every other successor gets treated as complete and forgotten ๐Ÿ’€

Parameters:

  • predicate (Callable[[str], bool])

Return type: None

filterServiceHosts(predicate)

Keeps only the services that the given predicate approves ๐Ÿงš

The predicate is called with the service host job's ID. Every other service gets treated as complete and forgotten ๐Ÿ‘‹

Parameters:

  • predicate (Callable[[str], bool])

Return type: None

clear_nonexistent_dependents(job_store)

Removes all references to child, follow-on, and associated service jobs that don't exist anymore ๐Ÿ—‘๏ธ In other words, all the ones that have been completed and removed.

Parameters:

  • job_store (AbstractJobStore)

Return type: None

clear_dependents()

Removes all references to successor and service jobs. Full clean slate ๐Ÿงน

Return type: None

is_subtree_done()

Checks whether the subtree is done ๐ŸŒˆ

Return type: bool

Returns: True if the job appears to be done, and all related child, follow-on, and service jobs appear to be finished and removed.

replace(other)

Takes on the ID of another JobDescription, while keeping our own state and type ๐Ÿฆ‹ When it gets updated in the JobStore, we save over the other JobDescription.

This is super useful for chaining jobs: the chained-to job can replace the parent job ๐Ÿ‘‘

Okay so this one merges the cleanup state and successors (everything except this job itself) from the job being replaced into this one ๐Ÿงนโœจ glow-up energy, bestie ๐Ÿ’…

Parameters

  • other (JobDescription) โ€” the job description being replaced ๐ŸŽ€

Return type

  • None

assert_is_not_newer_than(other)

Vibe check time ๐Ÿ•ฐ๏ธ this makes sure this JobDescription is not newer than a prospective new version of it. No time travelling allowed ๐Ÿ’œ

Parameters

  • other (JobDescription)

Return type

  • None

is_updated_by(other)

This returns True if the passed JobDescription is a distinct, newer version of this one ๐Ÿ‘‘ it's giving main character update.

Parameters

  • other (JobDescription)

Return type

  • bool

addChild(childID)

Makes the job with the given ID a child of the described job ๐Ÿงš

Parameters

  • childID (str)

Return type

  • None

addFollowOn(followOnID)

Makes the job with the given ID a follow-on of the described job ๐Ÿฆ‹

Parameters

  • followOnID (str)

Return type

  • None

addServiceHostJob(serviceID, parentServiceID=None)

Makes the ServiceHostJob with the given ID a service of the described job ๐ŸŒธ If you pass a parent ServiceHostJob ID, that parent service starts first, and it has to have been added already. No line-cutting ๐Ÿ™…โ€โ™€๏ธ

hasChild(childID)

Returns True if the job with the given ID is a child of the described job ๐Ÿซถ

Parameters

  • childID (str)

Return type

  • bool

hasFollowOn(followOnID)

Tests if the job with the given ID is a follow-on of the described job ๐Ÿ”

Parameters

  • followOnID (str)

Return type

  • bool

hasServiceHostJob(serviceID)

Tests if the ServiceHostJob is a service of the described job ๐Ÿง

Return type

  • bool

renameReferences(renames)

Applies the given dict of ID renames to all references to jobs ๐Ÿ”

Okay but it does not touch our own ID or the IDs of finished predecessors, so those stay exactly as they are ๐Ÿ™…โ€โ™€๏ธ and any IDs that aren't in the renames dict also get left alone ๐ŸŒท

Parameters

  • renames (dict[TemporaryID, str]) โ€” the rename operations to apply ๐Ÿ’–

Return type

  • None

addPredecessor()

Lets the JobDescription know that a predecessor has been added to its Job ๐Ÿงฉ

Return type

  • None

onRegistration(jobStore)

Does setup work that needs the JobStore โœจ It gets called by the Job saving logic once this JobDescription meets the JobStore and has its ID assigned.

This is also the method you override when you need setup (like hooking up flag files for service jobs) that depends on the JobStore ๐Ÿšฉ

Parameters

  • jobStore (AbstractJobStore) โ€” the job store we are being placed into ๐Ÿ 

Return type

  • None

setupJobAfterFailure(exit_status=None, exit_reason=None)

Configures the job after a failure ๐Ÿค• It reduces remainingTryCount if it's greater than zero, and sets the memory to be at least as big as the default memory, since running out of memory is super common ๐Ÿ’€

This one needs a configuration to already be assigned, so check out toil.job.Requirer.assignConfig() first ๐Ÿšจ

Parameters

  • exit_status (int | None) โ€” the exit code from the job ๐Ÿ”ข
  • exit_reason (BatchJobExitReason | None) โ€” the reason the job stopped, if the batch system can tell us ๐Ÿ“‹

Return type

  • None

getLogFileHandle(jobStore)

Creates a context manager that yields a file handle to the log file ๐Ÿ“œ It assumes logJobStoreFileID is set.

remainingTryCount (property)

Gets the number of tries remaining โณ You get the try count that's set on the JobDescription, or the default based on the retry count from the config if none is set.

clearRemainingTryCount()

Clears remainingTryCount and resets it back to its default value ๐Ÿงฝ

Return type

  • bool

It returns True if a modification to the JobDescription was made, and False otherwise ๐Ÿ’…

reserve_versions(count)

Reserves a job version number for later, so it can be journaled asynchronously ๐Ÿ“š

Parameters

  • count (int)

Return type

  • None

pre_update_hook()

Runs before a created or updated version of this job gets pickled and saved ๐Ÿ’พ It's called by the job store.

Return type

  • None

โœจ JOB.RUNNER API โœจ

okay so the Runner is literally the bestie who sets up and kicks off your whole Toil run ๐Ÿ’… it has every method you need to get things configured and started ๐Ÿš€

๐Ÿ’– class Job.Runner ๐Ÿ’–

Used to set up and run a Toil workflow. โœจ

๐ŸŽ€ getDefaultArgumentParser() ๐ŸŽ€

static getDefaultArgumentParser(jobstore_as_flag=False)

This gives you an argument parser with all the Toil workflow options already baked in ๐Ÿ“ ngl this is the Right Way to grab an argument parser in a Toil Python workflow ๐Ÿ‘‘

Parameters

  • jobstore_as_flag (bool) โ€” makes the job store option a --jobStore flag instead of a required jobStore positional argument ๐Ÿฆ‹

Return type

  • ArgumentParser

Returns

  • the argument parser a Toil workflow uses, with the Toil options added on top โœจ

๐ŸŒธ getDefaultOptions() ๐ŸŒธ

static getDefaultOptions(jobStore=None, jobstore_as_flag=False)

Gets the default options for a Toil workflow, so you don't have to start from scratch ๐Ÿ’œ

Parameters

  • jobStore (str | PathLike[str] | None) โ€” a string describing the job store for the workflow ๐Ÿงš
  • jobstore_as_flag (bool) โ€” makes the job store option a --jobStore flag instead of a required jobStore positional argument ๐Ÿฆ‹

Return type

  • Namespace

Returns

  • the options a Toil workflow uses ๐Ÿ’…

๐Ÿฆ‹ addToilOptions() ๐Ÿฆ‹

static addToilOptions(parser, jobstore_as_flag=False)

This adds the default Toil options to an optparse or argparse parser object ๐ŸŒˆ

โš ๏ธ Heads up bestie: you should probably use getDefaultArgumentParser() instead, since it makes a parser of the correct class so Toil's config file and environment variables actually work. If the parser you pass here is just an argparse.ArgumentParser and not a configargparse.ArgParser, Toil's config file and environment variables will not be respected ๐Ÿ’€

Parameters

  • parser (OptionParser | ArgumentParser) โ€” the options object you want to add Toil options to ๐Ÿซถ
  • jobstore_as_flag (bool) โ€” makes the job store option a --jobStore flag instead of a required jobStore positional argument ๐Ÿฆ‹

Return type

  • None

๐Ÿ”ฅ startToil() ๐Ÿ”ฅ

static startToil(job, options)
๐Ÿšจ Deprecated! This has been deprecated by toil.common.Toil.start, so use that one instead ๐Ÿ™ˆ

This runs the Toil workflow using the given options. The options are built with getDefaultOptions and addToilOptions, and the workflow starts with this job โœจ

Parameters

  • job (Job) โ€” the root job of the workflow ๐Ÿ‘‘

Raises

  • toil.exceptions.FailedJobsException if, at the end of the function, there are still failed jobs ๐Ÿ˜ญ

Return type

  • Any

Returns

  • the return value of the root job's run function ๐ŸŽ€

โœจ JOB.FILESTORE API โœจ

okay the AbstractFileStore is basically an abstraction of a Toil run's shared storage, and it's giving organized ๐Ÿ—‚๏ธ๐Ÿ’–

๐Ÿงš class toil.fileStores.abstractFileStore.AbstractFileStore ๐Ÿงš

class toil.fileStores.abstractFileStore.AbstractFileStore(jobStore, jobDesc, file_store_dir, waitForPreviousCommit)

This is the interface that lets user code run by Toil read and write files ๐Ÿ“‚ It also gives that code access to other Toil facilities, including:

  • normal (non-real-time) logging ๐Ÿ“
  • finding the correct temporary directory for scratch work ๐Ÿงน
  • importing and exporting files into and out of the workflow ๐Ÿ“ฆ

It stores user files in the jobStore, but keeps them separate from the actual jobs ๐Ÿฆ‹ It may implement caching ๐ŸŒˆ

It gets passed as an argument to the toil.job.Job.run() method ๐Ÿ’…

๐Ÿ”’ Careful! Access to files is only permitted inside the context manager provided by toil.fileStores.abstractFileStore.AbstractFileStore.open(). Anything outside that is a no-go ๐Ÿ™…โ€โ™€๏ธ

It's also responsible for committing completed jobs back to the job store with an update operation, and it lets that commit operation be waited for โณ

Parameters

  • jobStore (AbstractJobStore)
  • jobDesc (JobDescription)
  • file_store_dir (str)
  • waitForPreviousCommit (Callable[[], Any])

๐ŸŽ€ __init__() ๐ŸŽ€

__init__(jobStore, jobDesc, file_store_dir, waitForPreviousCommit)

This creates a brand new file store object ๐ŸŒธ

Parameters

  • jobStore (AbstractJobStore) โ€” the job store in use for the current Toil run ๐Ÿ 
  • jobDesc (JobDescription) โ€” the JobDescription object for the currently running job ๐ŸŽฏ
  • file_store_dir (str) โ€” the per-worker local temporary directory where the file store should keep local files. The file store creates per-job directories under here ๐Ÿ—ƒ๏ธ
  • waitForPreviousCommit (Callable[[], Any]) โ€” the waitForCommit method of the previous job's file store, for when jobs run in sequence on the same worker. It stops this file store's startCommit and the previous job's startCommit from running at the same time and racing. If they did race, the later job could be fully marked as completed in the job store before the earlier one ๐Ÿ˜ฑ

Return type

  • None

๐ŸŒˆ createFileStore() ๐ŸŒˆ

static createFileStore(jobStore, jobDesc, file_store_dir, waitForPreviousCommit, caching)

This creates a concrete FileStore ๐Ÿ’–

Parameters

  • jobStore (AbstractJobStore)
  • jobDesc (JobDescription)
  • file_store_dir (str)
  • waitForPreviousCommit (Callable[[], Any])
  • caching (bool | None)

Return type

  • NonCachingFileStore | CachingFileStore

๐Ÿ’œ shutdownFileStore() ๐Ÿ’œ

static shutdownFileStore(workflowID, config_work_dir, config_coordination_dir)

This does any filestore-specific cleanup that's needed ๐Ÿงฝ

๐Ÿ’€ Destructive operation! This is a destructive operation, so it's super important that no other running processes on the system are modifying or using the file store for this workflow. Otherwise, it's a whole mess ๐Ÿ˜ญ

This is meant to be the last call to the file store in a Toil run. The batch system cleanup function calls it when the batch system shuts down ๐ŸŒ™

Parameters

  • workflowID (str) โ€” the workflow ID for this invocation of the workflow ๐Ÿ†”
  • config_work_dir (str | None) โ€” the path to the work directory in the Toil Config ๐Ÿ—‚๏ธ
  • config_coordination_dir (str | None) โ€” the path to the coordination directory in the Toil Config ๐Ÿ“‚โœจ

Return type: None ๐ŸŒธ


โœจ open(job) ๐Ÿงš

Okay so this is the context manager that wraps around a job, handling the stuff that happens right before and right after it runs ๐ŸŽ€

Heads up, bestie: file operations are ONLY allowed inside the context manager ๐Ÿ™…โ€โ™€๏ธ

Implementations must only yield from within with super().open(job):. ๐Ÿ’…

Parameters

  • job (Job) โ€” the Toil job instance that's about to run ๐Ÿ’œ

Return type: Generator[None, None, None]


๐Ÿ’– get_disk_usage()

This gives you the number of bytes of disk used by the last job that ran under open() ๐Ÿ“Š

Disk usage gets measured at the very end of the job. TODO: sample periodically and record peak usage ๐Ÿ‘€

Return type: int | None


๐Ÿฆ‹ getLocalTempDir()

Get a brand new local temporary directory to dump your files into ๐Ÿ—‚๏ธ

It only sticks around for the duration of the job, lowkey a temporary era ๐ŸŒท

Return type: str

Returns: the absolute path to a new local temporary directory. It exists for the duration of the job only, and it's guaranteed to get deleted once the job terminates, along with every file inside it, recursively ๐Ÿงนโœจ


๐ŸŒˆ getLocalTempFile(suffix=None, prefix=None)

Get a new local temporary file that persists for the duration of the job ๐Ÿ“„

Parameters

  • suffix (str | None) โ€” if it's not None, the file name ends with this string. Otherwise, the default ".tmp" is used ๐Ÿ“
  • prefix (str | None) โ€” if it's not None, the file name starts with this string. Otherwise, the default "tmp" is used ๐Ÿงš

Return type: str

Returns: the absolute path to a local temporary file. It exists for the duration of the job only, and is guaranteed to be deleted once the job terminates ๐Ÿ’…


๐Ÿ”ฅ getLocalTempFileName(suffix=None, prefix=None)

Get a valid name for a new local file, but don't actually create anything at that path ๐Ÿ™ˆ

Parameters

  • suffix (str | None) โ€” if it's not None, the file name ends with this string. Otherwise, the default ".tmp" is used ๐Ÿ“
  • prefix (str | None) โ€” if it's not None, the file name starts with this string. Otherwise, the default "tmp" is used ๐Ÿงš

Return type: str

Returns: the path to a valid file ๐Ÿซถ


๐Ÿ‘‘ abstractmethod writeGlobalFile(localFileName, cleanup=False)

Upload a file (given as a path) to the job store ๐Ÿš€

If the file lives in a FileStore-managed temporary directory (the kind you get from toil.fileStores.abstractFileStore.AbstractFileStore.getLocalTempDir()), it becomes a local copy of the file. That copy is eligible for deletion by toil.fileStores.abstractFileStore.AbstractFileStore.deleteLocalFile() ๐Ÿงผ

If you upload an executable file from the local filesystem, its executability is preserved when it gets downloaded again. Main character energy ๐ŸŽ€โšก

Parameters

  • localFileName (str) โ€” the path to the local file you want to upload. The last path component (the basename of the file) stays associated with the file in the file store, if the backing JobStore supports it. That way the file can be searched for by name or name glob ๐Ÿ”
  • cleanup (bool) โ€” if True, the copy of the global file gets deleted once the job and all its successors have finished running. If not, the global file has to be deleted manually, so don't forget ๐Ÿ˜ญ

Return type: FileID (toil.fileStores.FileID)

Returns: an ID you can use to retrieve the file ๐ŸŽŸ๏ธ


๐Ÿ’œ writeGlobalFileStream(cleanup=False, basename=None, encoding=None, errors=None)

This is basically writeGlobalFile, but it lets you write a stream straight into the job store ๐ŸŒŠ The yielded file handle doesn't need to be closed explicitly, and you should not close it explicitly ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • encoding (str | None) โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which means binary mode ๐Ÿ”ข
  • errors (str | None) โ€” how encoding errors get handled. Errors are the same as for open(). Defaults to 'strict' when an encoding is specified โš ๏ธ
  • cleanup (bool) โ€” works the same as in toil.fileStores.abstractFileStore.AbstractFileStore.writeGlobalFile() ๐Ÿงน
  • basename (str | None) โ€” if the backing JobStore supports it, this basename gets used so that when you search the job store with a query matching that basename, the file will be detected ๐Ÿ”Ž

Return type: Iterator[tuple[WriteWatchingStream, FileID]]

Returns: a context manager that yields a tuple of 1) a file handle you can write to, and 2) the toil.fileStores.FileID of the resulting file in the job store ๐Ÿฆ‹


๐Ÿงš logAccess(fileStoreID, destination=None)

Record that the given file was read by the job ๐Ÿ“ (to be announced if the job fails ๐Ÿ“ฃ)

If destination is not None, it gives the path the file was downloaded to. Otherwise, it assumes the file was streamed ๐ŸŒธ

Must be called by the readGlobalFile() and readGlobalFileStream() implementations. No skipping this step, periodt ๐Ÿ’…

Parameters

  • fileStoreID (FileID | str)
  • destination (str | None)

Return type: None ๐Ÿ’…

๐Ÿฆ‹ readGlobalFile

abstractmethod readGlobalFile(fileStoreID, userPath=None,
cache=True, mutable=False, symlink=False)

Okay so this one is how you make a file from the job store show up locally. ๐Ÿซถ It's giving "I need that file on my machine, now."

If mutable is True, you get a local copy, so the original stays untouched and doesn't change the file for other jobs. โœจ If mutable is False, Toil can make a link to the file instead, which saves disk space. ๐Ÿ’พ The downloaded file is executable only if it was originally uploaded from an executable file on the local filesystem. ๐Ÿ”ฅ

If you give a userPath, that's where the file goes. If you don't, it lands in the local temp directory with an encoded name. ๐Ÿงš

โš ๏ธ Don't delete the destination file yourself! ๐Ÿ’€ Only deleteLocalFile is allowed to remove it.

Implementations must call logAccess() to report the download. ๐Ÿ“

Parameters

  • fileStoreID (str) โ€” the job store id for the file ๐Ÿ†”
  • userPath (str | None) โ€” the path and name where the global file gets copied or hard-linked (see above) ๐Ÿ“
  • cache (bool) โ€” described in toil.fileStores.CachingFileStore.readGlobalFile() ๐Ÿง 
  • mutable (bool) โ€” also described in toil.fileStores.CachingFileStore.readGlobalFile() ๐Ÿชž
  • symlink (bool) โ€” True if the caller can take a symlink, False if it can only take a normal file or a hardlink ๐Ÿ”—

Return type

str

Returns

An absolute path to a local, temporary copy of the file keyed by fileStoreID. ๐ŸŒธ

๐ŸŒˆ readGlobalFileStream

abstractmethod readGlobalFileStream(fileStoreID, encoding=None,
errors=None)

This is basically readGlobalFile's chill cousin: it reads a stream straight from the job store. ๐ŸŽ€

The file handle you get back doesn't need to be closed, and you should not close it yourself. ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • encoding (str | None) โ€” the name of the encoding used to decode the file. The encodings are the same as for decode(). It defaults to None, which means binary mode. ๐Ÿ”ค
  • errors (str | None) โ€” an optional string that says how encoding errors get handled. These work the same as for open(). If you specify an encoding, it defaults to 'strict'. ๐Ÿšจ
  • fileStoreID (str) ๐Ÿ†”

Return type

ContextManager[IO[bytes] | IO[str], bool | None]

Implementations must call logAccess() to report the download. ๐Ÿ“

Return type

ContextManager[IO[bytes] | IO[str], bool | None]

Returns

A context manager that yields a file handle you can read from. ๐Ÿ“–

Parameters

  • fileStoreID (str) ๐Ÿ†”
  • encoding (str | None) ๐Ÿ”ค
  • errors (str | None) ๐Ÿšจ

๐Ÿ“ getGlobalFileSize

getGlobalFileSize(fileStoreID)

This one gets the size of the file behind the given ID, in bytes. ๐Ÿงฎ

If it's a FileID or anything else with a non-None size field, Toil just uses that. โšก

Otherwise, it asks the job store to poll the file's size. ๐Ÿ•ต๏ธโ€โ™€๏ธ

Heads up: the job store might overestimate the size. This can happen if the file is encrypted and had an IV or other encryption framing added. ๐Ÿ”

Parameters

  • fileStoreID (FileID | str) โ€” the File ID for the file ๐Ÿ†”

Return type

int

Returns

The file's size in bytes, as stored in the job store. ๐Ÿ’œ

๐Ÿ—‘๏ธ deleteLocalFile

abstractmethod deleteLocalFile(fileStoreID)

This deletes the local copies of files linked to the job store ID you pass in. ๐Ÿงน

If no such local copies exist, it raises an OSError with an errno of errno.ENOENT. ๐Ÿ’€ That means you can't call it several times in a row. ๐Ÿ™ˆ

The files it deletes are all of these:

  • Everything the current job read from this file ID with readGlobalFile into the job's file-store-provided temp directory. ๐Ÿ“‚
  • The file that was written to create the given file ID, if the current job wrote it from the job's file-store-provided temp directory. โœ๏ธ

Parameters

  • fileStoreID (FileID | str) โ€” the File Store ID of the file to be deleted ๐Ÿ—‘๏ธ

Return type

None

๐Ÿ’ฅ deleteGlobalFile

abstractmethod deleteGlobalFile(fileStoreID)

This one deletes the local files and then permanently removes them from the job store. ๐Ÿ˜ค

To keep the job restartable if it needs to be, the delete doesn't happen until after the job's run method has finished. ๐Ÿ”

Parameters

  • fileStoreID (FileID | str) โ€” the File Store ID of the file to be deleted ๐Ÿ†”

Return type

None

๐Ÿ“ฃ log_to_leader

log_to_leader(text, level=20)

This sends a logging message to the leader. ๐Ÿ“จ The worker logs the same message at the same level too. ๐Ÿชต

It doesn't depend on the commit system, so it's safe to use during an asynchronous commit, or when there's no commit afterward. ๐Ÿซง

Parameters

  • text (str) โ€” the string to log โœ๏ธ
  • level (int) โ€” the logging level ๐Ÿ“ถ

Return type

None

๐ŸŒŠ log_user_stream

log_user_stream(name, stream)

This sends a stream of UTF-8 text to the leader as a named log stream. ๐ŸŒธ

It's super useful for things like the error logs of Docker containers. ๐Ÿณ The leader either shows it to the user or organizes it nicely for user-level log info. ๐Ÿ‘‘

Parameters

  • name (str) โ€” a hierarchical, .-delimited string ๐ŸŒณ
  • stream (IO[bytes]) โ€” a stream of encoded text. Encoding errors are tolerated, so it won't crash over them. ๐Ÿซถ

Return type: None ยท /usr/share/doc/python3/html/library/constants.html#None ๐Ÿ’…

abstractmethod startCommit(jobState=False) ๐Ÿ”ฅ Okay bestie, this one updates the job's status on disk โœจ It's allowed to bump the job's version number, and it may kick off an asynchronous process. If it does, call waitForCommit() to wait on that process. You must waitForCommit() before committing any more updates to the job, no cap ๐Ÿšจ While the async process is running, it's totally safe to modify the job, but anything you change after this call won't get committed until the next call ๐Ÿซถ

Parameters

  • jobState (bool ยท /usr/share/doc/python3/html/library/functions.html#bool) โ€” If True, it commits the state of the FileStore's job and file deletes. Otherwise, it only commits file creates and updates ๐ŸŒธ

Return type: None ยท /usr/share/doc/python3/html/library/constants.html#None

abstractmethod waitForCommit() โณ This one blocks while startCommit is running, so it's giving patience. The job's successor calls it to make sure it doesn't start touching the job store until this job is finished ๐Ÿฆ‹ It might get called even when startCommit was never called on that particular instance, and in that case it just doesn't block. Chill ๐Ÿ˜Œ

Return type: bool ยท /usr/share/doc/python3/html/library/functions.html#bool

Returns: Always returns True โœ…

abstractmethod classmethod shutdown(shutdown_info) ๐ŸŒ™ Shuts down the filestore on this node. It's meant to be called on batch system shutdown, so it's the closing ceremony ๐Ÿ‘‘

Parameters

  • shutdown_info (Any ยท /usr/share/doc/python3/html/library/typing.html#typing.Any) โ€” The implementation-specific shutdown info, used for shutting down the file store and removing all its state and all job local temp directories from the node ๐Ÿงน

Return type: None ยท /usr/share/doc/python3/html/library/constants.html#None


๐Ÿงš class toil.fileStores.FileID(fileStoreID, size, executable=False)

A small wrapper around Python's builtin string class, and honestly it's iconic ๐Ÿ’– It represents a file's ID in the file store and has a size attribute, which is the file's size in bytes. This object gets returned by importFile and writeGlobalFile ๐ŸŽ€

Calls into the file store can use bare strings too. If the size isn't in the ID, it gets queried from the job store, so you're covered either way ๐Ÿซถ

Parameters

  • fileStoreID (str ยท /usr/share/doc/python3/html/library/stdtypes.html#str)
  • size (int ยท /usr/share/doc/python3/html/library/functions.html#int)
  • executable (bool ยท /usr/share/doc/python3/html/library/functions.html#bool)
  • args (Any ยท /usr/share/doc/python3/html/library/typing.html#typing.Any)
  • kwargs (dict ยท /usr/share/doc/python3/html/library/stdtypes.html#dict[str ยท /usr/share/doc/python3/html/library/stdtypes.html#str, Any ยท /usr/share/doc/python3/html/library/typing.html#typing.Any])

Return type: FileID ยท #toil.fileStores.FileID

__init__(fileStoreID, size, executable=False) ๐ŸŒท

Parameters

  • fileStoreID (str ยท /usr/share/doc/python3/html/library/stdtypes.html#str)
  • size (int ยท /usr/share/doc/python3/html/library/functions.html#int)
  • executable (bool ยท /usr/share/doc/python3/html/library/functions.html#bool)

Return type: None

pack() ๐Ÿ“ฆ Packs the FileID into a string so it can be passed through external code. Slay ๐Ÿ’…

Return type: str ยท /usr/share/doc/python3/html/library/stdtypes.html#str

classmethod unpack(packedFileStoreID) ๐Ÿ”“ Unpacks the result of pack() back into a FileID object. It's the undo button, basically ๐Ÿฆ‹

Parameters

  • packedFileStoreID (str ยท /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: FileID ยท #toil.fileStores.FileID


โœจ BATCH SYSTEM API โœจ

Okay so the batch system interface is how Toil stays flexible about where jobs run ๐ŸŒˆ It abstracts over different ways of running batches of jobs, like on Slurm clusters, Kubernetes clusters, or a single node. The toil.batchSystems.abstractBatchSystem.AbstractBatchSystem API gets implemented to run jobs using a given job management system, and that's the main character ๐Ÿ‘‘

๐Ÿ“ Batch System Environment Variables

Environment variables let you pass scheduler-specific parameters along. It's giving customization ๐Ÿ’œ

SLURM has two environment variables. The first one applies to all jobs, and the second one defines the partition to use for parallel jobs ๐ŸŒธ

export TOIL_SLURM_ARGS="-t 1:00:00 -q fatq"
export TOIL_SLURM_PE='multicore'

TORQUE also has two. One is for everything except the resource requirements, and the other is for the resource requirements themselves, written without the -l prefix ๐ŸŽ€

export TOIL_TORQUE_ARGS="-q fatq"
export TOIL_TORQUE_REQS="walltime=1:00:00"

GridEngine (SGE, UGE) needs one more environment variable to define the parallel environment (see http://www.softpanorama.org/HPC/Grid_engine/parallel_environment.shtml#Important_details) for running multicore jobs ๐Ÿ”ฅ

export TOIL_GRIDENGINE_PE='smp'
export TOIL_GRIDENGINE_ARGS='-q batch.q'

HTCondor lets you include extra parameters in the submit file that gets passed to condor_submit ๐Ÿงš

export TOIL_HTCONDOR_PARAMS='requirements = TARGET.has_sse4_2 == true; accounting_group = test'
The environment variable is parsed as a semicolon-separated string of parameter = value pairs. Get the semicolons right or it won't parse, bestie ๐Ÿ™ˆ

๐Ÿฆ‹ Batch System API

๐Ÿ’– class toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

This is an abstract base class that represents the interface the batch system has to provide to Toil. Basically it's the contract โœจ

abstractmethod classmethod supportsAutoDeployment() ๐Ÿš€ Tells you whether the batch system supports auto-deployment of the user script itself. If it does, setUserScript() can be invoked to set the resource object representing the user script ๐Ÿซถ

Note to implementors: If your implementation returns True here, it should also overrideโ€ฆ and then the sentence just stops there ๐Ÿ™ˆ

Return type: bool ยท /usr/share/doc/python3/html/library/functions.html#bool

abstractmethod classmethod supportsWorkerCleanup() ๐Ÿงน Tells you whether the batch system supports worker cleanup. It indicates whether the batch system invokes BatchSystemSupport.workerCleanup() (#toil.batchSystems.abstractBatchSystem.BatchSystemSupport.workerCleanup) after the last job for a particular workflow invocation finishes ๐Ÿ’…

Quick vibe check on terms: "worker" means an entire node, not just a worker process. A worker process can run more than one job sequentially, and more than one concurrent worker process can exist on a worker node for the same workflow. The batch system is said to shut down after the last worker process terminates ๐Ÿ‘‘

Return type: bool ยท /usr/share/doc/python3/html/library/functions.html#bool

setUserScript(userScript) ๐Ÿ“œ Sets the user script for this workflow. This method must be called before the first job is issued to this batch system, and only if supportsAutoDeployment() (#toil.batchSystems.abstractBatchSystem.AbstractBatchSystem.supportsAutoDeployment) returns True. Otherwise it will raise an exception ๐Ÿ’€

Parameters

  • userScript (Resource ยท #toil.resource.Resource) โ€” The resource object representing the user script or module, plus the modules it depends on ๐ŸŒˆ

Return type: None ยท /usr/share/doc/python3/html/library/constants.html#None

set_message_bus(message_bus) ๐Ÿ“ฃ Gives the batch system a chance to connect directly to the message bus. That way it can send informational messages about the jobs it's running to other Toil components. Communication is caring ๐Ÿซถ

Parameters

  • message_bus (MessageBus ยท #toil.bus.MessageBus)

Return type: None ยท /usr/share/doc/python3/html/library/constants.html#None

abstractmethod issueBatchJob(command, job_desc, job_environment=None) ๐Ÿš€ Issues a job with the specified command to the batch system and returns a unique job ID number. Iconic behavior, honestly ๐Ÿ‘‘

Parameters

  • command (str ยท /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the command to execute somewhere to run the Toil worker process
  • job_desc (JobDescription ยท #toil.job.JobDescription) โ€” the JobDescription for the job being run
  • job_environment (dict ยท /usr/share/doc/python3/html/library/stdtypes.html#dict[str ยท /usr/share/doc/python3/html/library/stdtypes.html#str, str ยท /usr/share/doc/python3/html/library/stdtypes.html#str] | None ยท /usr/share/doc/python3/html/library/constants.html#None) โ€” a collection of job-specific environment variables to be set on the worker ๐ŸŒธ

Return type: int ยท /usr/share/doc/python3/html/library/functions.html#int

Returns: you get back a unique job ID number ๐ŸŽ€ that you can use to reference the newly issued job later. Literally your receipt, bestie ๐Ÿงพโœจ

๐Ÿ’… killBatchJobs(jobIDs)

abstractmethod killBatchJobs(jobIDs) is an abstract method, so every batch system has to write its own version ๐Ÿซถ

Okay so this one kills the given job IDs ๐Ÿ’€. Once it returns, the killed jobs won't show up in getRunningBatchJobIDs anymore, and they won't come back from getUpdatedBatchJob either ๐Ÿ™ˆ

  • Parameters
    • jobIDs (list[int], docs: /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/functions.html#int), the list of IDs of the jobs you want gone ๐Ÿ—‘๏ธ
  • Return type: None (/usr/share/doc/python3/html/library/constants.html#None), nothing to see here ๐Ÿ’…

๐Ÿ”ฎ getIssuedBatchJobIDs()

abstractmethod getIssuedBatchJobIDs() is the "show me everything" method ๐Ÿ‘€

It gets all the jobs that are currently issued, meaning the ones that are running right now or just waiting for their turn โณ

  • Return type: list[int] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/functions.html#int)
  • Returns: a list of issued jobs, given as job ID numbers. They may be running, or they may be waiting to be run. The list is technically a list, but please don't depend on the ordering ๐Ÿ™…โ€โ™€๏ธ

๐Ÿƒโ€โ™€๏ธ getRunningBatchJobIDs()

abstractmethod getRunningBatchJobIDs() is the actually running right now check. Waiting doesn't count here, bestie ๐Ÿšซโณ

It gives you a map of job ID numbers for jobs that are running at this moment, along with how long each one has been running in seconds โฑ๏ธ

  • Return type: dict[int, float] (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/functions.html#float)
  • Returns: a dictionary where the keys are running job ID numbers and the values are how many seconds each one has been running ๐ŸŒธ

๐Ÿฆ‹ getUpdatedBatchJob(maxWait)

abstractmethod getUpdatedBatchJob(maxWait) is the one that tells you which jobs have finished (ceased running, either successfully or with an error) ๐ŸŽ‰ Each job only gets returned exactly once, so don't expect a second look ๐Ÿซ 

Jobs killed by killBatchJobs won't be reported here. Heads up though: those can make it return None earlier than maxWait ๐Ÿ‘€

  • Parameters
    • maxWait (int, docs: /usr/share/doc/python3/html/library/functions.html#int), the number of seconds it's allowed to block while it waits for a result โฒ๏ธ
  • Return type: UpdatedBatchJobInfo <#toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo> | None (docs: /usr/share/doc/python3/html/library/constants.html#None)
  • Returns: if there's a result, you get an UpdatedBatchJobInfo. If there isn't, you get None ๐Ÿซถ
    • wallTime is how many seconds of wall-clock time the job ran for. It's always a strictly positive float. If the batch system doesn't track wall time, it's None instead โŒš

๐Ÿ“ข getSchedulingStatusMessage()

getSchedulingStatusMessage() is the gossip button ๐Ÿ—ฃ๏ธ It gets a log message fragment for the user about anything that might be going wrong in the batch system, but only if there's something useful to say.

If there's nothing useful, it returns None ๐Ÿ™ƒ It can also tell you what resource is the limiting factor when jobs are being scheduled. If the leader thinks the workflow is stuck, this message can be shown to the user so they can figure out why it's stuck ๐Ÿ”

  • Return type: str | None (docs: /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/constants.html#None)
  • Returns: a user-directed message about the scheduling state ๐Ÿ’ฌ

๐Ÿ›‘ shutdown()

abstractmethod shutdown() gets called when a toil invocation wraps up ๐ŸŽฌ It should cleanly terminate all the worker threads, so nothing gets left hanging ๐Ÿงต

  • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)

๐ŸŒˆ setEnv(name, value=None)

setEnv(name, value=None) lets you set an environment variable for the worker process before it launches ๐Ÿš€

Workers usually inherit the environment of whatever machine they're running on. This method lets you override specific variables in that inherited environment before the worker starts. Note that this is a different mechanism from the one the worker uses internally to set up the environment of a job, so don't mix them up ๐Ÿ™…โ€โ™€๏ธ

A call to this method affects all jobs issued after it returns. Note to implementors: that means you'll usually need to copy the variables before enqueuing a job ๐Ÿ“‹

If you don't give a value, it gets looked up from the current environment ๐Ÿ‘€

  • Parameters
    • name (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
    • value (str | None, docs: /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/constants.html#None)
  • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)

๐ŸŽ€ add_options(parser)

classmethod add_options(parser) is for batch systems that come with their own command line options ๐Ÿ› ๏ธ If yours does, it adds them to the parser you give it.

  • Parameters
    • parser (ArgumentParser | _ArgumentGroup, docs: /usr/share/doc/python3/html/library/argparse.html#argparse.ArgumentParser)
  • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)

โš™๏ธ setOptions(setOption)

classmethod setOptions(setOption) processes the command line or configuration options that are relevant to this batch system ๐Ÿงฉ

  • Parameters
    • setOption (OptionSetter <#toil.batchSystems.options.OptionSetter>), a function with the signature setOption(option_name, parsing_function=None, check_function=None, default=None, env=None). It returns nothing and updates the run configuration as a side effect โœจ
  • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)

๐Ÿงš getWorkerContexts()

getWorkerContexts() gets a list of picklable context manager objects that wrap the worker's work, in order ๐ŸŽ

These let the Toil worker do things in-process, like configuring environment variables, hot-deploying user scripts, or cleaning up a node. Without them, you'd need a wrapping "executor" process to handle that ๐Ÿ™Œ

  • Return type: list[ContextManager[Any, bool | None]] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/typing.html#typing.ContextManager, /usr/share/doc/python3/html/library/typing.html#typing.Any, /usr/share/doc/python3/html/library/functions.html#bool, /usr/share/doc/python3/html/library/constants.html#None)

โœจ JOB.SERVICE API โœจ

okay bestie, the Service class is how you spawn databases and servers inside a Toil workflow ๐Ÿ’พ๐Ÿฆ‹ it's literally giving main character energy.

๐Ÿ’– class Job.Service

class Job.Service(memory=None, cores=None, disk=None, accelerators=None, preemptible=None, unitName='')

Abstract class used to define the interface to a service. You have to subclass it yourself to actually define your services ๐Ÿ’…

It's not executed as a job. It runs inside a ServiceHostJob instead ๐Ÿงš

๐ŸŒธ Parameters

  • memory (str | int | None)
  • cores (str | int | float | None)
  • disk (str | int | None)
  • accelerators (str | int | Mapping[str, Any] | AcceleratorRequirement | Sequence[str | int | Mapping[str, Any] | AcceleratorRequirement] | None)
  • preemptible (str | int | bool | None)
  • unitName (str | None)

๐ŸŽ€ __init__

__init__(memory=None, cores=None, disk=None, accelerators=None, preemptible=None, unitName='')

Memory, core and disk requirements are specified exactly the same way as in toil.job.Job.__init__() ๐Ÿซถ

๐ŸŒธ Parameters

  • memory (str | int | None)
  • cores (str | int | float | None)
  • disk (str | int | None)
  • accelerators (str | int | Mapping[str, Any] | AcceleratorRequirement | Sequence[str | int | Mapping[str, Any] | AcceleratorRequirement] | None)
  • preemptible (str | int | bool | None)
  • unitName (str | None)

Return type: None

๐Ÿ”ฅ abstractmethod start(job)

Start the service.

๐ŸŒธ Parameters

  • job (ServiceHostJob) โ€” the underlying host job the service is running in. You can use it to register deferred functions, or to get at the fileStore for creating temporary files โœจ

Return type: Any

๐Ÿ’œ Returns

An object describing how to access the service. It has to be pickleable, because jobs use it to reach the service (see toil.job.Job.addService()) ๐Ÿฆ‹

๐Ÿ”ฅ abstractmethod stop(job)

Stops the service. The function can block until it's complete. ๐Ÿ›‘

๐ŸŒธ Parameters

  • job (ServiceHostJob) โ€” the same underlying host job as above, again usable for deferred functions or the fileStore ๐Ÿ’–

Return type: None

๐ŸŒˆ check()

Checks that the service is still running. ๐Ÿ‘€

๐Ÿ’€ Raises

  • exceptions.RuntimeError โ€” if the service failed, the service job gets labeled failed ๐Ÿ˜ญ

Return type: bool

๐Ÿ’œ Returns

True if the service is still running, otherwise False. If it returns False, the service job gets terminated and counts as a success ๐ŸŽ‰

โš ๏ธ Important point: if the service job exits because of a failure, it should raise a RuntimeError, not return False! Returning False means "all good, shut it down," so a failure dressed up as False will be treated as a success ๐Ÿ’€

โœจ EXCEPTIONS API โœจ

okay so this section is all about the Toil-specific exceptions ๐Ÿ’… these are the custom errors Toil throws when something goes sideways, so you can catch them by name. no cap, super useful ๐Ÿซถ


๐Ÿงจ toil.job.JobException

exception toil.job.JobException(message)

this is the general job exception ๐Ÿ’– basically the catch-all for when a job goes wrong.

๐Ÿ› ๏ธ __init__(message)

__init__(message)
  • message (str)

Return type: None


๐ŸŒ€ toil.job.JobGraphDeadlockException

exception toil.job.JobGraphDeadlockException(string)

bestie, this one gets raised when your workflow has an unresolvable dependency, like a cycle ๐Ÿ”„ it's giving stuck forever energy. go peep toil.job.Job.checkJobGraphForDeadlocks() for more on that.

๐Ÿ› ๏ธ __init__(string)

__init__(string)

๐Ÿ“ toil.jobStores.abstractJobStore.ConcurrentFileModificationException

exception toil.jobStores.abstractJobStore.ConcurrentFileModificationException(jobStoreFileID)

this one shows up when multiple processes try to modify the same file at once ๐Ÿ˜ญ two cooks in one kitchen, and the file is paying the price.

  • jobStoreFileID (FileID | str)

๐Ÿ› ๏ธ __init__(jobStoreFileID)

__init__(jobStoreFileID)
  • jobStoreFileID (FileID | str) โ€” the ID of the file that got modified by multiple workers or processes concurrently

๐Ÿ  toil.jobStores.abstractJobStore.JobStoreExistsException

exception toil.jobStores.abstractJobStore.JobStoreExistsException(locator, prefix)

this just means the job store you asked for already exists ๐Ÿ™…โ€โ™€๏ธ it's already living its best life there.

  • locator (str)
  • prefix (str)

๐Ÿ› ๏ธ __init__(locator, prefix)

__init__(locator, prefix)
  • locator (str) โ€” the location of the job store
  • locator
  • prefix (str)

๐Ÿ‘ป toil.jobStores.abstractJobStore.NoSuchFileException

exception toil.jobStores.abstractJobStore.NoSuchFileException(jobStoreFileID, customName=None, *extra)

this one means the file does not exist ๐Ÿ‘ป we were SURE it was there. the vibes are gone.

  • jobStoreFileID (FileID | str)
  • customName (str | None)
  • extra (Any)

๐Ÿ› ๏ธ __init__(jobStoreFileID, customName=None, *extra)

__init__(jobStoreFileID, customName=None, *extra)
  • jobStoreFileID (FileID | str) โ€” the ID of the file that we wrongly assumed was there
  • customName (str | None) โ€” optionally, an alternate name for the file that isn't there
  • extra (Any) โ€” optional extra info to tack onto the error message
  • extra

๐Ÿ” toil.jobStores.abstractJobStore.NoSuchJobException

exception toil.jobStores.abstractJobStore.NoSuchJobException(jobStoreID)

this means the job you're looking for does not exist ๐Ÿซ  it ghosted you.

  • jobStoreID (FileID | str)

๐Ÿ› ๏ธ __init__(jobStoreID)

__init__(jobStoreID)
  • jobStoreID (FileID | str) โ€” the jobStoreID that we mistakenly assumed was real
  • jobStoreID

๐Ÿšซ toil.jobStores.abstractJobStore.NoSuchJobStoreException

exception toil.jobStores.abstractJobStore.NoSuchJobStoreException(locator, prefix)

this one means the job store does not exist at all ๐Ÿš๏ธ there's nothing at that address, bestie.

  • locator (str)
  • prefix (str)

๐Ÿ› ๏ธ __init__(locator, prefix)

__init__(locator, prefix)
  • locator (str) โ€” the location of the job store
  • prefix (str) โ€” the type of job store
  • locator
  • prefix

โœจ RUNNING TESTS โœจ

Okay bestie, you run Toil's tests with make targets, like $ make <target> ๐Ÿ’… Which ones actually do stuff depends on which environment variables you've set (more on that in Running Integration Tests) ๐Ÿงช

  • test โ€” invokes all the tests ๐Ÿ’–
  • integration_test โ€” invokes only the integration tests ๐Ÿ”—
  • test_offline โ€” skips building the Docker appliance and only invokes tests with no Docker dependencies ๐Ÿฆ‹
  • integration_test_local โ€” makes integration tests way easier to debug locally ๐Ÿ” It runs them serially and doesn't redirect output, so everything shows up on your terminal like it should โœจ

Before you run tests for the first time, set up your virtual environment by following the steps in Installing Plugins (see buildfromsource) ๐ŸŒธ

Run all tests, slow ones included:

$ make test

Run only the quick tests (as of Jul 25, 2018, this was ~ 20 minutes) โฐ:

$ export TOIL_TEST_QUICK=True; make test

Run an individual test with:

$ make test tests=src/toil/test/sort/sortTest.py::SortTest::testSort

The default value for tests is "src", which includes all tests in the src/ subdirectory of the project root. Tests that need a particular feature get skipped implicitly ๐Ÿ™ˆ If you want to explicitly skip tests that depend on a feature that's currently installed, use:

$ make test tests="-m 'not aws' src"

This runs only the tests that don't depend on the aws extra, even if that extra is currently installed. Note the difference between a feature and an extra ๐Ÿงš Every extra is a feature, but some features aren't extras, like the gridengine feature. To skip tests involving both the gridengine feature and the aws extra, use the following:

$ make test tests="-m 'not aws and not gridengine' src"

๐Ÿ Running Tests with pytest

Honestly, it's often simpler to just use pytest directly instead of the make wrapper ๐Ÿ’œ This usually works as expected, but some tests need a little manual prep. To run a specific test with pytest, use the following:

python3 -m pytest src/toil/test/sort/sortTest.py::SortTest::testSort

For more info, check out the pytest documentation at https://docs.pytest.org/en/latest/ ๐Ÿ“š

๐ŸŽ๏ธ Running Integration Tests

These tests usually only run in our CI workflow because of their resource requirements and cost ๐Ÿ’ธ But you can make them available for local testing:

  • Tests that use Docker (like the autoscaling tests and the Docker tests) need an appliance image to be hosted ๐Ÿณ First, make sure you've gone through the setup in Using Docker with Quay. Then build and host the appliance image by running the make target push_docker:
$ make push_docker
  • Integration tests need to be activated with an environment variable, plus you have to export info relevant to the tests you want to run ๐Ÿ”“ Enable them with:
$ export TOIL_TEST_INTEGRATIVE=True
  • Last step: set the environment variables for your keyname and desired zone ๐Ÿ—๏ธ
$ export TOIL_X_KEYNAME=[Your Keyname]
$ export TOIL_X_ZONE=[Desired Zone]

Where X is one of our currently supported cloud providers (GCE, AWS) ๐ŸŒˆ

  • Check the sections above for guidance on running tests ๐Ÿซถ

๐ŸŒˆ Test Environment Variables

Here's the cast of test environment variables, bestie ๐Ÿ‘‘

  • TOIL_TEST_TEMP โ€” an absolute path to a directory where Toil tests write their temporary files ๐Ÿ“ If you don't set it, it defaults to the system's standard temporary directory (see https://docs.python.org/2/library/tempfile.html#tempfile.gettempdir).
  • TOIL_TEST_INTEGRATIVE โ€” if True, this lets the integration tests run ๐Ÿƒโ€โ™€๏ธ It's only valid when running the tests from the source directory via make test or make test_parallel.
  • TOIL_AWS_KEYNAME โ€” an AWS keyname (see Preparing your AWS environment, prepareaws) ๐Ÿ”‘ It's required to run the AWS tests.
  • TOIL_GOOGLE_PROJECTID โ€” a Google Cloud account projectID (see Running in Google Compute Engine (GCE), runninggce) โ˜๏ธ It's required to run the Google Cloud tests.
  • TOIL_TEST_QUICK โ€” if True, long-running tests get skipped ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

Partial install and failing tests

Heads up: some tests may fail with an ImportError if the required extras aren't installed ๐Ÿ˜ญ Install Toil with all of the extras to prevent those errors.

๐Ÿณ Using Docker with Quay

Some of the tests need Docker ๐Ÿ‹ Follow the installation instructions for your system on the Docker website (https://www.docker.com/products/docker) to get started.

When you run make test, you might still get this error:

$ make test
Please set TOIL_DOCKER_REGISTRY, e.g. to quay.io/USER.

To fix it, make an account with Quay (https://quay.io/) and specify it like so, where USER is your Quay username:

$ TOIL_DOCKER_REGISTRY=quay.io/USER make test

Pro move: you can add this variable to your bashrc by running:

$ echo 'export TOIL_DOCKER_REGISTRY=quay.io/USER' >> $HOME/.bashrc

๐Ÿ“ Running Mesos Tests

If you're running Toil's Mesos tests, be sure to create the virtualenv with --system-site-packages so it includes the Mesos Python bindings ๐Ÿฅน Verify this by activating the virtualenv and running pip list | grep mesos. On macOS, that may come up empty. To fix it, run the following:

for i in /usr/local/lib/python2.7/site-packages/*mesos*; do ln -snf $i venv/lib/python2.7/site-packages/; done

โœจ DEVELOPING WITH DOCKER โœจ

okay so if you're building features that rely on the Toil Appliance (that's the docker image toil uses for AWS autoscaling) ๐Ÿณ, bestie, you should lowkey set up a personal registry on Quay https://quay.io/ or Docker Hub https://hub.docker.com/ ๐Ÿ’…. Here's the tea: Toil Appliance images are tagged with the Git commit they're based on, and only commits on our master branch trigger an appliance build on Quay. So the second you make a commit or dirty your working copy, Toil can't automatically find the right Toil Appliance image anymore ๐Ÿ˜ญ. If you want to test appliance changes in autoscaling, you need to build and push your own appliance image to a personal Docker registry. The next section walks you through it ๐Ÿฆ‹.

Making Your Own Toil Docker Image

Note! Toil checks if the docker image specified by TOIL_APPLIANCE_SELF exists before launching, using the docker v2 schema. This should work for any major docker repository, but you can override this check with --forceDockerAppliance if you want ๐Ÿ™ˆ.

Here's a general workflow (similar instructions apply when using Docker Hub) ๐ŸŒธ:

  1. Make some changes to the provisioner of your local version of Toil โœจ
  2. Go to the location where you installed the Toil source code and run
$ make docker

This automatically builds a docker image that's ready to upload to your personal Quay https://quay.io/ account. On Docker Desktop, containerd may have to be enabled https://docs.docker.com/desktop/containerd/#enable-the-containerd-image-store. If you haven't installed the Toil source code yet, check out Installing Plugins #buildfromsource.

  1. You'll need Docker installed and need to log into Quay https://docs.quay.io/solution/getting-started.html if you haven't already. Also make sure your Quay account is public ๐ŸŽ€.
  2. Set the environment variable TOIL_DOCKER_REGISTRY to your Quay account. If you find yourself doing this a lot, you might want to add
export TOIL_DOCKER_REGISTRY=quay.io/<MY_QUAY_USERNAME>

to your .bashrc or equivalent ๐Ÿ’œ.

  1. Now run
$ make push_docker

which uploads the docker image to your Quay account. Take note of the image's tag for the next step ๐Ÿท๏ธ.

  1. Finally, tell Toil where to pull the Appliance image you just created (it uses the Toil release you have installed by default). To do this, set the environment variable TOIL_APPLIANCE_SELF to the url of your image. For more info, see Environment Variables #envars.
  2. Now you can launch your cluster! For more information, see Running a Workflow with Autoscaling #autoscaling ๐Ÿš€.

Running a Cluster Locally

The Toil Appliance container is also super useful as a test environment, since it can simulate a Toil cluster locally ๐Ÿงš. An important caveat: autoscaling only works on an EC2 instance and cannot (at this time) run on a local machine ๐Ÿ’€.

To spin up a local cluster, start by using this Docker run command to launch a Toil leader container:

docker run \
    --entrypoint=mesos-master \
    --net=host \
    -d \
    --name=leader \
    --volume=/home/jobStoreParentDir:/jobStoreParentDir \
    quay.io/ucsc_cgl/toil:3.6.0 \
    --registry=in_memory \
    --ip=127.0.0.1 \
    --port=5050 \
    --allocation_interval=500ms

A couple notes on this one: the -d flag tells Docker to run in daemon mode, so the container runs in the background ๐ŸŒ™. To check that the container is running, run docker ps to see all containers. If you want to run your own container instead of the official UCSC container, just swap quay.io/ucsc_cgl/toil:3.6.0 for your own container name ๐Ÿซถ.

Also, we're not mounting the job store directory itself, but rather the location where the job store will be written. Due to complications with running Docker on MacOS, I recommend only mounting directories within your home directory ๐Ÿ“. The next command launches the Toil worker container with similar parameters:

docker run \
    --entrypoint=mesos-slave \
    --net=host \
    -d \
    --name=worker \
    --volume=/home/jobStoreParentDir:/jobStoreParentDir \
    quay.io/ucsc_cgl/toil:3.6.0 \
    --work_dir=/var/lib/mesos \
    --master=127.0.0.1:5050 \
    --ip=127.0.0.1 \
    โ€”-attributes=preemptable:False \
    --resources=cpus:2

Here we're specifying 2 CPUs and a non-preemptable worker. You can easily change either or both of these in a logical way โญ. To change the number of cores, swap the 2 for whatever number you like. To make the worker preemptable, change preemptable:False to preemptable:True. Also, the same volume is mounted into the worker. This is needed since both the leader and worker read and write to the job store ๐Ÿ‘‘.

Now that your cluster is running, you can run

docker exec -it leader bash

to get a shell in your leader "node" ๐Ÿ’…. You can also replace the leader parameter with worker to get shell access on your worker.

Docker-in-Docker issues

If you want to run Docker inside this Docker cluster (dockerized tools, perhaps), you should also mount in the Docker socket via -v /var/run/docker.sock:/var/run/docker.sock. This gives the Docker client inside the Toil Appliance access to the Docker engine on the host ๐Ÿ”ฅ. Client/engine version mismatches have been known to cause issues, so we recommend using Docker version 1.12.3 on the host to match the Docker client installed in the Appliance.

Finally, be careful where you write files inside the Toil Appliance ๐Ÿ˜ฌ. "Child" Docker containers launched in the Appliance will actually be siblings to the Appliance, since the Docker engine lives on the host. This means the child container can only mount in files from the Appliance if those files are in a directory that was originally mounted into the Appliance from the host. That way, the files are accessible to the sibling container. Note: if Docker can't find the file or directory on the host, it will silently fail and mount in an empty directory.

Enabling FUSE

When running toil-wdl-runner with Singularity, Singularity decompresses images to sandbox directories by default. This can take a while if a workflow has lots of images ๐Ÿข. To avoid this, you can give the Docker container access to FUSE at startup. There are 2 main ways to do this. You can either run all the Docker containers in privileged mode:

docker run \
    -d \
    --name=toil_leader \
    --privileged \
    quay.io/ucsc_cgl/toil:6.2.0

Or pass the /dev/fuse device node through into the container:

docker run \
    -d \
    --name=toil_leader \
    --device=/dev/fuse \
    quay.io/ucsc_cgl/toil:6.2.0

toil-wdl-runner will handle the logic from there ๐Ÿงšโ€โ™€๏ธ.

โœจ MAINTAINER'S GUIDELINES โœจ

In general, as developers and maintainers of the code, we follow these guidelines ๐ŸŽ€:

  • We strive to never break the build on master. All development should happen on branches, either in the main Toil repository or in developers' forks.
  • Pull requests should be used for any and all changes (except truly trivial ones) ๐Ÿ’–.
  • Pull requests should be in response to issues. If you find yourself making a pull request without an issue, create the issue first ๐Ÿ™ˆ.

Naming Conventions

  • Commit messages should be great https://chris.beams.io/posts/git-commit/#seven-rules. Most importantly, they must:
    • Have a short subject line. If you need more space, drop down two lines and write a body explaining what is changing and why it has to change.
    • Write the subject line as a command: Destroy all humans, not All humans destroyed.
    • Reference the issue being fixed in a Github-parseable format, such as (resolves #1234) at the end of the subject line, or This will fix #1234. somewhere in the body. If no single commit on its own fixes the issue, the cross-reference must appear in the pull request title or body instead ๐Ÿ”ฅ.
  • Branches in the main Toil repository must start with issues/, followed by the issue number (or numbers, separated by a dash), followed by a short, lowercase, hyphenated description of the change. (There can be many open pull requests with their branches at any given time, and this convention keeps branches easy to identify ๐Ÿฆ‹.)

Say there's an issue numbered #123 titled Foo does not work. The branch name would be issues/123-fix-foo, and the commit title would be Fix foo in case of bar (resolves #123) ๐Ÿ’….

Pull Requests

  • All pull requests must be reviewed by a person other than the request's author. Review the PR by following the Reviewing Pull Requests #reviewingprs checklist ๐Ÿ‘‘.
  • Modified pull requests must be re-reviewed before merging. Note that Github does not enforce this! ๐Ÿ˜ญ
  • Merge pull requests by following the Merging Pull Requests #mergingprs checklist โœจ.
  • When merging a pull request, make sure to update the Draft Changelog https://github.com/DataBiosphere/toil/wiki/Draft-Changelog on the Github wiki. We use it to produce the changelog for the next release. The PR template tells you to do this, so don't forget ๐ŸŒˆ. New entries go at the bottom.
  • Pull requests won't be merged unless CI tests pass. Gitlab tests only run on code in the main Toil repository on some branch, so it's the responsibility of the approving reviewer to make sure pull requests from outside repositories are copied to branches in the main repository. This can be done with (from a Toil clone):
./contrib/admin/test-pr theirusername their-branch issues/123-fix-description-here

You have to repeat this every time the PR submitter updates their PR, after checking that the update is not malicious ๐Ÿซถ.

If there's no issue corresponding to the PR (the branch gets named after it), the reviewer should first create the issue ๐Ÿ™ˆ.

Developers who have push access to the main Toil repository are encouraged to make their pull requests from within the repository, so they can skip this step ๐Ÿงš.

  • ๐Ÿ’… okay bestie, when you merge a PR into master, lowkey always pick "Squash and marge" ๐Ÿ”ฅ especially when the PR is one single unit of work. If you rewrote the PR from scratch with all the fixes baked in, it would be exactly one commit โœจ. That keeps the commit history on master super readable and way easier to debug if something breaks ๐Ÿซถ
  • When you squash a PR with multiple authors, please add Co-authored-by <https://github.blog/2018-01-29-commit-together-with-co-authors/> so everyone gets their credit ๐Ÿ’–
  • See Issue #2816 <https://github.com/DataBiosphere/toil/issues/2816> for more deets ๐Ÿฆ‹

๐Ÿ’… Publishing a Release ๐Ÿ’…

okay so here's how you publish a Toil release, step by step ๐Ÿ‘‘

  • Figure out the release version X.Y.Z ๐ŸŽ€ It should follow semantic versioning <https://semver.org/>. If user-workflow-breaking changes are made, X gets incremented, and Y and Z go back to zero ๐Ÿ’€ If non-breaking changes are made but new functionality is added, X stays the same as the last release, Y gets incremented, and Z goes back to zero. If only patches are released, X and Y stay the same as the last release and Z gets incremented ๐ŸŒธ
  • If it doesn't exist already, make a release branch in the Toil repo named X.Y.x, where x is a literal lower-case "x" ๐Ÿงš For patch releases, find the existing branch and make sure it's up to date with the patch commits that are going out. They can be cherry-picked over <https://trunkbaseddevelopment.com/branch-for-release/> from master ๐Ÿซถ
  • On the release branch, edit version_template.py in the root of the repository. Find the line that looks like this (slightly different for patch releases):
baseVersion = 'X.Y.0a1'

Make it look like this instead:

baseVersion = 'X.Y.Z'
  • Commit your change to the branch โœจ
  • Tag the current state of the release branch as releases/X.Y.Z ๐Ÿท๏ธ
  • Make the Github release here <https://github.com/DataBiosphere/toil/releases/new>, referencing that tag ๐ŸŽ€ For a non-patch release, fill in the description with the changelog from the wiki page <https://github.com/DataBiosphere/toil/wiki/Draft-Changelog>, which you should clear afterwards ๐Ÿงน For a patch release, just describe the patch ๐Ÿ’…
  • For a non-patch release, set up the main branch so development builds declare themselves as alpha versions of what the next release will probably be ๐Ÿฆ‹ Edit version_template.py in the root of the repository on the main branch to set baseVersion like this:
baseVersion = 'X.Y+1.0a1'

Make sure to replace X and Y+1 with actual numbers ๐Ÿ”ข

๐ŸŒˆ Using Git Hooks ๐ŸŒˆ

in the contrib/hooks directory, there are two scripts, mypy-after-commit.py and mypy-before-push.py ๐Ÿงš They can be set up as Git hooks so you don't accidentally push commits that would immediately fail type-checking. They're supposed to eliminate the need to run make mypy constantly ๐Ÿ™ˆ You can install them into your Git working copy like this:

ln -rs ./contrib/hooks/mypy-after-commit.py .git/hooks/post-commit
ln -rs ./contrib/hooks/mypy-before-push.py .git/hooks/pre-push

After you make a commit, the post-commit script starts type-checking it, and if that takes too long it re-launches the process in the background โณ When you push, the pre-push script checks whether the commit you're pushing type-checked successfully. If it hasn't been type-checked but is currently checked out, it gets type-checked then โœจ If type-checking fails, the push is aborted ๐Ÿ›‘

Type-checking only happens if you're in a Toil development virtual environment. If you aren't, the scripts won't do anything ๐Ÿซ 

To bypass or override the pre-push hook (if it's wrong, or if you need to push something that doesn't typecheck), you can run git push --no-verify ๐Ÿ™…โ€โ™€๏ธ If the scripts get confused about whether a commit actually typechecks, you can clear out the type-checking result cache. It lives in /var/run/user/<your UID>/.mypy_toil_result_cache on Linux and in .mypy_toil_result_cache in the Toil repo on Mac ๐Ÿ—‘๏ธ

To uninstall the scripts, delete .git/hooks/post-commit and .git/hooks/pre-push ๐Ÿ‘‹

๐ŸŽ€ Adding Retries to a Function ๐ŸŽ€

see toil.lib.retry <https://github.com/DataBiosphere/toil/blob/master/src/toil/lib/retry.py> ๐Ÿ’–

retry() can decorate any function, based on the list of errors you want it to retry on ๐Ÿ”

That list of errors can contain normal Exception objects, and/or RetryCondition objects wrapping Exceptions to include extra conditions ๐Ÿง 

For example, retrying on one Exception (HTTPError):

from requests import get
from requests.exceptions import HTTPError

@retry(errors=[HTTPError])
def update_my_wallpaper():
    return get('https://www.deviantart.com/')

Or:

from requests import get
from requests.exceptions import HTTPError

@retry(errors=[HTTPError, ValueError])
def update_my_wallpaper():
    return get('https://www.deviantart.com/')

The examples above retry for the default interval on any errors listed in the errors= arg list ๐ŸŒธ

To retry on specifically 500/502/503/504 errors, you can specify an ErrorCondition object instead, like this:

from requests import get
from requests.exceptions import HTTPError

@retry(errors=[
    ErrorCondition(
               error=HTTPError,
               error_codes=[500, 502, 503, 504]
           )])
def update_my_wallpaper():
    return requests.get('https://www.deviantart.com/')

To retry on specifically errors containing the phrase "NotFound":

from requests import get
from requests.exceptions import HTTPError

@retry(errors=[
    ErrorCondition(
        error=HTTPError,
        error_message_must_include="NotFound"
    )])
def update_my_wallpaper():
    return requests.get('https://www.deviantart.com/')

To retry on all HTTPError errors EXCEPT an HTTPError containing the phrase "NotFound":

from requests import get
from requests.exceptions import HTTPError

@retry(errors=[
    HTTPError,
    ErrorCondition(
               error=HTTPError,
               error_message_must_include="NotFound",
               retry_on_this_condition=False
           )])
def update_my_wallpaper():
    return requests.get('https://www.deviantart.com/')

To retry on boto3's specific status errors, an example of the implementation is:

import boto3
from botocore.exceptions import ClientError

@retry(errors=[
    ErrorCondition(
               error=ClientError,
               boto_error_codes=["BucketNotFound"]
           )])
def boto_bucket(bucket_name):
    boto_session = boto3.session.Session()
    s3_resource = boto_session.resource('s3')
    return s3_resource.Bucket(bucket_name)

Any combination of these works too, as long as the codes are matched to the correct exceptions ๐Ÿง A ValueError will not return a 404, for example ๐Ÿ™…โ€โ™€๏ธ

The retry function as a decorator makes retrying functions way easier and clearer ๐Ÿฅฐ It also encourages smaller, independent functions, instead of lumping a bunch of different things that might need different retry conditions into one function ๐Ÿ‘‘

The ErrorCondition object does a lot of the heavy lifting for you ๐Ÿ’ช It boils writing specific retry conditions down to an API that covers all the common use-cases, so you never have to write any new bespoke functions ๐Ÿซถ

Use-cases covered currently:

  1. Retrying on a normal error, like a KeyError.
  2. Retrying on HTTP error codes (use ErrorCondition).
  3. Retrying on boto's specific status errors, like "BucketNotFound" (use ErrorCondition).
  4. Retrying when an error message contains a certain phrase (use ErrorCondition).
  5. Explicitly NOT retrying on a condition (use ErrorCondition).

If you need new functionality, the best practice in Toil right now is to add it to the ErrorCondition itself, rather than making a brand new custom retry method ๐ŸŒˆโœจ

โœจ PULL REQUEST CHECKLISTS โœจ

okay so this section is basically your PR cheat sheet, bestie ๐Ÿ’… it's got checklists for dealing with PRs. for the general PR stuff, go check out Pull Requests (#prs) ๐Ÿฆ‹

๐Ÿ‘€ Reviewing Pull Requests ๐Ÿ‘€

this checklist has to stay in sync with the checklist in the pull request template ๐Ÿซถ

when you're reviewing a PR, do the following:

  • Check where it's coming from. Make sure it's coming from issues/XXXX-fix-the-thing in the Toil repo, or from an external repo.
    • If it's from an external repo, pull it in for CI with:
contrib/admin/test-pr otheruser theirbranchname issues/XXXX-fix-the-thing
  • Read through the code changes. Make sure it doesn't have:
    • Addition of trailing whitespace. ๐Ÿ™ˆ
    • New variable or member names in camelCase that want to be in snake_case. ๐Ÿ
    • New functions without type hints (https://docs.python.org/3/library/typing.html).
    • New functions or classes without informative docstrings.
    • Changes to semantics that aren't reflected in the relevant docstrings.
    • New or changed command line options for Toil workflows that aren't reflected in docs/running/cliOptions.rst.
    • New features without tests. ๐Ÿ˜ญ
  • Leave comments. Comment on the lines of code where problems exist with a review comment. You can shift-click the line numbers in the diff to select multiple lines โœจ
  • Wrap it up. Finish the review with an overall description of your opinion ๐Ÿ‘‘

๐ŸŽ€ Merging Pull Requests ๐ŸŽ€

this checklist has to stay in sync with the checklist in the pull request template too, so no skipping ๐Ÿ’–

when you're merging a PR, do the following:

  • Check the tests. Make sure the PR passed tests, including the Gitlab tests, for the most recent commit in its branch. ๐Ÿงช
  • Check the review. Make sure the PR has been reviewed. If not, review it. If it has been reviewed and any requested changes seem to have been addressed, proceed ๐Ÿฆ‹
  • Squash and merge. Merge with the Github "Squash and merge" feature ๐Ÿซง
  • Copy the changelog entry. Copy its recommended changelog entry to the Draft Changelog (https://github.com/DataBiosphere/toil/wiki/Draft-Changelog) ๐Ÿ“‹
  • Tag it. Append the issue number in parentheses to the changelog entry ๐Ÿ”ฅ

๐Ÿ—๏ธ TOIL ARCHITECTURE ๐Ÿ—๏ธ

okay this diagram is the whole vibe of how Toil is built, so let's look at it together ๐ŸŒˆ it lays out the software architecture of Toil.

[image: Toil's architecture is composed of the leader, the job store, the worker processes, the batch system, the node provisioner, and the stats and logging monitor.]

Figure 1: The basic components of Toil's architecture. ๐Ÿ–ผ๏ธ

these are the components, and here's the tea on each one โ˜•

  • the leader ๐Ÿ‘‘ โ€” the leader is responsible for deciding which jobs should be run. to do this it traverses the job graph. right now it's a single threaded process, but we take aggressive steps to keep it from becoming a bottleneck (see Read-only Leader described below) ๐Ÿ’ช
  • the job-store ๐Ÿ—„๏ธ โ€” handles all the files shared between the components. files in the job-store are the means by which the state of the workflow is maintained. each job is backed by a file in the job store, and atomic updates to this state are used to make sure the workflow can always be resumed upon failure. the job-store can also store all user files, so they can be shared between jobs. it's defined by the AbstractJobStore class (toil.jobStores.abstractJobStore.AbstractJobStore). multiple implementations of this class let Toil support different back-end file stores, e.g.: S3, network file systems, Google file store, etc. โ˜๏ธ
  • workers ๐Ÿ โ€” the workers are temporary processes responsible for running jobs, one at a time per worker. each worker process is invoked with a job argument that it's responsible for running. the worker monitors this job and reports back success or failure to the leader by editing the job's state in the file-store. if the job defines successor jobs, the worker may choose to run them immediately (see Job Chaining below) โšก
  • the batch-system ๐Ÿšฆ โ€” responsible for scheduling the jobs given to it by the leader, running a worker command for each job. it's defined by the AbstractBatchSystem class (toil.batchSystems.abstractBatchSystem.AbstractBatchSystem). Toil uses multiple existing batch systems to schedule jobs, including Apache Mesos, GridEngine, and a multi-process single node implementation that lets workflows run without any of these frameworks. so Toil can therefore fairly easily be made to run a workflow using an existing cluster ๐Ÿซถ
  • the node provisioner ๐Ÿญ โ€” creates the worker nodes that the batch system schedules workers onto. it's defined by the AbstractProvisioner class (toil.provisioners.abstractProvisioner.AbstractProvisioner).
  • the statistics and logging monitor ๐Ÿ“Š โ€” monitors the logging and statistics produced by the workers and reports them. it uses the job-store to gather this information ๐Ÿง

๐Ÿงฉ Jobs and JobDescriptions ๐Ÿงฉ

okay so as noted in Job Basics (#jobbasics), a job is the atomic unit of work in a Toil workflow โœจ workflows extend the Job class (toil.job.Job) to define units of work. these jobs get pickled and stored in the job-store by the leader, and the worker retrieves and un-pickles them when they're scheduled to run.

during scheduling, Toil doesn't work with the actual Job objects. instead, JobDescription objects (toil.job.JobDescription) are used to store all the information that the Toil leader ever needs to know about the job. this includes requirements information, dependency information, the body object to run, the worker command to issue, etc. ๐Ÿ’…

internally, the JobDescription object is referenced by its jobStoreID, which is often not human readable. however, the Job and JobDescription objects contain several human-readable names that are super useful for logging and identification ๐Ÿฆ‹

  • jobName ๐Ÿท๏ธ โ€” the name of the kind of job this is. this may be used in job store IDs and logging. it's also used to let the cluster scaler learn a model for how long the job will take. defaults to the job class's name if no real user-defined name is available.
    • for a FunctionWrappingJob (toil.job.FunctionWrappingJob), the jobName is replaced by the wrapped function's name.
    • for a CWL workflow, the jobName is the class name of the internal job that's running the CWL workflow, such as "CWLJob".
  • unitName ๐ŸŽ€ โ€” the name of this particular instance of this kind of job. if the user sets it, it will appear with the jobName in logging.
    • for a CWL workflow, the unitName is the dotted path from the workflow down to the task being run, including numbers for scatter steps.
  • displayName ๐Ÿ’– โ€” a human-readable name to identify this particular job instance. it's used as an identifier of the job class in the stats report. defaults to the job class's name if no real user-defined name is available.
    • for CWL workflows, this includes the jobName and the unitName. main character energy ๐Ÿ‘‘

๐Ÿ“Š Statistics and Logging ๐Ÿ“Š

okay so the stats and logging system is a whole vibe ๐Ÿ’… It's one joint class called StatsAndLogging (toil.statsAndLogging.StatsAndLogging) ๐ŸŽ€ You can instantiate it and run it as a thread on the leader, where it keeps polling the job store for new log files with read_logs() ๐Ÿ‘€ Those log files are JSON, so they hold structured data ๐Ÿงš

Structured log messages from user Python code get stored under workers.logs_to_leader. They come from the file store's log_to_leader() method and get logged at the appropriate level ๐Ÿ’– The text the worker captured for all its chained jobs (that's logs.messages) gets logged at debug level in the worker's output ๐ŸŒธ And if --writeLogs or --writeLogsGzip is provided, the StatsAndLogging thread also saves the received worker logs into per-job files inside the job store using writeLogFiles() ๐Ÿฆ‹

Ngl, the worker only fills that in when debug logging is on, or when --writeLogsFromAllJobs is set. Otherwise, logs from successful jobs just aren't persisted ๐Ÿ’€ Logs from failed jobs are handled differently. They get written to the file store, and the log file is available through toil.job.JobDescription.getLogFileHandle(). The leader thread grabs those and calls back into StatsAndLogging to print them or save them locally, whichever is appropriate โœจ

The CWL and WDL interpreters use log_user_stream() to inject their task-level logs into the stats and logging system ๐ŸŽ€ The full text of those logs lands in the JSON stats files, and when the StatsAndLogging thread spots them, it reports and saves them, kind of like how it handles regular Toil job logs ๐Ÿซถ

To pass the stats and the non-failed-job logs around, the job store has a logs mailbox system ๐Ÿ“ฌ write_logs() drops in a string, and read_logs() on the leader hands those strings to a callback. The mailbox tracks new versus old based on whether anyone has read a string yet, so you can read only the new values or every value it's observed ๐Ÿ‘‘ The stats and logging system uses this to move around structured JSON that holds both log data and worker-measured stats. It expects StatsAndLogging to be the only live reader ๐Ÿ”ฅ


โšก Optimizations โšก

Toil has a bunch of optimizations built for scalability, and here are some of the key ones ๐Ÿ’…

๐Ÿ‘‘ Read-only leader

The leader process is a single thread for now ๐Ÿงต Most of its job is processing the state of jobs, and each job is stored as a file in the job-store ๐Ÿ“ To keep that one thread from getting overloaded, each worker does as much as it can to manage the state of the job it's running ๐Ÿ’ช So, with a couple of minor exceptions, the leader never needs to write or update a job's state in the job-store ๐Ÿ™ˆ

For example, when a job is complete and has no further successors, the responsible worker deletes the job from the job-store to mark it complete โœ… The leader then only has to check whether the file exists when it gets a signal from the batch-system that the job is done ๐Ÿซถ This off-loading of state management is orthogonal to any future parallelization of the leader ๐ŸŒˆ

๐Ÿ”— Job chaining

The worker helps schedule successor jobs too, so the leader has fewer individual jobs to process ๐Ÿงš Right now it's pretty simple. If there is a single next successor job to run, and its resources fit within the resources of the current job and closely match them, then that job runs immediately on the worker without going back to the leader โšก

More extensions of this strategy are possible. For lots of workflows that define a series of serial successors (e.g. map sequencing reads, post-process mapped reads, etc.), this pattern is super effective at reducing leader workload ๐Ÿ˜ค

๐Ÿซง Preemptable node support

Running at large scale means dealing with intermittent node failures ๐Ÿฅน So Toil is designed to always be resumable, as long as the job-store doesn't become corrupt ๐Ÿ›Ÿ That robustness is what lets Toil run on preemptible nodes, which are only available when others aren't willing to pay more to use them ๐Ÿ’ธ

Designing workflows that divide into many short individual jobs that can use preemptable nodes lets them be scheduled and executed efficiently ๐Ÿฆ‹

๐Ÿ—„๏ธ Caching

Running bioinformatic pipelines often means passing large datasets between jobs ๐Ÿงฌ Toil caches the results from jobs, so child jobs running on the same node can directly use the same file objects ๐ŸŽ€ That eliminates the need for an intermediary transfer to the job store ๐Ÿƒโ€โ™€๏ธ Caching also takes pressure off local disks, because multiple jobs can share a single file ๐Ÿ’ฟ The drop in I/O lets pipelines run faster, and by sharing files, users can run more jobs in parallel since overall disk requirements go down ๐Ÿš€

To demonstrate how efficient caching is, we ran an experimental internal pipeline on 3 samples from the TCGA Lung Squamous Carcinoma (LUSC) dataset ๐Ÿ”ฌ The pipeline takes the tumor and normal exome fastqs, plus the tumor rna fastq and input, and predicts MHC presented neoepitopes in the patient that are potential targets for T-cell based immunotherapies ๐Ÿ’– It was run on each sample individually on c3.8xlarge machines on AWS (60GB RAM, 600GB SSD storage, 32 cores) ๐Ÿ–ฅ๏ธ The pipeline aligns the data to hg19-based references, predicts MHC haplotypes using PHLAT, calls mutations using 2 callers (MuTect and RADIA), and annotates them using SnpEff. Then it predicts MHC:peptide binding using the IEDB suite of tools, before running an in-house rank boosting algorithm on the final calls ๐Ÿงช

To optimize time, the pipeline is written so mutations are called on a per-chromosome basis from the whole-exome bams and merged into a complete vcf ๐Ÿงฉ Running mutect in parallel on whole exome bams would make each mutect job download the complete Tumor and Normal Bams to its working directory. That quickly fills the disk and limits how parallel the jobs can be ๐Ÿ˜ญ The workflow ran in Toil, with and without caching, and Figure 2 shows it finishes faster with caching while using less disk on average than the uncached run ๐Ÿ“‰ We believe the benefits of caching from file transfers will be much higher on magnetic disk-based storage systems than on the SSD systems we tested ๐Ÿ’œ

[image: Graph outlining the efficiency gain from caching.]

Figure 2: Efficiency gain from caching. The lower half of each plot describes the disk used by the pipeline, recorded every 10 minutes over the duration of the pipeline, and the upper half shows the corresponding stage of the pipeline being processed. Since jobs requesting the same file shared the same inode, the effective load on the disk is considerably lower than in the uncached case, where every job downloads a personal copy of every file it needs ๐Ÿซง In all cases, the uncached run uses almost 300-400GB more than the cached run in the resource heavy mutation calling step. We also see a benefit in wall time for each stage, since we eliminate the time taken for file transfers โฑ๏ธ


๐Ÿ“œ Toil support for Common Workflow Language ๐Ÿ“œ

The CWL document and input document get loaded using the 'cwltool.load_tool' module ๐Ÿ“œ That does normalization and URI expansion (so relative file references become absolute file URIs ๐Ÿ”—), validates the document against the CWL schema โœ…, initializes Python objects for the major document elements (command line tools, workflows, workflow steps) ๐Ÿงฑ, and performs static type checking that sources and sinks have compatible types ๐Ÿ”

Input files referenced by the CWL document and input document get imported into the Toil file store ๐Ÿ“ฅ CWL documents can use any URI scheme the Toil file store supports, including local files and object storage โ˜๏ธ

The location field of File references gets updated to reflect the import token returned by the Toil file store ๐ŸŽŸ๏ธ

For directory inputs, the directory listing is stored in a Directory object ๐Ÿ“‚ Each individual file gets imported into the Toil file store too ๐Ÿ’–

An initial workflow Job is created from the toplevel CWL document ๐ŸŒฑ Then control passes to the Toil engine, which schedules that initial workflow job to run ๐Ÿšฆ

When the toplevel workflow job runs, it traverses the CWL workflow and creates a toil job for each step ๐Ÿ‘ฃ The dependency graph is expressed by making downstream jobs children of upstream jobs, and initializing the child jobs with an input object containing the promises of output from upstream jobs ๐Ÿช„

Toil jobs have a single output, but CWL lets steps have multiple output parameters that can feed into multiple other steps ๐Ÿคฏ So the input to a CWLJob is expressed as an "indirect dictionary" ๐Ÿ“– This is a dictionary of input parameters, where each entry value is a tuple of a promise and a promise key. When the job runs, the indirect dictionary is turned into a concrete input object. Each promise gets resolved into its actual value (which is always a dict), and then the promise key is used to look up the actual value for the input parameter โœจ

If a workflow step specifies a scatter, a scatter job is created and connected into the workflow graph as described above ๐Ÿงฉ When the scatter step runs, it creates child jobs for each parameterization of the scatter. A gather job is added as a follow-on to gather the outputs into arrays ๐Ÿงบ

When running a command line tool, it first creates output and temporary directories under the Toil local temp dir ๐Ÿ—‚๏ธ It then runs the command line tool using single_job_executor from CWLTool, providing a Toil-specific constructor for filesystem access and overriding the default PathMapper to use ToilPathMapper ๐Ÿƒโ€โ™€๏ธ

The ToilPathMapper keeps track of a file's symbolic identifier (the Toil FileID), its local path on the host (the value returned by readGlobalFile), and the location of the file inside the Docker container ๐Ÿณ it's giving organized ๐Ÿ’œ

okay so once single_job_executor from CWLTool finishes doing its thing ๐Ÿ’…, Toil gets the output object and the status back. If the underlying job failed, Toil raises an exception ๐Ÿ™ˆ no sneaking past that. Then every file in the output object gets tossed into the file store with writeGlobalFile ๐Ÿ“ฆ, and the 'location' field of each File reference gets updated to match the token the Toil file store hands back โœจ.

When the whole workflow wraps up ๐ŸŽ€, it returns an indirect dictionary that links to the outputs of the job steps feeding into the final output. That's the value toil.start() or toil.restart() gives you, and you resolve it to get the final output object ๐Ÿฆ‹. The files in that object get exported from the file store to outdir on the host file system, and their 'location' fields get updated to point at the final exported spot ๐Ÿ’–.


โœจ MINIMUM AWS IAM PERMISSIONS โœจ

Toil needs at least these permissions in an IAM role to run things on a cluster ๐Ÿ”. They're added by default when you launch a cluster, BUT if you make your own custom IAM role and pass it in with --awsEc2ProfileArn when launching a cluster <#launchawsclusterdetails>, double-check they're all there ๐Ÿซถ.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:*",
                "s3:*",
                "iam:PassRole"
            ],
            "Resource": "*"
        }
    ]
}

โœจ AUTO-DEPLOYMENT โœจ

If you want to run a Toil Python workflow in a distributed environment ๐ŸŒธ, on multiple worker machines, either in the cloud or on a bare-metal cluster, the Python code has to be made available to those other machines. If the workflow's main module imports other modules, those need to be on the workers too. Toil can automatically do that for you, with a little help from you ๐Ÿซถ. We call this feature auto-deployment of a workflow.

Let's look at the different auto-deploying scenarios first. Some of them, as we'll see shortly, can't be auto-deployed ๐Ÿ’€. Last but not least, we'll deal with declaring Toil as a dependency (see #depending-on-toil) for a workflow that's packaged as a setuptools distribution ๐Ÿ“ฆ.

Toil can be easily deployed to a remote host ๐Ÿš€. First, assuming you followed our Preparing your AWS environment section (#prepareaws) to install Toil and use it to create a remote leader node on (in this example) AWS, you can log into it using the Ssh-Cluster Command (#sshcluster). Once you're on the remote host, create and activate a virtualenv (and make sure to use the --system-site-packages option!!) ๐Ÿงš:

$ virtualenv --system-site-packages venv
$ . venv/bin/activate

Note the --system-site-packages option, which makes sure globally installed packages are accessible inside the virtualenv ๐ŸŒˆ. Do not (re)install Toil after this! The --system-site-packages option has already brought over Toil and its dependencies from your local installation of Toil for you ๐Ÿ˜ญ.

From here, you can install a project and its dependencies:

$ tree
.
โ”œโ”€โ”€ util
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ sort
โ”‚       โ”œโ”€โ”€ __init__.py
โ”‚       โ””โ”€โ”€ quick.py
โ””โ”€โ”€ workflow
    โ”œโ”€โ”€ __init__.py
    โ””โ”€โ”€ main.py

3 directories, 5 files
$ pip install matplotlib
$ cp -R workflow util venv/lib/python3.9/site-packages

Ideally, your project would have a setup.py file (see setuptools http://setuptools.readthedocs.io/en/latest/index.html) which streamlines the installation process โœจ:

$ tree
.
โ”œโ”€โ”€ util
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ sort
โ”‚       โ”œโ”€โ”€ __init__.py
โ”‚       โ””โ”€โ”€ quick.py
โ”œโ”€โ”€ workflow
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ main.py
โ””โ”€โ”€ setup.py

3 directories, 6 files
$ pip install .

Or, if your project has been published to PyPI:

$ pip install my-project

In each case, we've created a virtualenv with the --system-site-packages flag in the venv subdirectory, then installed the matplotlib distribution from PyPI along with the two packages our project consists of. (Again, both Python and Toil are assumed to be present on the leader and all worker nodes ๐Ÿ’œ.)

We can now run our workflow ๐ŸŽ‰:

$ python3 main.py --batchSystem=kubernetes โ€ฆ
Important: If the workflow's external dependencies contain native code (i.e. are not pure Python), then they must be manually installed on each worker.
Warning: Neither python3 setup.py develop nor pip install -e . can be used in this process, as instead of copying the source files, they create .egg-link files that Toil can't auto-deploy. Similarly, python3 setup.py install doesn't work either, as it installs the project as a Python .egg, which is also not currently supported by Toil (though it could be https://github.com/BD2KGenomics/toil/issues/1367 in the future). Also note that using the --single-version-externally-managed flag with setup.py will prevent the installation of your package as an .egg. It will also disable the automatic installation of your project's dependencies.

โœจ Auto Deployment with Sibling Python Files โœจ

This scenario applies if a Python workflow imports files that are its siblings ๐Ÿ‘ฏ:

$ cd my_project
$ ls
userScript.py utilities.py
$ ./userScript.py --batchSystem=kubernetes โ€ฆ

Here userScript.py imports additional functionality from utilities.py. Toil detects that userScript.py has sibling Python files and copies them to the workers, right alongside the main Python file. Heads up ๐Ÿ‘€: sibling Python files get auto-deployed regardless of whether they're actually imported by the workflow. All .py files living in the same directory as the main workflow Python file will be auto-deployed automatically.

This structure is a super suitable way to organize the source code of reasonably complicated workflows ๐Ÿ“.

โœจ Auto-Deploying a Package Hierarchy โœจ

Recall that in Python, a package (https://docs.python.org/2/tutorial/modules.html#packages) is a directory containing one or more .py files, one of which must be called __init__.py, and optionally other packages. For more involved workflows with a significant amount of code, this is the recommended way to organize your source code ๐Ÿง . Because we use a package hierarchy, the main workflow file is actually a Python module. It's merely one of the modules in the package hierarchy. We need to tell Toil that we want to use a package hierarchy by invoking Python's -m option. This lets Toil identify the entire set of modules belonging to the workflow and copy all of them to each worker. Note that while using the -m option is optional in the scenarios above, it is mandatory in this one ๐Ÿšจ.

The following shell session illustrates this ๐Ÿ‘‡:

$ cd my_project
$ tree
.
โ”œโ”€โ”€ utils
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ sort
โ”‚       โ”œโ”€โ”€ __init__.py
โ”‚       โ””โ”€โ”€ quick.py
โ””โ”€โ”€ workflow
    โ”œโ”€โ”€ __init__.py
    โ””โ”€โ”€ main.py

3 directories, 5 files
$ python3 -m workflow.main --batchSystem=kubernetes โ€ฆ

Here the workflow entry point module main.py doesn't reside in the current directory. It's part of a package called util, in a subdirectory of the current directory ๐Ÿ—‚๏ธ. Additional functionality is in a separate module called util.sort.quick, which corresponds to util/sort/quick.py. Because we invoke the workflow via python3 -m workflow.main, Toil can determine the root directory of the hierarchy (my_project in this case) and copy all Python modules underneath it to each worker. The -m option is documented here (https://docs.python.org/2/using/cmdline.html#cmdoption-m) ๐Ÿ“–.

When -m is passed, Python adds the current working directory to sys.path, the list of root directories considered when resolving a module name like workflow.main. Without that added convenience, we'd have to run the workflow as PYTHONPATH="$PWD" python3 -m workflow.main. This also means Toil can detect the root directory of the invoked module's package hierarchy even if it isn't the current working directory. In other words, we could do this ๐Ÿฆ‹:

$ cd my_project
$ export PYTHONPATH="$PWD"
$ cd /some/other/dir
$ python3 -m workflow.main --batchSystem=kubernetes โ€ฆ

Also note that the root directory itself must not be a package, i.e. it must not contain an __init__.py ๐Ÿ™….

โœจ Relying on Shared Filesystems โœจ

Bare-metal clusters typically mount a shared file system like NFS on each node. If every node has that file system mounted at the same path, you can place your project on that shared filesystem and run your Python workflow from there. Additionally, you can clone the Toil source tree into a directory on that shared file system, and you won't even need to install Toil on every worker ๐Ÿ™Œ. Be sure to add both your project directory and the Toil clone to PYTHONPATH. Toil replicates PYTHONPATH from the leader to every worker ๐Ÿ’….

Using a shared filesystem: Toil currently only supports a tempdir set to a local, non-shared directory.

โœจ Toil Appliance โœจ

The term Toil Appliance refers to the Ubuntu-based Docker image that Toil uses for the machines in clusters managed by Toil, and for executing jobs on Kubernetes. It's easily deployed, only needs Docker, and allows a consistent environment on all Toil clusters ๐Ÿณ. To specify a different image, see the Toil Environment Variables section (#envars). For more information on the Toil Appliance, see the Running in AWS section (#runningaws) โ˜๏ธ.

๐ŸŒธ ENVIRONMENT VARIABLES ๐ŸŒธ

okay bestie, there are a bunch of environment variables that change how Toil runs, so let's go through them ๐Ÿ’…โœจ

  • TOIL_CHECK_ENV โ€” ๐Ÿฆ‹ this is a flag that decides whether Toil looks back at the Python virtual environment it's installed in when it builds commands that might run on other hosts. If it's set to True and Toil is installed in the current virtual environment, Toil uses absolute paths to its own executables. The catch is that the virtual environment has to live at the same path on every node ๐Ÿ‘€. If it's not set that way, internal commands like _toil_worker get resolved using the PATH on whichever node they run on. This is super useful in a shared HPC environment, where people might have their own Toil installs in virtual environments ๐Ÿซถ
  • TOIL_WORKDIR โ€” ๐ŸŽ€ this is an absolute path to the directory where Toil writes its temporary files. The directory has to exist on each worker node, and every worker can have a different value ๐ŸŒˆ The --workDir command line option beats this one. When you're using the Toil docker container (like on Kubernetes), it defaults to /var/lib/toil. With Toil autoscaling on Mesos, it's somewhere inside the Mesos sandbox. In every other case, it falls back to the system's standard temporary directory, which you can read about at https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir ๐Ÿ’œ
  • TOIL_WORKDIR_OVERRIDE โ€” ๐Ÿ‘‘ same deal as TOIL_WORKDIR, an absolute path where Toil writes its temporary files, but this one is the boss. It overrides both TOIL_WORKDIR and the --workDir command line option ๐Ÿ’–
  • TOIL_COORDINATION_DIR โ€” ๐Ÿงš an absolute path to the directory where Toil writes its lock files. It has to exist on each worker node, and it can be set to something different on each worker. The --coordinationDir command line option overrides this one ๐ŸŒธ
  • TOIL_COORDINATION_DIR_OVERRIDE โ€” ๐Ÿ”ฅ the absolute path for lock files, same as above, but it overrides both TOIL_COORDINATION_DIR and the --coordinationDir command line option. Main character energy ๐Ÿ‘‘
  • TOIL_BATCH_LOGS_DIR โ€” ๐Ÿ“ a directory where batch system logs get saved, somewhere the leader can get to them ๐Ÿซถ The --batchLogsDir option overrides this. Heads up: it only works for grid engine batch systems, which are gridengine, htcondor, torque, slurm, and lsf ๐Ÿ™ˆ
  • TOIL_HISTORY โ€” ๐Ÿ“ decides whether the Toil history database is turned on. It defaults to true โœจ
  • TOIL_JOB_HISTORY โ€” ๐Ÿฆ‹ decides whether per-job history gets recorded in the Toil history database. It defaults to false, so you have to opt in ๐Ÿ’…
  • TOIL_KUBERNETES_HOST_PATH โ€” ๐ŸŒˆ a path on the Kubernetes hosts that gets mounted as the Toil work directory inside the workers, which lets everyone share a cache ๐Ÿค If the path doesn't exist yet, it gets created for you ๐ŸŽ€
  • TOIL_KUBERNETES_OWNER โ€” ๐Ÿ’œ a name prefix that makes your Kubernetes jobs easy to spot in a crowd ๐Ÿ‘€ If you don't set it, Toil uses your current user name ๐Ÿซถ
  • TOIL_KUBERNETES_SERVICE_ACCOUNT โ€” ๐Ÿ” the service account name that gets applied when Toil creates Kubernetes pods ๐Ÿ’–

Okay so the list keeps going and it's giving even more env vars ๐Ÿ’…โœจ let's gooo bestie ๐Ÿซถ

  • TOIL_KUBERNETES_POD_TIMEOUT โ€” how many seconds Toil waits for a scheduled Kubernetes pod to actually start running โฐ๐ŸŒธ
  • TOIL_KUBERNETES_POD_SECURITY_CONTEXT โ€” point this at a YAML file that defines a pod security context, and Toil slaps it on every pod ๐Ÿ”๐Ÿ’œ
  • TOIL_KUBERNETES_SECURITY_CONTEXT โ€” same vibe, but this YAML file is a security context for all the containers instead ๐Ÿ“ฆ๐Ÿฆ‹
  • KUBE_WATCH_ENABLED โ€” a boolean that lets you use the Kubernetes watch stream feature instead of polling for running jobs. It's lowkey so much more efficient ๐Ÿ‘€๐Ÿงš The default is False, so you have to opt in.
  • TOIL_APPLIANCE_SELF โ€” the fully qualified reference for the Toil Appliance you want to use, written as REPO/IMAGE:TAG. Valid examples are quay.io/ucsc_cgl/toil:3.6.0 and cket/toil:3.5.0. Also, since Docker defaults to Dockerhub, only quay.io repos need to include their registry ๐Ÿณ๐Ÿ“
  • TOIL_DOCKER_REGISTRY โ€” the URL of the registry where your Toil Appliance image lives. Docker uses Dockerhub by default, but quay.io is also super popular, and you can get it by setting this to quay.io ๐ŸŒˆ
  • TOIL_DOCKER_NAME โ€” the name of the Toil Appliance image you want. It's usually just toil, but this option exists so you can override it, since the image can be built with totally arbitrary names ๐ŸŽ€
  • TOIL_AWS_SECRET_NAME โ€” for the Kubernetes batch system, this is the name of a Kubernetes secret holding a credentials file that grants access to AWS resources. It gets mounted as ~/.aws inside the Kubernetes-managed Toil containers. With the right credentials (access to S3 and SimpleDB), this lets the AWSJobStore work with the Kubernetes batch system ๐Ÿ”‘โ˜๏ธ
  • TOIL_AWS_ZONE โ€” the zone to use when you're on AWS. It also determines the region, and it overrides TOIL_AWS_REGION ๐Ÿ—บ๏ธ๐Ÿ‘‘
  • TOIL_AWS_REGION โ€” the region to use when you're on AWS ๐ŸŒŽ
  • TOIL_AWS_AMI โ€” the ID of the AMI used for node provisioning. If you're unsure, just don't set this one ๐Ÿ™ˆ
  • TOIL_AWS_NODE_DEBUG โ€” decides whether nodes that failed health checks get kept around. If it's set to True, nodes that fail EC2 health checks won't be terminated right away, so you can poke at them and figure out what went wrong ๐Ÿ”๐Ÿ’…
Heads up: if any EC2 nodes get left behind this way, the security group gets left behind too. That's by necessity, since it can't be deleted until all its associated nodes are terminated. ๐Ÿซ 
  • TOIL_AWS_BATCH_QUEUE โ€” the name or ARN of an AWS Batch Queue, for use with the AWS Batch batch system ๐Ÿ“ฌโœจ
  • TOIL_AWS_BATCH_JOB_ROLE_ARN โ€” the ARN of an IAM role to run AWS Batch jobs as, for use with the AWS Batch batch system ๐Ÿชช๐ŸŒธ
Warning, bestie: if the jobs aren't run with an IAM role, or on machines that can't access S3 and SimpleDB, the AWS job store won't be usable at all. ๐Ÿ’€
  • TOIL_GOOGLE_PROJECTID โ€” ๐Ÿ’– the Google project ID that gets used when making Google job store names for tests or CWL workflows.
  • TOIL_SLURM_ALLOCATE_MEM โ€” โœจ decides whether Slurm gets told to allocate memory with --mem. It's True by default, so it's on unless you turn it off.
  • TOIL_SLURM_ARGS โ€” ๐ŸŽ€ extra arguments for sbatch when you're using the slurm batch system. ngl, don't put CPU or memory specs in here. Define resource requirements for the job instead. There's no default value. If neither --export nor --export-file shows up in your argument list, --export=ALL gets added for you ๐Ÿซถ
  • TOIL_SLURM_PARTITION โ€” ๐Ÿฆ‹ the partition your Slurm jobs get sent to.
  • TOIL_SLURM_GPU_PARTITION โ€” ๐Ÿ”ฅ the partition your Slurm jobs go to if they ask for GPUs.
  • TOIL_SLURM_PE โ€” ๐ŸŒธ the name of the slurm partition to use for parallel jobs. This is lowkey a lifesaver for clusters that don't have a partition taking both single-core and multi-core jobs. There's no default value.
  • TOIL_SLURM_TIME โ€” โฐ the Slurm job time limit, in [DD-]HH:MM:SS format. For example, 2-07:15:30 means 2 days, 7 hours, 15 minutes and 30 seconds, and 4:00:00 means 4 hours.
  • TOIL_GRIDENGINE_ARGS โ€” ๐Ÿงš extra arguments for qsub on the gridengine batch system. Same rule as before: no CPU or memory specs here, define resource requirements for the job instead. There's no default value.
  • TOIL_GRIDENGINE_PE โ€” ๐Ÿ’œ parallel environment arguments for qsub and the gridengine batch system. There's no default value.
  • TOIL_TORQUE_ARGS โ€” ๐Ÿ‘‘ arguments for qsub on the Torque batch system. Do not pass CPU or memory specs here, because that's giving chaos ๐Ÿ’€ Instead, define extra job parameters like the queue. Example: -q medium. Use TOIL_TORQUE_REQS to pass extra values for the -l resource requirements parameter. There's no default value.
  • TOIL_TORQUE_REQS โ€” ๐ŸŒˆ arguments for the resource requirements on the Torque batch system. Again, no CPU or memory specs. Instead, define extra resource requirements as a string that goes after the -l argument to qsub. Example: walltime=2:00:00,file=50gb. There's no default value.
  • TOIL_LSF_ARGS โ€” ๐Ÿ“ additional arguments for LSF's bsub command. Instead, define extra job parameters like the queue. Example: -q medium. There's no default value.
  • TOIL_HTCONDOR_PARAMS โ€” ๐Ÿฆ‹ additional parameters to include in the HTCondor submit file that gets passed to condor_submit. Do not pass CPU or memory specs here. Instead, define any extra parameters HTCondor might need. This variable is parsed as a semicolon-separated string of parameter = value pairs. Example: requirements = TARGET.has_sse4_2 == true;

Like this: accounting_group = test. There is no default value for this variable ๐Ÿซถ

  • TOIL_CUSTOM_DOCKER_INIT_COMMAND โ€” okay so this is your chance to run any custom bash command inside the Toil docker container before the Toil services start ๐Ÿณ. It's perfect for setup on the worker and/or primary nodes, like private docker authentication ๐Ÿ”. For AWS ECR, the example is pip install awscli && eval $(aws ecr get-login --no-include-email --region us-east-1). Slay ๐Ÿ’…
  • TOIL_CUSTOM_INIT_COMMAND โ€” any custom bash command you want to run before the Toil appliance starts โœจ. Same vibe as the one above: custom setup on the worker and/or primary nodes, like private docker authentication for the Toil appliance itself (aka whatever you pulled from TOIL_APPLIANCE_SELF) ๐ŸŽ€
  • TOIL_S3_HOST โ€” the IP address or hostname you want to use when connecting to S3 ๐Ÿฆ‹. Example: TOIL_S3_HOST=127.0.0.1
  • TOIL_S3_PORT โ€” a port number for connecting to S3 ๐ŸŒธ. Example: TOIL_S3_PORT=9001
  • TOIL_S3_USE_SSL โ€” you can turn SSL on or off for S3 connections ๐Ÿ”’. It's on by default (True), so only touch this if you need to. Example: TOIL_S3_USE_SSL=False
  • TOIL_FTP_USER โ€” the FTP username that overrides every FTP login ๐Ÿ‘‘. Example: TOIL_FTP_USER=ftp_user
  • TOIL_FTP_PASSWORD โ€” the FTP password that overrides every FTP login too ๐Ÿ™ˆ. Example: TOIL_FTP_PASSWORD=ftp_password
  • TOIL_WES_BROKER_URL โ€” an optional broker URL so the WES server and the Celery task queue can talk to each other ๐Ÿงš. If you don't set it, the default is amqp://guest:guest@localhost:5672// ๐Ÿ’œ
  • TOIL_WES_JOB_STORE_TYPE โ€” the default job store type for workflows run through the WES server ๐Ÿ“. It can be file, aws, or google.
  • TOIL_OWNER_TAG โ€” this tags your cloud resources with a tag that reads "Owner: $TOIL_OWNER_TAG" ๐Ÿท๏ธ. Real talk: UCSC uses this internally to keep a bot from terminating untagged resources ๐Ÿค–๐Ÿ’€
  • TOIL_AWS_PROFILE โ€” the name of the AWS profile you want Toil to run with ๐ŸŒˆ
  • TOIL_AWS_TAGS โ€” tags your cloud resources with any arbitrary tags you give in JSON format โญ. When you use launch cluster, the CLI options win and overwrite these. For info on valid AWS tags, check out AWS Tags at https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html ๐Ÿ“š
  • TOIL_TRS_ROOT โ€” an override for the Tool Registry Service endpoint or Dockstore deployment that Toil talks to for workflow lookups and metrics publication ๐Ÿ”. This lets you point those somewhere else, like https://qa.dockstore.org, for debugging ๐Ÿ›
  • TOIL_DOCKSTORE_TOKEN โ€” when publishing workflow metrics, use this Dockstore authentication token instead of the default public Toil one ๐Ÿ”‘
  • SINGULARITY_DOCKER_HUB_MIRROR โ€” an http or https URL for the Singularity wrapper inside the Toil Docker container ๐Ÿชž. It acts as a mirror for Docker Hub, so it's giving main character energy ๐Ÿ‘‘โœจ
  • OMP_NUM_THREADS โ€” bestie, this sets how many cores OpenMP apps get inside the workers ๐Ÿ’ช If you don't set it, Toil just uses the number of job threads ๐Ÿงตโœจ
  • GUNICORN_CMD_ARGS โ€” lets you add extra Gunicorn configurations for the Toil WES server ๐ŸŽ€ The settings docs live at https://docs.gunicorn.org/en/stable/settings.html#settings ๐Ÿ“š

โœจ API REFERENCE โœจ

This page contains auto-generated API reference documentation [1] ๐Ÿค“๐Ÿ’–

๐Ÿงš toil

Submodules

toil.batchSystems

Submodules

toil.batchSystems.abstractBatchSystem

Attributes

  • logger ๐Ÿชต
  • EXIT_STATUS_UNAVAILABLE_VALUE ๐Ÿšซ

Exceptions

  • InsufficientSystemResources โ€” the common base class for all non-exit exceptions ๐Ÿ’€
  • AcquisitionTimeoutException โ€” raised when a resource request times out โฐ

Classes

  • BatchJobExitReason โ€” an enum where the members are also (and must be) ints ๐Ÿ”ข
  • UpdatedBatchJobInfo ๐Ÿ“
  • WorkerCleanupInfo ๐Ÿงน
  • AbstractBatchSystem โ€” an abstract base class that represents the interface the batch system has to provide to Toil ๐Ÿงฑ
  • BatchSystemSupport โ€” a partial implementation of AbstractBatchSystem, with support methods ๐Ÿ› ๏ธ
  • NodeInfo โ€” the coresUsed attribute is a floating point value between 0 (all cores idle) and 1 (all cores ๐Ÿ‘€
  • AbstractScalableBatchSystem โ€” a batch system that supports a variable number of worker nodes ๐Ÿ“ˆ
  • ResourcePool โ€” represents an integral amount of a resource, such as memory bytes ๐Ÿง 
  • ResourceSet โ€” represents a collection of distinct resources, such as accelerators โšก

Module Contents

  • toil.batchSystems.abstractBatchSystem.logger ๐Ÿชต
  • toil.batchSystems.abstractBatchSystem.EXIT_STATUS_UNAVAILABLE_VALUE = 255 ๐Ÿšซ

class toil.batchSystems.abstractBatchSystem.BatchJobExitReason

Bases: enum.IntEnum

Enum where members are also (and must be) ints. This is giving very strict vibes ๐Ÿ˜ค

  • FINISHED = 1 โ€” Successfully finished. โœ…
  • FAILED = 2 โ€” Job finished, but failed. ๐Ÿ’”
  • LOST = 3 โ€” Preemptable failure (job's executing host went away). ๐Ÿ‘ป
  • KILLED = 4 โ€” Job killed before finishing. ๐Ÿ”ช
  • ERROR = 5 โ€” Internal error. ๐Ÿšจ
  • MEMLIMIT = 6 โ€” Job hit batch system imposed memory limit. ๐Ÿง ๐Ÿ’ฅ
  • MISSING = 7 โ€” Job disappeared from the scheduler without actually stopping, so Toil killed it. ๐Ÿซฅ
  • MAXJOBDURATION = 8 โ€” Job ran longer than --maxJobDuration, so Toil killed it. โŒ›
  • PARTITION = 9 โ€” Job was not able to talk to the leader via the job store, so Toil declared it failed. ๐Ÿ“ต

classmethod to_string(value)

Convert to human-readable string. Given an int that may or may not be equal to a value from the enum, it produces the string value of its matching enum entry, or a stringified int ๐Ÿช„

Parameters: value (int)

Return type: str

class toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo

  • jobID: int โ€” the Toil batch system ID of the job ๐Ÿ†”
  • exitStatus: int = 255 โ€” the exit status (integer value) of the job. 0 means successful ๐ŸŽ‰ EXIT_STATUS_UNAVAILABLE_VALUE is used when the exit status isn't available (e.g. the job is lost, or it died but the actual exit code was never reported) ๐Ÿซ 
  • exitReason: BatchJobExitReason | None = None ๐Ÿšช
  • wallTime: float | int | None = None โฑ๏ธ
  • backing_id: str | None = None โ€” the identifier for the job in the backing scheduler, if it's available ๐Ÿ”–

class toil.batchSystems.abstractBatchSystem.WorkerCleanupInfo

Bases: NamedTuple

  • work_dir: str | None โ€” the work directory path (where the cache would go) if the user specified one ๐Ÿ“
  • coordination_dir: str | None โ€” the coordination directory path (where lock files would go) if the user specified one ๐Ÿ”’
  • workflow_id: str โ€” used to identify files specific to this workflow ๐Ÿชช
  • clean_work_dir: str โ€” when to clean up the work and coordination directories for a job ('always', 'onSuccess', 'onError', 'never') ๐Ÿงฝ

class toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

Bases: abc.ABC

An abstract base class to represent the interface the batch system must provide to Toil. It's the blueprint, bestie ๐Ÿ“

classmethod supportsAutoDeployment()

Abstractmethod ๐Ÿงฉ

Return type: bool

Whether this batch system supports auto-deployment of the user script itself ๐Ÿš€

If it does, the setUserScript() can be invoked to set the resource object representing the user script. ๐Ÿ’… Note to implementors: if your implementation returns True here, it should also override classmethod supportsWorkerCleanup() ๐Ÿซถ

๐Ÿฆ‹ classmethod supportsWorkerCleanup()

Abstractmethod ๐Ÿ’€

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

Okay so this one answers whether the batch system supports worker cleanup. โœจ It tells you whether the batch system calls BatchSystemSupport.workerCleanup() after the last job for a particular workflow invocation finishes. ๐Ÿงน Quick vibe check: the word worker means an entire node here, not just one worker process. ๐Ÿ–ฅ๏ธ A worker process can run more than one job, one after another, and several concurrent worker processes can exist on the same worker node for the same workflow. ๐Ÿซ  The batch system is said to shut down after the last worker process terminates. ๐Ÿ‘‘

๐Ÿฆ‹ abstractmethod setUserScript(userScript)

Set the user script for this workflow. ๐ŸŽ€

This method must be called before the first job is issued to this batch system, and only if supportsAutoDeployment() returns True. Otherwise it will raise an exception. ๐Ÿšจ

Parameters:

  • userScript (toil.resource.Resource) โ€” the resource object representing the user script or module, plus all the modules it depends on. ๐Ÿงš

Return type: None ๐Ÿ“

๐Ÿฆ‹ set_message_bus(message_bus)

This gives the batch system a chance to connect directly to the message bus. ๐Ÿ“ฃ That way it can send informational messages about the jobs it's running to other Toil components. ๐Ÿ’œ

Parameters:

  • message_bus (toil.bus.MessageBus)

Return type: None ๐ŸŒธ

๐Ÿฆ‹ abstractmethod issueBatchJob(command, job_desc, job_environment=None)

This one issues a job with the specified command to the batch system and returns a unique job ID number. ๐Ÿ”ฅ It's giving "send it and get a receipt" energy. ๐Ÿงพ

Parameters:

  • command (str) โ€” the command to execute somewhere in order to run the Toil worker process. ๐Ÿƒโ€โ™€๏ธ
  • job_desc (toil.job.JobDescription) โ€” the JobDescription for the job being run. ๐ŸŽ€
  • job_environment (Optional[dict[str, str]]) โ€” a collection of job-specific environment variables to be set on the worker. ๐ŸŒˆ

Returns: a unique job ID number that can be used to reference the newly issued job. ๐Ÿ†”

Return type: int (/usr/share/doc/python3/html/library/functions.html#int) โœจ

๐Ÿฆ‹ abstractmethod killBatchJobs(jobIDs)

This kills the given job IDs. ๐Ÿ’€ After it returns, the killed jobs won't show up in the results of getRunningBatchJobIDs, and they won't be returned from getUpdatedBatchJob either. ๐Ÿ™ˆ Gone, reduced to nothing, iykyk.

Parameters:

  • jobIDs (list[int]) โ€” list of IDs of the jobs to kill. โญ

Return type: None ๐Ÿซถ

๐Ÿฆ‹ abstractmethod getIssuedBatchJobIDs()

This gets all the currently issued jobs. ๐Ÿ“‹

Returns: a list of jobs (as job ID numbers) that are currently issued. They may be running, or they may be waiting to be run. ๐Ÿงƒ Even though the result is a list, please don't depend on the ordering. ๐Ÿ™…โ€โ™€๏ธ

Return type: list[int] ๐ŸŒท

๐Ÿฆ‹ abstractmethod getRunningBatchJobIDs()

This gets a map of jobs, by job ID number, that are currently running (not just waiting), along with how long each one has been running in seconds. โฑ๏ธ The main character of this method is the timer. โณ

Returns: a dictionary with the currently running job ID numbers as keys, and how many seconds each has been running as the values. ๐Ÿ“–

Return type: dict[int, float] ๐ŸŒ™

๐Ÿฆ‹ abstractmethod getUpdatedBatchJob(maxWait)

This returns info about a job that has updated its status. ๐ŸŽ‰ That means it stopped running, either successfully or with an error. ๐Ÿ’” Each job gets returned exactly once, so no double-dipping. ๐Ÿ™…โ€โ™€๏ธ

Heads up, bestie: this does not return info for jobs killed by killBatchJobs. ๐Ÿ˜ญ Those can cause None to be returned earlier than maxWait, though, so don't panic when that happens. ๐Ÿซ 

Parameters:

  • maxWait (int) โ€” the number of seconds to block while waiting for a result. โฐ

Returns: if a result is available, it returns UpdatedBatchJobInfo. Otherwise it returns None. ๐ŸŽ€ The wallTime is the number of seconds (a strictly positive float) of wall-clock time the job ran for. If this batch system doesn't support tracking wall time, it's None instead. ๐Ÿ•ฐ๏ธ

Return type: Optional[UpdatedBatchJobInfo] ๐Ÿฆ‹

๐Ÿฆ‹ getSchedulingStatusMessage()

This gets a log message fragment for the user about anything that might be going wrong in the batch system, if there's one available. ๐Ÿšฆ If there's no useful message, it returns None. ๐Ÿ™ƒ

It's perfect for reporting which resource is the limiting factor when scheduling jobs. ๐Ÿ’ก If the leader thinks the workflow is stuck, the message can be shown to the user so they can figure out why it might be stuck. ๐Ÿ•ต๏ธโ€โ™€๏ธ

Returns: a user-directed message about the scheduling state. ๐Ÿ’ฌ

Return type: Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“

๐Ÿฆ‹ abstractmethod shutdown()

This is called at the completion of a Toil invocation. ๐Ÿ It should cleanly terminate all worker threads, no messy leftovers. ๐Ÿงนโœจ

Return type: None ๐Ÿ‘‹

๐Ÿฆ‹ abstractmethod setEnv(name, value=None)

This sets an environment variable for the worker process before it's launched. ๐ŸŒฑ

The worker process will typically inherit the environment of the machine it's running on. This method lets you override specific variables in that inherited environment before the worker launches. ๐Ÿ’… Note that this mechanism is different from the one the worker uses internally to set up the environment of a job. A call to this method affects all jobs issued after the method returns.

Note to implementors: this means you'd typically need to copy the variables before enqueuing a job. ๐Ÿซถ

If no value is provided, it's looked up from the current environment. ๐Ÿ”

Parameters:

  • name (str) (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • value (Optional[str]) (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None ๐ŸŒธ

๐Ÿฆ‹ classmethod add_options(parser)

If this batch system provides any command line options, this adds them to the given parser. ๐Ÿ› ๏ธ

Parameters:

  • parser (Union[argparse.ArgumentParser, argparse._ArgumentGroup])

Return type: None ๐ŸŽ€

๐Ÿฆ‹ classmethod setOptions(setOption)

This processes command line or configuration options relevant to this batch system. โš™๏ธ

Parameters:

  • setOption (toil.batchSystems.options.OptionSetter) โ€” a function with the signature setOption(option_name, parsing_function=None, check_function=None, default=None, env=None) that returns nothing. It's used to update the run configuration as a side effect. โœจ

Return type: None ๐Ÿ’œ

๐Ÿฆ‹ getWorkerContexts()

This gets a list of picklable context manager objects to wrap worker work in, in order. ๐ŸŽ

It can be used to ask the Toil worker to do things in-process, like configuring environment variables, hot-deploying user scripts, or cleaning up a node. Those things would otherwise need a wrapping "executor" process, and nobody wants that extra drama. ๐Ÿ™„๐Ÿ”ฅ

Return type: list[ContextManager[Any]] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐ŸŒˆ

Okay so bestie, this next bit is all about the BatchSystemSupport class ๐Ÿ’…โœจ It's a partial implementation of AbstractBatchSystem that's basically the helper crew, and they are giving main character energy ๐ŸŽ€

class toil.batchSystems.abstractBatchSystem.BatchSystemSupport(config, maxCores, maxMemory, maxDisk)

Bases: AbstractBatchSystem ๐Ÿฆ‹

Parameters

  • config (toil.common.Config) ๐Ÿ’–
  • maxCores (float) ๐ŸŒธ
  • maxMemory (float) ๐ŸŒธ
  • maxDisk (int) ๐ŸŒธ

Attributes

  • config
  • maxCores
  • maxMemory
  • maxDisk
  • environment: dict[str, str]

check_resource_request(requirer)

So this one checks that a resource request isn't bigger than what's available or allowed. No overreaching allowed ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • requirer (toil.job.Requirer) โ€” the object whose requirements are being checked ๐Ÿ‘€
  • job_name (str) โ€” the name of the job being checked, so you get a useful error report ๐Ÿงพ
  • detail (str) โ€” a batch-system-specific message to include in the error ๐Ÿ’ฌ

Raises

InsufficientSystemResources โ€” raised when a resource is requested in an amount greater than allowed ๐Ÿ’€

Return type

None

setEnv(name, value=None)

This sets an environment variable for the worker process before it launches. Workers usually inherit the environment of whatever machine they're on, but this lets you override specific variables in that inherited environment before the worker starts ๐Ÿงš Lowkey important: this is a different mechanism from the one the worker uses internally to set up a job's environment. Any call to this method affects every job issued after it returns. To the implementors out there, this means you'll typically need to copy the variables before enqueuing a job ๐Ÿซถ

If no value is given, it gets looked up from the current environment.

Parameters

  • name (str) โ€” the environment variable to be set on the worker ๐ŸŒˆ
  • value (Optional[str]) โ€” if given, the environment variable named by name gets set to this value. If None, the variable's current value gets used as the value on the worker ๐Ÿ’œ

Raises

RuntimeError โ€” raised if value is None and the name can't be found in the environment ๐Ÿ˜ญ

Return type

None

set_message_bus(message_bus)

This gives the batch system a chance to connect straight to the message bus, so it can send informational messages about its jobs to other Toil components. It's giving collab energy ๐Ÿค

Parameters

  • message_bus (toil.bus.MessageBus)

Return type

None

get_batch_logs_dir()

This gets the directory where the backing batch system should save its logs ๐Ÿ“‚

Only really makes sense if the backing batch system actually saves logs to a filesystem. Kubernetes, for example, does not ๐Ÿ™ˆ It ought to be a directory shared between the leader and the workers, if the backing batch system writes logs onto the worker's view of the filesystem, like many HPC schedulers do.

Return type

str

format_std_out_err_path(toil_job_id, cluster_job_id, std)

This formats the path for the batch system's standard output and error, plus any other files the batch system generates itself ๐Ÿงพ

Files get written to the batch logs directory (--batchLogsDir, which defaults to the Toil work directory) with names that include both the Toil and batch system job IDs, so debugging failed jobs is so much easier ๐Ÿ”

Parameters

  • toil_job_id (int) โ€” the unique ID that Toil gives a job ๐Ÿ†”
  • cluster_job_id (str) โ€” what the cluster uses as its internal job ID, for example GridEngine ๐Ÿ–ฅ๏ธ
  • std (str) โ€” the provenance of the stream, for example 'err' for stderr or 'out' for stdout ๐ŸŒŠ

Return type

string โ€” the formatted filename. However, if self.config.noStdOutErr is true, it returns '/dev/null' or the equivalent ๐Ÿ•ณ๏ธ

format_std_out_err_glob(toil_job_id)

This gives you a glob string that matches all the file paths format_std_out_err_path generates for a job. Ultimate pattern-matching queen behavior ๐Ÿ‘‘

Parameters

  • toil_job_id (int)

Return type

str

workerCleanup(info) (static)

This cleans up the worker node when the batch system shuts down โœจ Also see supportsWorkerCleanup(), bestie.

Parameters

  • info (WorkerCleanupInfo) โ€” a named tuple with all the relevant info for cleaning up the worker ๐Ÿงน

Return type

None


NodeInfo

class toil.batchSystems.abstractBatchSystem.NodeInfo(coresUsed, memoryUsed, coresTotal, memoryTotal, requestedCores, requestedMemory, workers)

Okay, so NodeInfo is all the stats on a node, and each attribute has its own vibe ๐Ÿ“Š

coresUsed is a floating point value between 0 (all cores idle) and 1 (all cores busy), reflecting the CPU load of the node ๐Ÿ”ฅ

memoryUsed is a floating point value between 0 (no memory used) and 1 (all memory used), reflecting the memory pressure on the node ๐Ÿง 

coresTotal and memoryTotal are the node's resources, not just the used ones. The full stash ๐Ÿ’Ž

requestedCores and requestedMemory are all the resources that Toil Jobs have reserved on the node, regardless of whether the Jobs are actually using them. Reserved is not the same as used, iykyk ๐Ÿ™ƒ

workers is an integer reflecting the number of currently active workers on the node ๐Ÿ

Parameters

  • coresUsed (float)
  • memoryUsed (float)
  • coresTotal (float)
  • memoryTotal (int)
  • requestedCores (float)
  • requestedMemory (int)
  • workers (int)

Attributes

  • coresUsed
  • memoryUsed
  • coresTotal
  • memoryTotal
  • requestedCores
  • requestedMemory
  • workers

AbstractScalableBatchSystem

class toil.batchSystems.abstractBatchSystem.AbstractScalableBatchSystem

Bases: AbstractBatchSystem ๐Ÿฆ‹

This is a batch system that can handle a variable number of worker nodes. It's the scaling queen ๐Ÿ‘‘ It's used by toil.provisioners.clusterScaler.ClusterScaler to scale the number of worker nodes in the cluster up or down, depending on overall load ๐Ÿ“ˆ๐Ÿ“‰

getNodes(preemptible=None, timeout=600) (abstract method)

This returns a dictionary mapping node identifiers of preemptible or non-preemptible nodes to NodeInfo objects, one for each node ๐Ÿ—‚๏ธ

Parameters

  • preemptible (Optional[bool]) โ€” if True (or False), only the (non-)preemptible nodes get returned. If None, all nodes get returned ๐ŸŽฏ
  • timeout (int) โณ

Return type

dict[str, NodeInfo]

nodeInUse(nodeIP) (abstract method)

This can be used to figure out if a worker node is running any tasks. If the node doesn't exist, this function should just return False ๐Ÿซ 

  • nodeIP (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the worker node's private IP address ๐ŸŒธ
  • Returns โ€” True if the worker node has been issued any tasks, else False ๐Ÿ’–
  • Return type โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’…

abstract method ignoreNode(nodeAddress) ๐Ÿ›‘

Okay so this one tells the batch system to stop sending jobs to a node. It's used in autoscaling when the autoscaler is ready to terminate a node but jobs are still running, so the node gets terminated only after the current jobs have finished ๐Ÿงน

  • nodeAddress (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the IP address of the node to ignore ๐Ÿซถ
  • Return type โ€” None ๐ŸŒˆ

abstract method unignoreNode(nodeAddress) ๐Ÿฆ‹

This one stops ignoring an address, presumably after a node with that address has been terminated. The vibe is that a brand new node is allowed to show up with the same address as an old terminated one ๐Ÿ‘‘

  • nodeAddress (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒธ
  • Return type โ€” None โœจ

๐Ÿ’ฅ exception toil.batchSystems.abstractBatchSystem.InsufficientSystemResources

toil.batchSystems.abstractBatchSystem.InsufficientSystemResources(requirer, resource, available=None, batch_system=None, source=None, details=[])
  • Bases โ€” Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception) ๐Ÿงš

It's the common base class for all non-exit exceptions ๐Ÿ’œ

  • requirer (toil.job.Requirer <#toil.job.Requirer>) ๐ŸŽ€
  • resource (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“
  • available (Optional[toil.job.ParsedRequirement]) โญ
  • batch_system (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒธ
  • source (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿฆ‹
  • details (list[str], /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’…

Attributes, bestie:

  • job_name โ€” job_name: str | None = '' (/usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/constants.html#None) ๐Ÿ™ˆ
  • resource ๐Ÿ’–
  • requested ๐Ÿ’–
  • available = None ๐Ÿ’–
  • batch_system = None ๐Ÿ’–
  • source = None ๐Ÿ’–
  • details = [] ๐Ÿ’–

__str__() ๐Ÿ”ฅ Explains the exception.

  • Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’€

๐Ÿ’ฅ exception toil.batchSystems.abstractBatchSystem.AcquisitionTimeoutException

toil.batchSystems.abstractBatchSystem.AcquisitionTimeoutException(resource, requested, available)
  • Bases โ€” Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception) ๐Ÿงš

This one gets raised when a resource request times out ๐Ÿ˜ญ

  • resource (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“
  • requested (Union[int, float, set[int]], with /usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/functions.html#float, and /usr/share/doc/python3/html/library/stdtypes.html#set plus /usr/share/doc/python3/html/library/functions.html#int) ๐ŸŒˆ
  • available (Union[int, float, set[int]], with /usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/functions.html#float, and /usr/share/doc/python3/html/library/stdtypes.html#set plus /usr/share/doc/python3/html/library/functions.html#int) ๐ŸŒˆ

Attributes:

  • requested โœจ
  • available โœจ
  • resource โœจ

๐Ÿซง class toil.batchSystems.abstractBatchSystem.ResourcePool

toil.batchSystems.abstractBatchSystem.ResourcePool(initial_value, resource_type, timeout=5)

This is an integral amount of a resource (like memory bytes) ๐Ÿง  You can acquire amounts immediately or with a timeout, and you can release them too. It also gives you a context manager so you can do something with an amount of resource you've acquired ๐Ÿซถ

  • initial_value (int, /usr/share/doc/python3/html/library/functions.html#int) ๐ŸŒธ
  • resource_type (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒธ
  • timeout (float, /usr/share/doc/python3/html/library/functions.html#float) ๐ŸŒธ

Attributes:

  • condition ๐Ÿ’œ
  • value ๐Ÿ’œ
  • resource_type ๐Ÿ’œ
  • timeout = 5 ๐Ÿ’œ

acquireNow(amount) โฐ Reserves the given amount of the given resource. It returns True if that worked and False if it's not possible immediately.

  • amount (int, /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“
  • Return type โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’…

acquire(amount) โณ Reserves the given amount of the given resource. If that isn't possible in under self.timeout time, it raises AcquisitionTimeoutException.

  • amount (int, /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“
  • Return type โ€” None ๐ŸŒˆ

release(amount) ๐Ÿฆ‹

  • amount (int, /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“
  • Return type โ€” None ๐ŸŒˆ

__str__() ๐Ÿ”ฅ

  • Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’€

__repr__() ๐Ÿ”ฅ

  • Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’€

acquisitionOf(amount) ๐ŸŽ€

  • amount (int, /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“
  • Return type โ€” collections.abc.Iterator[None] (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterator) ๐Ÿ‘‘

๐Ÿซง class toil.batchSystems.abstractBatchSystem.ResourceSet

toil.batchSystems.abstractBatchSystem.ResourceSet(initial_value, resource_type, timeout=5)

This one represents a collection of distinct resources (like accelerators) ๐Ÿงš Subsets can be acquired immediately or with a timeout, and released. There's also a context manager so you can do something with a set of resources you've acquired โœจ

  • initial_value (set[int], /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/functions.html#int) ๐ŸŒธ
  • resource_type (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒธ
  • timeout (float, /usr/share/doc/python3/html/library/functions.html#float) ๐ŸŒธ

Attributes:

  • condition ๐Ÿ’œ
  • value ๐Ÿ’œ
  • resource_type ๐Ÿ’œ
  • timeout = 5 ๐Ÿ’œ

acquireNow(subset) โฐ Reserves the given amount of the given resource. It returns True if that worked and False if it's not possible immediately.

  • subset (set[int], /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“
  • Return type โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’…

acquire(subset) โณ Reserves the given amount of the given resource. If that isn't possible in under self.timeout time, it raises AcquisitionTimeoutException.

  • subset (set[int], /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“
  • Return type โ€” None ๐ŸŒˆ

release(subset) ๐Ÿฆ‹

  • subset (set[int], /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“
  • Return type โ€” None ๐ŸŒˆ

get_free_snapshot() ๐Ÿ“ธ Gets a snapshot of what items are free right now. It may be stale as soon as you get it, but you'll need some kind of hint to try and do an acquire.

  • Return type โ€” set[int] (/usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ’…

__str__() ๐Ÿ”ฅ

  • Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’€

__repr__() ๐Ÿ”ฅ

  • Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’€

acquisitionOf(subset) ๐ŸŽ€

  • subset (set[int], /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“
  • Return type โ€” collections.abc.Iterator[None] (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterator) ๐Ÿ‘‘

๐ŸŒˆ toil.batchSystems.abstractGridEngineBatchSystem

Attributes, the whole vibe:

  • logger ๐Ÿงš
  • JobTuple ๐Ÿงš

โœจ Exceptions โœจ

Okay so the exceptions section is short and sweet ๐Ÿ™ˆ there's just one here, and it's giving main character energy:

  • ExceededRetryAttempts ๐Ÿ’€ is the common base class for all non-exit exceptions. It's a subclass of Exception.

๐Ÿฆ‹ Classes ๐Ÿฆ‹

Now the classes! ๐Ÿ’… The summary table cuts off mid-sentence, but the full description is below:

  • AbstractGridEngineBatchSystem ๐ŸŒธ a partial implementation of BatchSystemSupport for batch systems run on a

๐Ÿงš Module Contents ๐Ÿงš

Here's everything that lives in the module, bestie ๐Ÿ’–

  • toil.batchSystems.abstractGridEngineBatchSystem.logger
  • toil.batchSystems.abstractGridEngineBatchSystem.JobTuple

๐ŸŽ€ exception toil.batchSystems.abstractGridEngineBatchSystem.ExceededRetryAttempts ๐ŸŽ€

Bases: Exception

Common base class for all non-exit exceptions. It's the one I keep mentioning, so you know it's important ๐Ÿ’œ

๐Ÿ‘‘ class AbstractGridEngineBatchSystem ๐Ÿ‘‘

class toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem(config, maxCores, maxMemory, maxDisk)

Bases: toil.batchSystems.cleanup_support.BatchSystemCleanupSupport

A partial implementation of BatchSystemSupport for batch systems run on a standard HPC cluster. By default, auto-deployment is not implemented ๐Ÿ™ˆ

Parameters

  • config (toil.common.Config)
  • maxCores (float)
  • maxMemory (float)
  • maxDisk (float)

exception GridEngineThreadException ๐Ÿ“ Bases: Exception. Common base class for all non-exit exceptions, same energy as the one above โœจ

class GridEngineThread(newJobsQueue, updatedJobsQueue, killQueue, killedJobsQueue, boss) ๐Ÿงš

Bases: threading.Thread

A class that represents a thread of control. It can be safely subclassed in a limited fashion, and there are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the run() method in a subclass.

Parameters

  • newJobsQueue (queue.Queue)
  • updatedJobsQueue (queue.Queue)
  • killQueue (queue.Queue)
  • killedJobsQueue (queue.Queue)
  • boss (AbstractGridEngineBatchSystem)

Attributes ๐Ÿฆ‹

  • boss
  • newJobsQueue
  • updatedJobsQueue
  • killQueue
  • killedJobsQueue
  • waitingJobs: list[JobTuple] = []
  • runningJobs
  • runningJobsLock
  • batchJobIDs: dict[int, str]
  • exception = None

Methods ๐Ÿ’…

  • getBatchSystemID(jobID) โœจ gets the batch system-specific job ID. It's lowkey the only consistent way to cleanly grab that ID right now.
    • Parameters: jobID (int) -- Toil BatchSystem numerical job ID
    • Return type: str
  • forgetJob(jobID) ๐Ÿงน removes the jobID you pass in.
    • Parameters: jobID (int) -- toil job ID
    • Return type: None
  • createJobs(newJob) ๐ŸŒˆ creates a new job with the given attributes. It's implementation-specific and gets called by GridEngineThread.run().
    • Parameters: newJob (JobTuple)
    • Return type: bool
  • killJobs() ๐Ÿ’€ kills any running jobs within the thread.
  • checkOnJobs() ๐Ÿ” checks and updates the status of all running jobs. It respects statePollingWait and will return cached results if it isn't time to talk to the scheduler yet.
  • run() ๐Ÿš€ runs any new jobs.
  • coalesce_job_exit_codes(batch_job_id_list) ๐ŸŽฏ returns exit codes and possibly exit reasons for a list of jobs, or None if they're still running. It gets called by GridEngineThread.checkOnJobs(). The default version falls back on self.getJobExitCode and polls each job one by one.
    • Parameters: batch_job_id_list (string) -- List of batch system job ID
    • Return type: list[Union[int, tuple[int, Optional[toil.batchSystems.abstractBatchSystem.BatchJobExitReason]], None]]
  • abstractmethod prepareSubmission(cpu, memory, jobID, command, jobName, job_environment=None, gpus=None) ๐ŸŽ€ is the prep work for putting together a command-line string for submitting to the batch system (via submitJob()).
    • Param int cpu
    • Param int memory
    • Param int jobID: Toil job ID
    • Param string subLine: the command line string to be called
    • Param string jobName: the name of the Toil job, to provide metadata to batch systems if they want it
    • Param dict job_environment: the environment variables to be set on the worker
    • Return type: List[str]
    • Parameters: cpu (int), memory (int), jobID (int), command (str), jobName (str), job_environment (Optional[dict[str, str]]), gpus (Optional[int])
  • abstractmethod submitJob(subLine) ๐Ÿšข is a wrapper routine that submits the actual command-line call, then processes the output to get the batch system job ID.
    • Param string subLine: the literal command line string to be called
    • Return type: string, the batch system job ID, which gets stored internally
  • abstractmethod getRunningJobIDs() ๐Ÿ‘€ gets a list of running job IDs. It's implementation-specific and gets called by the boss AbstractGridEngineBatchSystem implementation via AbstractGridEngineBatchSystem.getRunningBatchJobIDs().
    • Return type: list
abstractmethod killJob(jobID)

okay bestie, this one is the kill switch ๐Ÿ’€ It takes out one specific job using its Toil job ID. Every implementation handles the actual killing its own way, and it gets called by GridEngineThread.killJobs() ๐Ÿ”ฅ

  • jobID (string) โ€” the Toil job ID
abstractmethod getJobExitCode(batchJobID)

this one gives you the job's exit code, and sometimes an instance of abstractBatchSystem.BatchJobExitReason tagging along โœจ

  • It returns None if the job is still running ๐Ÿƒโ€โ™€๏ธ
  • If the job already stopped but the exit code isn't available, you get EXIT_STATUS_UNAVAILABLE_VALUE ๐Ÿ™ˆ
  • Implementation-specific, and it's called by GridEngineThread.checkOnJobs() ๐Ÿ’…
  • The exit code is only 0 if the job affirmatively succeeded. No vibes-based success here, periodt ๐ŸŒธ

Parameters

  • batchjobID (string) โ€” batch system job ID

Return type

Union[int, tuple[int, Optional[toil.batchSystems.abstractBatchSystem.BatchJobExitReason]], None]

Doc links for the types in there:

  • int โ†’ /usr/share/doc/python3/html/library/functions.html#int
  • tuple โ†’ /usr/share/doc/python3/html/library/stdtypes.html#tuple
  • BatchJobExitReason โ†’ toil.batchSystems.abstractBatchSystem.BatchJobExitReason

Here are the attributes this class is carrying around ๐Ÿงš:

  • config
  • currentJobs
  • newJobsQueue
  • updatedJobsQueue
  • killQueue
  • killedJobsQueue
  • background_thread
classmethod supportsAutoDeployment()

this checks whether the batch system can auto-deploy the user script itself. If it can, setUserScript() can be called to set the resource object that represents the user script ๐Ÿ“ฆ

Note to implementors: if your implementation returns True here, it should also override

count_needed_gpus(job_desc)

counts how many cluster-allocatable GPUs you want to grab for the given job ๐ŸŽ€

  • job_desc (toil.job.JobDescription)
issueBatchJob(command, job_desc, job_environment=None)

this is the send-it moment ๐Ÿš€ It issues a job with the command you give it to the batch system, then hands back a unique job ID number.

  • command (str) โ€” the command to run somewhere to launch the Toil worker process
  • job_desc (toil.job.JobDescription) โ€” the JobDescription for the job being run
  • job_environment (Optional[dict[str, str]]) โ€” a bundle of job-specific environment variables to set on the worker ๐ŸŒˆ

Returns

a unique job ID number you can use to reference the newly issued job ๐Ÿ’–

Doc links for those types:

  • str โ†’ /usr/share/doc/python3/html/library/stdtypes.html#str
  • dict โ†’ /usr/share/doc/python3/html/library/stdtypes.html#dict
killBatchJobs(jobIDs)

kills the given jobs (represented as Job ids), then double-checks they're actually dead by making sure they're no longer in the list of issued jobs ๐Ÿ’€โœจ

getIssuedBatchJobIDs()

grabs the list of issued jobs ๐Ÿ“‹

getRunningBatchJobIDs()

retrieves the running job IDs from both the local machine and the batch scheduler ๐Ÿƒโ€โ™€๏ธ It respects statePollingWait, so if it isn't time to talk to the scheduler yet, you get cached results instead. Main character patience ๐Ÿ‘‘

getUpdatedBatchJob(maxWait)

returns info about a job that has updated its status, meaning it stopped running either successfully or with an error. Each job only shows up exactly once ๐Ÿฆ‹

Jobs killed by killBatchJobs won't show up here. They might make this return None sooner than maxWait, though.
  • maxWait โ€” the number of seconds to block while waiting for a result

Returns

If a result is available, you get an UpdatedBatchJobInfo. If not, you get None. wallTime is how long the job ran in wall-clock time, as a strictly positive float in seconds, or None if this batch system can't track wall time โฑ๏ธ

shutdown()

signals the thread to shut down (using a sentinel), then cleanly joins the thread ๐Ÿซถ

Return type

None

setEnv(name, value=None)

sets an environment variable for the worker process before it launches ๐ŸŒธ The worker usually inherits the environment of the machine it runs on, but this lets you override specific variables in that inherited environment. This is different from the mechanism the worker uses internally to set up a job's environment, so don't mix them up ๐Ÿ™ˆ A call to this affects every job issued after the method returns.

Note to implementors: this means you'll typically need to copy the variables before enqueuing a job.

If you don't give a value, it gets looked up from the current environment.

Parameters

  • name โ€” the environment variable to set on the worker
  • value โ€” if given, the variable named by name is set to this value. If None, the variable's current value is used as the value on the worker

Raises RuntimeError (docs: /usr/share/doc/python3/html/library/exceptions.html#RuntimeError) โ€” if value is None and the name can't be found in the environment ๐Ÿ˜ญ

classmethod getWaitDuration()
sleepSeconds(sleeptime=1)

a little helper that every state-querying function leans on so nobody over-queries ๐Ÿ›Œ

with_retries(operation, *args, **kwargs)

calls operation with args and kwargs. If one of the calls to a command fails, it sleeps and tries again ๐Ÿ”


toil.batchSystems.awsBatch

this is the batch system for running Toil workflows on AWS Batch ๐Ÿงก It's especially good with the AWS job store.

AWS Batch can't schedule based on disk usage. The backing machines need to have "enough" disk, and the other constraints need to make sure the disk never fills up. Otherwise it's a whole disaster ๐Ÿ’€

It assumes you've already got an AWS Batch Queue name or ARN ready to go. It also handles creating and destroying a JobDefinition for the workflow run ๐Ÿง

Additional containers should be launched with Singularity, not Docker ๐Ÿณ

Attributes

  • logger
  • STATE_TO_EXIT_REASON
  • MAX_POLL_COUNT
  • MIN_REQUESTABLE_MIB
  • MIN_REQUESTABLE_CORES

Classes

  • AWSBatchBatchSystem, which adds cleanup support when the last running job leaves a node, for batch systems that can't provide it using the backing scheduler โœจ

Module Contents

  • toil.batchSystems.awsBatch.logger
  • toil.batchSystems.awsBatch.STATE_TO_EXIT_REASON: dict[str, toil.batchSystems.abstractBatchSystem.BatchJobExitReason]
  • toil.batchSystems.awsBatch.MAX_POLL_COUNT = 100
  • toil.batchSystems.awsBatch.MIN_REQUESTABLE_MIB = 4
  • toil.batchSystems.awsBatch.MIN_REQUESTABLE_CORES = 1
class toil.batchSystems.awsBatch.AWSBatchBatchSystem(config, maxCores, maxMemory, maxDisk)

Bases: toil.batchSystems.cleanup_support.BatchSystemCleanupSupport ๐Ÿงธ

This one adds cleanup support when the last running job leaves a node, for batch systems that can't pull that off using the backing scheduler ๐Ÿงน

Parameters

  • config (toil.common.Config)
  • maxCores (float) โ€” docs: /usr/share/doc/python3/html/library/functions.html#float
  • maxMemory (float) โ€” docs: /usr/share/doc/python3/html/library/functions.html#float
  • maxDisk (int) โ€” docs: /usr/share/doc/python3/html/library/functions.html#int
classmethod supportsAutoDeployment()

same deal as before: this checks whether the batch system supports auto-deployment of the user script itself ๐Ÿ“ฆ

Okay so, the batch system is about to get its moment ๐Ÿ’… If it does support auto-deployment, you can call setUserScript() to hand over the resource object for the user script ๐Ÿซถ

๐Ÿ“ Note to implementors: If your implementation returns True here, it should also override

Return type โ€” bool ๐ŸŒธ


โœจ ATTRIBUTES โœจ

Here's the full list of attributes on this batch system, no skipping ๐Ÿฆ‹

  • region
  • client
  • queue
  • job_role_arn
  • owner_tag
  • worker_work_dir
  • user_script: toil.resource.Resource | None = None
  • docker_image
  • job_definition: str | None = None
  • bs_id_to_aws_id: dict[int, str]
  • aws_id_to_bs_id: dict[str, int]
  • killed_job_aws_ids: set[str]

๐Ÿ’– setUserScript(user_script)

Sets the user script for this workflow. Lowkey a must-do: this has to be called before the first job is issued to this batch system, and it only works if supportsAutoDeployment() returns True. Otherwise it's going to raise an exception ๐Ÿ˜ญ

Parameters

  • userScript โ€” the resource object representing the user script or module, plus any modules it depends on
  • user_script (toil.resource.Resource)

Return type โ€” None

๐Ÿš€ issueBatchJob(command, job_desc, job_environment=None)

Issues a job with the specified command to the batch system and gives you back a unique job ID number. Iconic ๐Ÿ‘‘

Parameters

  • command (str) โ€” the command to execute somewhere to run the Toil worker process
  • job_desc (toil.job.JobDescription) โ€” the JobDescription for the job being run
  • job_environment (Optional[dict[str, str]]) โ€” a collection of job-specific environment variables to be set on the worker

Returns โ€” a unique job ID number that you can use to reference the newly issued job

Return type โ€” int

๐Ÿ”ฅ getUpdatedBatchJob(maxWait)

Returns info about a job that has updated its status, meaning it stopped running, either successfully or with an error. Each job only shows up here exactly once, so don't expect a repeat ๐Ÿ™ˆ

Jobs killed by killBatchJobs won't be returned here, although they might make this return None earlier than maxWait.

Parameters

  • maxWait (int) โ€” the number of seconds to block, waiting for a result

Returns โ€” If a result is available, it returns UpdatedBatchJobInfo. Otherwise it returns None. wallTime is the number of seconds (a strictly positive float) of wall-clock time the job ran for, or None if this batch system doesn't support tracking wall time.

Return type โ€” Optional[toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo]

๐ŸŒˆ shutdown()

Called at the end of a toil invocation. It should cleanly terminate all worker threads, no drama ๐Ÿงš

Return type โ€” None

๐ŸŽ€ getIssuedBatchJobIDs()

Gets all currently issued jobs.

Returns โ€” A list of jobs (as job ID numbers) that are currently issued, meaning they might be running or waiting to be run. The result is a list, but don't depend on the ordering ๐Ÿ’€

Return type โ€” list[int]

๐Ÿƒโ€โ™€๏ธ getRunningBatchJobIDs()

Gets a map of job ID numbers for jobs that are currently running (not just waiting), along with how long each one has been running, in seconds โญ

Returns โ€” a dictionary with currently running job ID number keys, and how many seconds they've been running as the value

Return type โ€” dict[int, float]

๐Ÿ›‘ killBatchJobs(job_ids)

Kills the given job IDs. After it returns, the killed jobs won't show up in getRunningBatchJobIDs, and they won't be returned from getUpdatedBatchJob either ๐Ÿ“

Parameters

  • jobIDs โ€” list of IDs of jobs to kill
  • job_ids (list[int])

Return type โ€” None

๐Ÿงฉ classmethod add_options(parser)

If this batch system has any command line options, this adds them to the given parser ๐Ÿฆ‹

Parameters

  • parser (Union[argparse.ArgumentParser, argparse._ArgumentGroup])

Return type โ€” None

๐ŸŒธ classmethod setOptions(setOption)

Processes command line or configuration options that are relevant to this batch system ๐Ÿ’œ

Parameters

  • setOption (toil.batchSystems.options.OptionSetter) โ€” a function with the signature setOption(option_name, parsing_function=None, check_function=None, default=None, env=None) that returns nothing. It's used to update the run configuration as a side effect โœจ

Return type โ€” None


โœจ toil.batchSystems.cleanup_support โœจ

Okay, new module, same energy ๐Ÿซถ

๐Ÿง Attributes

  • logger

๐ŸŽ€ Classes

  • BatchSystemCleanupSupport โ€” adds cleanup support when the last running job leaves a node, for batch systems that can't provide it using the backing scheduler ๐ŸŒˆ
  • WorkerCleanupContext โ€” a context manager used by BatchSystemCleanupSupport to implement

๐Ÿ’… Module Contents

  • toil.batchSystems.cleanup_support.logger

๐Ÿฆ‹ class toil.batchSystems.cleanup_support.BatchSystemCleanupSupport(config, maxCores, maxMemory, maxDisk)

Bases: toil.batchSystems.local_support.BatchSystemLocalSupport

Adds cleanup support when the last running job leaves a node, for batch systems that can't provide it using the backing scheduler ๐Ÿ”ฅ

Parameters

  • config (toil.common.Config)
  • maxCores (float)
  • maxMemory (float)
  • maxDisk (int)

๐Ÿ’– classmethod supportsWorkerCleanup()

Whether this batch system supports worker cleanup. Main character energy ๐Ÿ‘‘

It tells you whether this batch system calls BatchSystemSupport.workerCleanup() after the last job for a particular workflow invocation finishes. Quick clarity moment: the word worker means an entire node here, not just a worker process. A worker process can run more than one job sequentially, and more than one concurrent worker process can exist on a worker node for the same workflow. The batch system is said to shut down after the last worker process terminates ๐Ÿ˜ญ

Okay so the return type here is bool (/usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’… yes or no, bestie, nothing in between โœจ

๐ŸŒธ getWorkerContexts() ๐ŸŒธ

Okay this one is giving main character energy ๐Ÿ‘‘. It hands back a list of picklable context manager objects that wrap the worker's work, and they run in order ๐Ÿงš. It's perfect for asking the Toil worker to do stuff in-process, like configuring environment variables, hot-deploying user scripts, or cleaning up a node, stuff that would otherwise need a wrapping "executor" process ๐Ÿซถ.

Return type: list[ContextManager[Any]] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐ŸŽ€


๐Ÿฆ‹ class toil.batchSystems.cleanup_support.WorkerCleanupContext(workerCleanupInfo) ๐Ÿฆ‹

Okay bestie, this is the context manager that BatchSystemCleanupSupport uses to clean up a node once the last worker is done working ๐Ÿงน. It gets wrapped around the worker's work, so it's always there for the clean-up crew ๐Ÿ’–.

Parameters

  • workerCleanupInfo (toil.batchSystems.abstractBatchSystem.WorkerCleanupInfo) ๐ŸŒˆ

Attribute: workerCleanupInfo โœจ

__enter__()

Return type None ๐Ÿ’…

__exit__(type, value, traceback)

Parameters:

  • type (Optional[WorkerCleanupContext.__exit__.type[BaseException]], with BaseException at /usr/share/doc/python3/html/library/exceptions.html#BaseException) ๐Ÿ™ˆ
  • value (Optional[BaseException], with BaseException at /usr/share/doc/python3/html/library/exceptions.html#BaseException) ๐Ÿ™ˆ
  • traceback (Optional[types.TracebackType], with types.TracebackType at /usr/share/doc/python3/html/library/types.html#types.TracebackType) ๐Ÿ™ˆ

Return type None ๐Ÿ’œ


๐Ÿงš toil.batchSystems.contained_executor ๐Ÿงš

Okay this is the executor for running inside a container ๐Ÿณ. It's super useful for the Kubernetes batch system and the TES batch system plugin, so you know it's important ๐Ÿ’–

โœจ Attributes โœจ

  • logger ๐Ÿ“

๐ŸŒˆ Functions ๐ŸŒˆ

  • pack_job(command[, user_script, environment]) โ€” Creates a command that runs the given command in an environment ๐Ÿซง
  • executor() โ€” The main function of the _toil_contained_executor entrypoint ๐Ÿ”ฅ

๐Ÿ’œ Module Contents ๐Ÿ’œ

toil.batchSystems.contained_executor.logger ๐Ÿ“

toil.batchSystems.contained_executor.pack_job(command, user_script=None, environment=None)

Okay so this one builds the command that runs your job inside an environment ๐ŸŒธ It returns a command to run the job, as an argument list that can be run inside the Toil appliance container ๐ŸŽ

Parameters:

  • command (str, with str at /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the worker command to run to run the job ๐Ÿ’…
  • user_script (Optional[toil.resource.Resource]) โ€” the user script that will be loaded before the job is run ๐Ÿ“œ
  • environment (Optional[dict[str, str]], with dict at /usr/share/doc/python3/html/library/stdtypes.html#dict and str at /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the environment variable dict that will be applied before the job is run ๐ŸŒฟ

Return type: list[str] (/usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€

toil.batchSystems.contained_executor.executor()

Okay this is the main function of the _toil_contained_executor entrypoint ๐Ÿงธ It runs inside the Toil container and is responsible for setting up the user script and running the command for the job. That command may in turn invoke the Toil worker entrypoint, so it's like a whole chain of slay ๐Ÿ”—

Return type: None ๐Ÿ’–


๐Ÿ“ toil.batchSystems.gridengine ๐Ÿ“

โœจ Attributes โœจ

  • logger ๐Ÿ“

๐ŸŒท Classes ๐ŸŒท

  • GridEngineBatchSystem โ€” A partial implementation of BatchSystemSupport for batch systems run on a (the table cuts off right there, bestie ๐Ÿ˜ญ)

๐Ÿ’œ Module Contents ๐Ÿ’œ

toil.batchSystems.gridengine.logger ๐Ÿ“

๐Ÿฆ‹ class toil.batchSystems.gridengine.GridEngineBatchSystem(config, maxCores, maxMemory, maxDisk) ๐Ÿฆ‹

Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem ๐ŸŒธ

Okay this is a partial implementation of BatchSystemSupport for batch systems run on a standard HPC cluster ๐Ÿ–ฅ๏ธ By default, auto-deployment is not implemented, so keep that in mind ๐Ÿ‘€

Parameters:

  • config (toil.common.Config) โš™๏ธ
  • maxCores (float, with float at /usr/share/doc/python3/html/library/functions.html#float) ๐Ÿ”ข
  • maxMemory (float, with float at /usr/share/doc/python3/html/library/functions.html#float) ๐Ÿง 
  • maxDisk (float, with float at /usr/share/doc/python3/html/library/functions.html#float) ๐Ÿ’พ

๐Ÿซง class GridEngineThread(newJobsQueue, updatedJobsQueue, killQueue, killedJobsQueue, boss) ๐Ÿซง

Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem.GridEngineThread โœจ

Okay this is the Grid Engine-specific AbstractGridEngineWorker methods, so it's where the Grid Engine magic lives ๐Ÿช„

Parameters:

  • newJobsQueue (queue.Queue, with queue.Queue at /usr/share/doc/python3/html/library/queue.html#queue.Queue) ๐Ÿ“ฅ
  • updatedJobsQueue (queue.Queue, with queue.Queue at /usr/share/doc/python3/html/library/queue.html#queue.Queue) ๐Ÿ”„
  • killQueue (queue.Queue, with queue.Queue at /usr/share/doc/python3/html/library/queue.html#queue.Queue) ๐Ÿ›‘
  • killedJobsQueue (queue.Queue, with queue.Queue at /usr/share/doc/python3/html/library/queue.html#queue.Queue) ๐Ÿ’€
  • boss (AbstractGridEngineBatchSystem) ๐Ÿ‘‘

getRunningJobIDs()

Get a list of running job IDs ๐Ÿƒโ€โ™€๏ธ This one is implementation-specific and gets called by the boss AbstractGridEngineBatchSystem implementation via AbstractGridEngineBatchSystem.getRunningBatchJobIDs() ๐Ÿซถ

Return type: list (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐ŸŽ€

killJob(jobID)

Kill a specific job with the Toil job ID ๐Ÿ”ช This one is implementation-specific and gets called by GridEngineThread.killJobs() ๐Ÿ’…

Parameters:

  • jobID (string) โ€” the Toil job ID ๐Ÿ†”

prepareSubmission(cpu, memory, jobID, command, jobName, job_environment=None, gpus=None)

Okay so this is the prep work for putting together a command-line string that gets submitted to the batch system (via submitJob()) ๐Ÿ“ฆ It's the behind-the-scenes glow-up before the job goes out ๐ŸŒŸ

Param int cpu ๐Ÿงฎ

Param int memory ๐Ÿง 

Param int jobID โ€” the Toil job ID ๐Ÿ†”

Param string subLine โ€” the command line string to be called ๐Ÿ“Ÿ

Param string jobName โ€” the name of the Toil job, to provide metadata to batch systems if desired ๐Ÿท๏ธ

Param dict job_environment โ€” the environment variables to be set on the worker ๐ŸŒฟ

Return type: List[str] (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’–

Parameters:

  • cpu (int, with int at /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿงฎ
  • memory (int, with int at /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿง 
  • jobID (int, with int at /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ†”
  • command (str, with str at /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“Ÿ
  • jobName (str, with str at /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿท๏ธ
  • job_environment (Optional[dict[str, str]], with dict at /usr/share/doc/python3/html/library/stdtypes.html#dict and str at /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒฟ
  • gpus (Optional[int </usr/share/doc/python3/html/library/functions.html#int>]) ๐ŸŽฎ an optional int, and that's the whole vibe.

๐Ÿš€ submitJob(subLine)

This is the wrapper that actually fires off your command-line call, then digs through the output to grab the batch system job ID. ๐ŸŽฏ

  • Param string subLine โ€” the literal command line string that gets called ๐Ÿ“ž
  • Return type string โ€” the batch system job ID, which gets stashed internally ๐Ÿ—‚๏ธ

๐Ÿ” getJobExitCode(sgeJobID)

Grabs the job exit code by checking both qstat and qacct. ๐Ÿ•ต๏ธโ€โ™€๏ธ If the job is still running, it returns None. Your higher-level code should retry on CalledProcessErrorStderr, because if the job just finished, the qacct result might be stale and you don't want to panic over nothing. ๐Ÿ˜ญ

๐Ÿง prepareQsub(cpu, mem, jobID, job_environment=None)

Parameters

  • cpu (int </usr/share/doc/python3/html/library/functions.html#int>)
  • mem (int </usr/share/doc/python3/html/library/functions.html#int>)
  • jobID (int </usr/share/doc/python3/html/library/functions.html#int>)
  • job_environment (Optional[dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str>]])

Return type

list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]

๐Ÿ’ค classmethod getWaitDuration()


โœจ toil.batchSystems.htcondor โœจ

๐Ÿงฉ Attributes

  • logger
  • JobTuple
  • schedd_lock

๐Ÿ›๏ธ Classes

  • HTCondorBatchSystem โ€” the partial BatchSystemSupport implementation, which we'll get into below ๐Ÿ’–

๐Ÿ“ฆ Module Contents

  • toil.batchSystems.htcondor.logger
  • toil.batchSystems.htcondor.JobTuple
  • toil.batchSystems.htcondor.schedd_lock

๐Ÿ class toil.batchSystems.htcondor.HTCondorBatchSystem(config, maxCores, maxMemory, maxDisk)

  • Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem <#toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem>

This is a partial implementation of BatchSystemSupport for batch systems that run on a standard HPC cluster. ๐Ÿ–ฅ๏ธ By default, auto-deployment is not implemented, so don't count on it being there. ๐Ÿ™ˆ

Parameters

  • config (toil.common.Config <#toil.common.Config>)
  • maxCores (float </usr/share/doc/python3/html/library/functions.html#float>)
  • maxMemory (float </usr/share/doc/python3/html/library/functions.html#float>)
  • maxDisk (float </usr/share/doc/python3/html/library/functions.html#float>)

๐Ÿงต class GridEngineThread(newJobsQueue, updatedJobsQueue, killQueue, killedJobsQueue, boss) (nested inside HTCondorBatchSystem)

  • Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem.GridEngineThread <#toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem.GridEngineThread>

This is a thread-of-control class, so basically a little worker thread. ๐Ÿงต You can subclass it safely, but only in a limited way. There are two ways to tell it what to do: pass a callable object to the constructor, or override the run() method in your subclass. ๐Ÿ’…

Parameters

  • newJobsQueue (queue.Queue </usr/share/doc/python3/html/library/queue.html#queue.Queue>)
  • updatedJobsQueue (queue.Queue </usr/share/doc/python3/html/library/queue.html#queue.Queue>)
  • killQueue (queue.Queue </usr/share/doc/python3/html/library/queue.html#queue.Queue>)
  • killedJobsQueue (queue.Queue </usr/share/doc/python3/html/library/queue.html#queue.Queue>)
  • boss (AbstractGridEngineBatchSystem <#toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem>)

๐Ÿช„ createJobs(newJob)

Creates a brand-new job from the attributes you give it. โœจ It's implementation-specific and gets called by GridEngineThread.run().

  • Parameters newJob (JobTuple)
  • Return type bool </usr/share/doc/python3/html/library/functions.html#bool>

๐Ÿงพ prepareSubmission(cpu, memory, disk, jobID, jobName, command, environment)

This is the prep work for putting together the command-line string you'll submit to the batch system (via submitJob()). ๐Ÿ“

  • Param int cpu
  • Param int memory
  • Param int jobID โ€” the Toil job ID ๐Ÿ†”
  • Param string subLine โ€” the command line string to be called
  • Param string jobName โ€” the name of the Toil job, handy for giving batch systems metadata if they want it ๐Ÿท๏ธ
  • Param dict job_environment โ€” the environment variables to be set on the worker ๐ŸŒฟ
  • Return type List[str </usr/share/doc/python3/html/library/stdtypes.html#str>]

Parameters

  • cpu (int </usr/share/doc/python3/html/library/functions.html#int>)
  • memory (int </usr/share/doc/python3/html/library/functions.html#int>)
  • disk (int </usr/share/doc/python3/html/library/functions.html#int>)
  • jobID (int </usr/share/doc/python3/html/library/functions.html#int>)
  • jobName (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • command (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • environment (dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str>])

๐Ÿš€ submitJob(submitObj)

Wrapper that fires off the actual command-line call, then processes the output to get the batch system job ID. ๐ŸŽฏ

  • Param string subLine โ€” the literal command line string to be called ๐Ÿ“ž
  • Return type string โ€” the batch system job ID, which gets stored internally ๐Ÿ—‚๏ธ

๐Ÿ“‹ getRunningJobIDs()

Gets you a list of the running job IDs. ๐Ÿ‘€ It's implementation-specific, and the boss AbstractGridEngineBatchSystem implementation calls it via AbstractGridEngineBatchSystem.getRunningBatchJobIDs().

  • Return type list </usr/share/doc/python3/html/library/stdtypes.html#list>

๐Ÿ›‘ killJob(jobID)

Kills one specific job, identified by its Toil job ID. ๐Ÿ’€ It's implementation-specific and gets called by GridEngineThread.killJobs().

  • Parameters jobID (string) โ€” the Toil job ID

๐Ÿ getJobExitCode(batchJobID)

Returns the job exit code, and possibly an instance of abstractBatchSystem.BatchJobExitReason. ๐ŸŽ€

  • If the job is still running, it returns None. โณ
  • If the job isn't running but the exit code isn't available, you'll get EXIT_STATUS_UNAVAILABLE_VALUE. ๐Ÿคทโ€โ™€๏ธ
  • It's implementation-specific and gets called by GridEngineThread.checkOnJobs().
  • > The exit code will only be 0 if the job affirmatively succeeded. ๐Ÿฅน

Parameters

  • batchjobID (string) โ€” the batch system job ID

๐Ÿ”Œ connectSchedd()

Connects to the HTCondor Schedd and yields a Schedd object. ๐Ÿ”Œ You can only use it inside the context. It handles locking so only one thread is trying to do this at a time, so no tug-of-war. ๐Ÿซถ

โœ‚๏ธ duplicate_quotes(value)

Escapes a string by doubling up every single and double quote in it. ๐Ÿ’œ

This one's for arguments we pass to HTCondor that have to be wrapped in both double and single quote enclosures. Double-wrapped and iconic ๐Ÿ’…โœจ

Parameters

  • value (str, ref /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€

Return type

  • str (ref /usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ getEnvString(overrides) โœจ

Okay so this one builds an environment string that an HTCondor Submit object can use ๐Ÿงš If you want examples of valid strings, check out http://research.cs.wisc.edu/htcondor/manual/current/condor_submit.html#man-condor-submit-environment ๐Ÿ”—

Parameters

  • overrides (dict[str, str]) ๐ŸŒธ
    • dict ref /usr/share/doc/python3/html/library/stdtypes.html#dict
    • str ref /usr/share/doc/python3/html/library/stdtypes.html#str

Return type

  • str (ref /usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ issueBatchJob(command, jobNode, job_environment=None) โœจ

issueBatchJob(command, jobNode, job_environment=None)

Bestie, this one issues a job with the specified command to the batch system and gives you back a unique job ID number ๐Ÿฆ‹

Parameters

  • command (str, ref /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’–
    • The command to execute somewhere to run the Toil worker process.
  • job_desc ๐Ÿซถ
    • The JobDescription for the job being run.
  • job_environment (Optional[dict[str, str]], refs /usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒˆ
    • A collection of job-specific environment variables to be set on the worker.

Returns

  • A unique job ID number that can be used to reference the newly issued job ๐Ÿ‘‘

โœจ toil.batchSystems.kubernetes โœจ

Batch system for running Toil workflows on Kubernetes โ˜๏ธ๐Ÿ’œ

Only useful with network-based job stores, like AWSJobStore. ๐Ÿ™ˆ
Within non-privileged Kubernetes containers, additional Docker containers cannot yet be launched. That functionality will need to wait for user-mode Docker ๐Ÿ’€

Attributes

Here's the squad of attributes ๐Ÿ“

  • logger
  • retryable_kubernetes_errors
  • KeyValuesList

Classes

  • KubernetesBatchSystem, which adds cleanup support when the last running job leaves a node, for batch systems that can't provide it using the backing scheduler ๐ŸŽ€

Functions

  • is_retryable_kubernetes_error(e), a function that determines whether or not Toil should retry or stop given exceptions thrown by Kubernetes ๐Ÿ’…

Module Contents

  • toil.batchSystems.kubernetes.logger
  • toil.batchSystems.kubernetes.retryable_kubernetes_errors: list[type[Exception] | toil.lib.retry.ErrorCondition]
    • list ref /usr/share/doc/python3/html/library/stdtypes.html#list
    • type ref /usr/share/doc/python3/html/library/functions.html#type
    • Exception ref /usr/share/doc/python3/html/library/exceptions.html#Exception
    • toil.lib.retry.ErrorCondition ref #toil.lib.retry.ErrorCondition
  • toil.batchSystems.kubernetes.is_retryable_kubernetes_error(e)

A function that determines whether or not Toil should retry or stop given exceptions thrown by Kubernetes ๐Ÿฆ‹

Parameters

  • e (Exception, ref /usr/share/doc/python3/html/library/exceptions.html#Exception)

Return type

  • bool (ref /usr/share/doc/python3/html/library/functions.html#bool)
  • toil.batchSystems.kubernetes.KeyValuesList
  • class toil.batchSystems.kubernetes.KubernetesBatchSystem(config, maxCores, maxMemory, maxDisk)
class toil.batchSystems.kubernetes.KubernetesBatchSystem(config, maxCores, maxMemory, maxDisk)

Bases: toil.batchSystems.cleanup_support.BatchSystemCleanupSupport (ref #toil.batchSystems.cleanup_support.BatchSystemCleanupSupport)

Adds cleanup support when the last running job leaves a node, for batch systems that can't provide it using the backing scheduler ๐Ÿงน

Parameters

  • config (toil.common.Config, ref #toil.common.Config)
  • maxCores (int, ref /usr/share/doc/python3/html/library/functions.html#int)
  • maxMemory (float, ref /usr/share/doc/python3/html/library/functions.html#float)
  • maxDisk (int, ref /usr/share/doc/python3/html/library/functions.html#int)
  • classmethod supportsAutoDeployment() ๐Ÿš€
    • Whether this batch system supports auto-deployment of the user script itself.
    • If it does, setUserScript() can be invoked to set the resource object representing the user script.
    • > Note to implementors: If your implementation returns True here, it should also override

Return type

  • bool (ref /usr/share/doc/python3/html/library/functions.html#bool)
  • credential_time: datetime.datetime | None = None ๐Ÿ•ฐ๏ธ
    • Refs /usr/share/doc/python3/html/library/datetime.html#datetime.datetime and /usr/share/doc/python3/html/library/constants.html#None
  • namespace: str ๐ŸŒˆ
    • Ref /usr/share/doc/python3/html/library/stdtypes.html#str
  • host_path: str | None ๐ŸŒธ
    • Refs /usr/share/doc/python3/html/library/stdtypes.html#str and /usr/share/doc/python3/html/library/constants.html#None
  • service_account: str | None ๐Ÿงš
    • Refs /usr/share/doc/python3/html/library/stdtypes.html#str and /usr/share/doc/python3/html/library/constants.html#None
  • pod_timeout: float โฑ๏ธ
    • Ref /usr/share/doc/python3/html/library/functions.html#float
  • unique_id ๐Ÿ”‘
  • job_prefix: str = 'Uninferable-toil-Instance of uuid.UUID-' ๐Ÿ“
    • Ref /usr/share/doc/python3/html/library/stdtypes.html#str
  • finished_job_ttl: int = 3600 โญ
    • Ref /usr/share/doc/python3/html/library/functions.html#int
  • user_script: toil.resource.Resource | None = None ๐Ÿ’œ
    • Refs #toil.resource.Resource and /usr/share/doc/python3/html/library/constants.html#None
  • docker_image: str ๐Ÿณ
    • Ref /usr/share/doc/python3/html/library/stdtypes.html#str
  • worker_work_dir: str ๐Ÿ“‚
    • Ref /usr/share/doc/python3/html/library/stdtypes.html#str
  • aws_secret_name: str | None ๐Ÿ”
    • Refs /usr/share/doc/python3/html/library/stdtypes.html#str and /usr/share/doc/python3/html/library/constants.html#None
  • enable_watching: bool ๐Ÿ‘€
    • Ref /usr/share/doc/python3/html/library/functions.html#bool
  • run_id: str = 'toil-Instance of uuid.UUID' ๐Ÿฆ„
    • Ref /usr/share/doc/python3/html/library/stdtypes.html#str
  • resource_sources: list[toil.batchSystems.abstractBatchSystem.ResourcePool] ๐ŸŽ
    • Refs /usr/share/doc/python3/html/library/stdtypes.html#list and #toil.batchSystems.abstractBatchSystem.ResourcePool
  • schedulingThread: threading.Thread ๐Ÿงต
    • Ref /usr/share/doc/python3/html/library/threading.html#threading.Thread
  • class DecoratorWrapper(to_wrap, decorator) ๐ŸŽ€
    • Class to wrap an object so all its methods are decorated.

Parameters

  • to_wrap (Any)
  • decorator (Callable[[Callable[P, Any]], Callable[P, Any]])
  • P
  • __getattr__(name) ๐Ÿ’…
    • Get a member as if we are actually the wrapped object. If it looks callable, we will decorate it.

Parameters

  • name (str, ref /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

  • Any
  • ItemT
  • CovItemT
  • P
  • R
  • setUserScript(userScript) ๐Ÿ“œ
    • Set the user script for this workflow.
    • This method must be called before the first job is issued to this batch system, and only if supportsAutoDeployment() returns True, otherwise it will raise an exception. ๐Ÿšจ

Parameters

  • userScript (toil.resource.Resource, ref #toil.resource.Resource) โ€” the resource object representing the user script or module and the modules it depends on.

Return type

  • None
  • class Placement ๐Ÿงฉ
    • Internal format for pod placement constraints and preferences.
    • required_labels: KeyValuesList = [] ๐Ÿ”’
      • Labels which are required to be present (with these values).
    • desired_labels: KeyValuesList = [] ๐ŸŒŸ
      • Labels which are optional, but preferred to be present (with these values).
  • prohibited_labels: KeyValuesList = []: ๐Ÿšซ these are the labels that are NOT allowed to be on a node, but only when they show up with these exact values. Total no-go vibes ๐Ÿ’€
  • tolerated_taints: KeyValuesList = []: ๐Ÿงช these are the taints that are totally allowed to be on a node (again, only with these values). Pods can hang there, no drama โœจ

set_preemptible(preemptible) ๐Ÿฆ‹

Okay so this one sets the constraints for whether a job is preemptible or not. Lowkey the most important part of the whole thing ๐Ÿ”ฅ

Preemptible jobs can run on preemptible or non-preemptible nodes, and they'll prefer the preemptible nodes if any are available ๐Ÿ’จ

Non-preemptible jobs are not allowed on nodes marked as preemptible. No cap, that's the rule ๐Ÿ™…โ€โ™€๏ธ

It understands the labeling scheme that EKS uses and the taint scheme that GCE uses. The Toil-managed Kubernetes setup mimics at least one of these, so you're covered ๐Ÿซถ

Parameters:

  • preemptible (bool, /usr/share/doc/python3/html/library/functions.html#bool)

Return type: None

apply(pod_spec) ๐Ÿ’…

This one sets the affinity and/or tolerations fields on pod_spec so the pod lands on the right kind of nodes for the constraints we've got. It's giving organized ๐ŸŒธ

Parameters:

  • pod_spec (kubernetes.client.V1PodSpec)

Return type: None

class FakeResponse ๐ŸŽ€

Just one field, bestie:

  • data: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

T ๐Ÿงš

A solo T with no extra notes. Simple, iconic.

issueBatchJob(command, job_desc, job_environment=None) ๐Ÿš€

Issues a job with the specified command to the batch system and gives you back a unique job ID number ๐Ÿ”ข

Parameters:

  • command (str, /usr/share/doc/python3/html/library/stdtypes.html#str): the command to execute somewhere to run the Toil worker process
  • job_desc (toil.job.JobDescription, #toil.job.JobDescription): the JobDescription for the job being run
  • job_environment (Optional[dict[str, str]], /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str): a collection of job-specific environment variables to be set on the worker ๐ŸŒˆ

Returns: a unique job ID number that you can use to reference the newly issued job

Return type: int (/usr/share/doc/python3/html/library/functions.html#int)

getUpdatedBatchJob(maxWait) โฐ

Returns info about a job that has updated its status, meaning it stopped running either successfully or with an error. Each job only shows up exactly once, so no repeats ๐Ÿ‘€

Jobs killed by killBatchJobs won't get returned here, although they may cause None to come back earlier than maxWait.

Parameters:

  • maxWait (float, /usr/share/doc/python3/html/library/functions.html#float): the number of seconds to block, waiting for a result

Returns: if a result is available, it returns UpdatedBatchJobInfo. Otherwise it returns None. wallTime is the number of seconds (a strictly positive float) of wall-clock time the job ran for, or None if this batch system doesn't support tracking wall time โฑ๏ธ

Return type: Optional[toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo] (#toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo)

shutdown() ๐Ÿ›‘

Called at the completion of a toil invocation. It should cleanly terminate all worker threads, so it's giving tidy exit energy โœจ

Return type: None

getIssuedBatchJobIDs() ๐Ÿ“‹

Gets all currently issued jobs.

Returns: a list of jobs (as job ID numbers) that are currently issued. They might be running, or they might be waiting to run. Even though the result is a list, don't depend on the ordering ๐Ÿ™ˆ

Return type: list[int] (/usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/functions.html#int)

getRunningBatchJobIDs() ๐Ÿƒโ€โ™€๏ธ

Gets a map of job ID numbers for jobs that are currently running (not just waiting), along with how long each one has been running, in seconds ๐Ÿ•ฐ๏ธ

Returns: a dictionary with currently running job ID number keys, and how many seconds they've been running as the value

Return type: dict[int, float] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/functions.html#float)

killBatchJobs(jobIDs) ๐Ÿ’€

Kills the given job IDs. After it returns, the killed jobs won't appear in the results of getRunningBatchJobIDs, and they won't be returned from getUpdatedBatchJob either. Bye bye ๐Ÿ‘‹

Parameters:

  • jobIDs (list[int], /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/functions.html#int): list of IDs of jobs to kill

Return type: None

classmethod get_default_kubernetes_owner() ๐Ÿง‘โ€๐Ÿ’ป

Gets the default Kubernetes-acceptable username string to tack onto jobs.

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

class KubernetesConfig ๐ŸŒˆ

Bases: Protocol

This is a type-enforcing protocol for Toil configs that have the extra Kubernetes batch system fields. Main character energy ๐Ÿ‘‘

TODO: Until MyPY lets protocols inherit from non-protocols, we'll have to manually enforce that this also has to be a Config. Not ideal, but we're working on it ๐Ÿซ 

Fields:

  • kubernetes_host_path: str | None (/usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/constants.html#None)
  • kubernetes_owner: str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • kubernetes_service_account: str | None (/usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/constants.html#None)
  • kubernetes_pod_timeout: float (/usr/share/doc/python3/html/library/functions.html#float)

classmethod add_options(parser) ๐Ÿง

If this batch system provides any command line options, this adds them to the given parser.

Parameters:

  • parser (Union[argparse.ArgumentParser, argparse._ArgumentGroup], /usr/share/doc/python3/html/library/argparse.html#argparse.ArgumentParser)

Return type: None

OptionType ๐Ÿซถ

Just the name, no description here.

classmethod setOptions(setOption) โš™๏ธ

Processes command line or configuration options relevant to this batch system.

Parameters:

  • setOption (toil.batchSystems.options.OptionSetter, #toil.batchSystems.options.OptionSetter): a function with the signature setOption(option_name, parsing_function=None, check_function=None, default=None, env=None) that returns nothing. It updates the run configuration as a side effect ๐Ÿช„

Return type: None


toil.batchSystems.local_support ๐ŸŒธ

Attributes

  • logger ๐Ÿชต

Classes

  • BatchSystemLocalSupport: adds a local queue for helper jobs, useful for CWL & others ๐Ÿ’–

Module Contents

toil.batchSystems.local_support.logger

class toil.batchSystems.local_support.BatchSystemLocalSupport(config, maxCores, maxMemory, maxDisk) โœจ

Bases: toil.batchSystems.abstractBatchSystem.BatchSystemSupport (#toil.batchSystems.abstractBatchSystem.BatchSystemSupport)

Adds a local queue for helper jobs, useful for CWL & others. It's the helper-job bestie ๐Ÿงš

Parameters:

  • config (toil.common.Config, #toil.common.Config)
  • maxCores (float, /usr/share/doc/python3/html/library/functions.html#float)
  • maxMemory (float, /usr/share/doc/python3/html/library/functions.html#float)
  • maxDisk (int, /usr/share/doc/python3/html/library/functions.html#int)

Attribute localBatch: typed as toil.batchSystems.singleMachine.SingleMachineBatchSystem (#toil.batchSystems.singleMachine.SingleMachineBatchSystem) ๐Ÿ’œ

handleLocalJob(command, jobDesc) ๐Ÿฆ‹

To be called by issueBatchJob. Ngl, it's the handoff that keeps things moving ๐Ÿ”ฅ

Returns the jobID if the jobDesc got submitted to the local queue, and None if it didn't ๐Ÿ’–โœจ

Parameters

  • command (str) ๐ŸŽ€
  • jobDesc (toil.job.JobDescription) ๐Ÿฆ‹

Return type: Optional[int]

๐Ÿ’… killLocalJobs(jobIDs)

Will kill all local jobs that match the provided jobIDs. It gets called by killBatchJobs, so you won't usually be calling it yourself ๐Ÿซถ

Parameters

  • jobIDs (list[int]) ๐ŸŒธ

Return type: None

๐Ÿงš getIssuedLocalJobIDs()

Called by getIssuedBatchJobIDs. It's the local side of that lookup, so it's giving teamwork ๐Ÿค

Return type: list[int]

๐ŸŒˆ getRunningLocalJobIDs()

Called by getRunningBatchJobIDs(). Okay so this one hands back a dict mapping each running job's int ID to a float ๐Ÿ‘‘

Return type: dict[int, float]

โœจ getUpdatedLocalJob(maxWait)

Called by getUpdatedBatchJob(). Literally the "what's new with my jobs?" check ๐Ÿ‘€

Parameters

  • maxWait (int) โญ

Return type: Optional[toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo]

๐Ÿ”ฅ getNextJobID()

Must be used to get job IDs so that the local and batch jobs do not conflict. Do not make up your own IDs, bestie, it will get messy ๐Ÿ’€

Return type: int

๐Ÿฆ‹ shutdownLocal()

Called from shutdown(). Time to clean up and log off ๐ŸŒ™

Return type: None


๐ŸŒธ toil.batchSystems.lsf ๐ŸŒธ

Attributes

  • logger ๐Ÿช„

Classes

  • LSFBatchSystem โ€” a partial implementation of BatchSystemSupport for batch systems run on a standard HPC cluster ๐Ÿ’œ

Module Contents

toil.batchSystems.lsf.logger

โœจ class toil.batchSystems.lsf.LSFBatchSystem(config, maxCores, maxMemory, maxDisk)

Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem

This is a partial implementation of BatchSystemSupport for batch systems run on a standard HPC cluster. By default, auto-deployment is not implemented, so keep that in mind ๐Ÿ™ˆ

Parameters

  • config (toil.common.Config) ๐ŸŽ€
  • maxCores (float) ๐ŸŽ€
  • maxMemory (float) ๐ŸŽ€
  • maxDisk (float) ๐ŸŽ€

๐Ÿ’– class GridEngineThread(newJobsQueue, updatedJobsQueue, killQueue, killedJobsQueue, boss)

Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem.GridEngineThread

These are the LSF-specific GridEngineThread methods, so this is where the LSF magic happens โœจ

Parameters

  • newJobsQueue (queue.Queue) ๐Ÿฆ‹
  • updatedJobsQueue (queue.Queue) ๐Ÿฆ‹
  • killQueue (queue.Queue) ๐Ÿฆ‹
  • killedJobsQueue (queue.Queue) ๐Ÿฆ‹
  • boss (AbstractGridEngineBatchSystem) ๐Ÿ‘‘

๐ŸŒŸ getRunningJobIDs()

Gets a list of running job IDs. This one is implementation-specific, and the boss AbstractGridEngineBatchSystem implementation calls it through AbstractGridEngineBatchSystem.getRunningBatchJobIDs().

Return type: list

๐Ÿซง fallbackRunningJobIDs(currentjobs)

๐Ÿ—ก๏ธ killJob(jobID)

Kills one specific job using its Toil job ID. This is implementation-specific, and GridEngineThread.killJobs() calls it ๐Ÿ’€

Parameters

  • jobID (string) โ€” the Toil job ID ๐Ÿ“

๐Ÿชฉ prepareSubmission(cpu, memory, jobID, command, jobName, job_environment=None, gpus=None)

This is the prep work. It puts together the command-line string that gets handed to the batch system (via submitJob()) ๐Ÿง

  • int cpu ๐ŸŒธ
  • int memory ๐ŸŒธ
  • int jobID โ€” the Toil job ID ๐ŸŒธ
  • string subLine โ€” the command-line string to be called ๐ŸŒธ
  • string jobName โ€” the name of the Toil job, which gives batch systems metadata if they want it ๐ŸŒธ
  • dict job_environment โ€” the environment variables to set on the worker ๐ŸŒธ

Parameters

  • cpu (int) ๐ŸŽ€
  • memory (int) ๐ŸŽ€
  • jobID (int) ๐ŸŽ€
  • command (str) ๐ŸŽ€
  • jobName (str) ๐ŸŽ€
  • job_environment (Optional[dict[str, str]]) ๐ŸŽ€
  • gpus (Optional[int]) ๐ŸŽ€

Return type: List[str]

๐Ÿš€ submitJob(subLine)

This is the wrapper that submits the actual command-line call, then processes the output to get the batch system job ID ๐Ÿ“ฎ

Parameters

  • subLine (string) โ€” the literal command-line string to be called ๐Ÿ’œ

Return type: string โ€” the batch system job ID, which gets stored internally ๐Ÿ”’

๐ŸŒ™ coalesce_job_exit_codes(batch_job_id_list)

Returns exit codes and possibly exit reasons for a list of jobs, or None if they're still running ๐Ÿƒโ€โ™€๏ธ It's called by GridEngineThread.checkOnJobs().

The default version falls back on self.getJobExitCode and polls each job one by one.

Parameters

  • batch_job_id_list (string) โ€” the list of batch system job IDs ๐ŸŒท

Return type: list

๐Ÿ getJobExitCode(lsfJobID)

Returns the job's exit code and possibly an instance of abstractBatchSystem.BatchJobExitReason.

  • It returns None if the job is still running โณ
  • If the job isn't running but the exit code isn't available, you'll get EXIT_STATUS_UNAVAILABLE_VALUE ๐Ÿซ 
  • The exit code will only be 0 if the job affirmatively succeeded ๐ŸŽ‰

This is implementation-specific, and GridEngineThread.checkOnJobs() calls it.

Parameters

  • batchjobID (string) โ€” the batch system job ID ๐Ÿ’

Okay so this next batch is all about the LSF helpers, and bestie, the return types are giving union energy ๐Ÿ’…๐Ÿ”ฅ

Return type (this one is a whole mood โœจ)

Union[int, tuple[int, Optional[toil.batchSystems.abstractBatchSystem.BatchJobExitReason]], None]

๐Ÿงš parse_bjobs_record(bjobs_record, job)

These are helper functions for getJobExitCode and to parse the bjobs status record, so they're doing the behind-the-scenes work ๐Ÿซถ

Parameters

  • bjobs_record (dict) ๐Ÿ’œ
  • job (int) ๐ŸŒธ

Return type

Union[int, tuple[int, Optional[toil.batchSystems.abstractBatchSystem.BatchJobExitReason]], None]

๐Ÿฆ‹ getJobExitCodeBACCT(job)

Return type

Union[int, tuple[int, Optional[toil.batchSystems.abstractBatchSystem.BatchJobExitReason]], None]

๐ŸŒˆ fallbackGetJobExitCode(job)

This is the backup plan, and it's giving safety net ๐Ÿงท

Return type

Union[int, tuple[int, Optional[toil.batchSystems.abstractBatchSystem.BatchJobExitReason]], None]

๐ŸŽ€ prepareBsub(cpu, mem, jobID)

This one makes a bsub commandline for you to execute, and it's literally so pretty โœจ

params:

  • cpu: number of cores needed ๐Ÿ’–
  • mem: number of bytes of memory needed ๐Ÿง 
  • jobID: ID number of the job ๐Ÿชช

Parameters

  • cpu (int)
  • mem (int)
  • jobID (int)

Return type

list[str]

๐Ÿ“ parseBjobs(bjobs_output_str)

This one parses records out of bjobs json type output, no cap ๐Ÿงƒ

Params

  • bjobs_output_str: stdout of bjobs json type output ๐Ÿ–จ๏ธ

๐Ÿ’… parseMaxMem(jobID)

This one parses the maximum memory from the job, so it's your memory detective ๐Ÿ•ต๏ธโ€โ™€๏ธ

Parameters

  • jobID: ID number of the job ๐Ÿ”ข

โญ getWaitDuration()

Lowkey the sweetest one: we give LSF a second to catch its breath, in seconds ๐Ÿฅน๐Ÿซง


๐Ÿ‘‘ toil.batchSystems.lsfHelper

Attributes

This module has a bunch of attributes, and the page lists just their names with no values next to them, so here they are, iykyk ๐Ÿ’œ

  • LSB_PARAMS_FILENAME ๐Ÿ“
  • LSF_CONF_FILENAME ๐Ÿ“
  • LSF_CONF_ENV ๐ŸŒฟ
  • DEFAULT_LSF_UNITS ๐Ÿ“
  • DEFAULT_RESOURCE_UNITS ๐Ÿ“
  • LSF_JSON_OUTPUT_MIN_VERSION ๐Ÿ”–
  • logger ๐Ÿ“

โœจ Functions โœจ

okay so this table is the cheat sheet ๐Ÿ’… here's every function, bestie:

  • find(basedir, string) โ€” walks basedir and returns all files matching string ๐Ÿ”
  • find_first_match(basedir, string) โ€” returns the first file that matches string, starting from basedir ๐Ÿฆ‹
  • get_conf_file(filename, env) โ€” no blurb for this one ๐Ÿ™ˆ
  • apply_conf_file(fn, conf_filename) โ€” no blurb for this one either
  • per_core_reserve_from_stream(stream) โ€” no blurb, it just exists ๐ŸŒธ
  • get_lsf_units_from_stream(stream) โ€” also no blurb ๐Ÿซถ
  • tokenize_conf_stream(conf_handle) โ€” converts the key=val pairs in an LSF config stream into tuples of tokens ๐Ÿงš
  • apply_bparams(fn) โ€” applies fn to each line of bparams and returns the result โœจ
  • apply_lsadmin(fn) โ€” applies fn to each line of lsadmin and returns the result โœจ
  • get_lsf_units([resource]) โ€” checks if we can find LSF_UNITS_FOR_LIMITS in lsadmin and lsf.conf ๐Ÿ’œ
  • parse_mem_and_cmd_from_output(output) โ€” uses regex to find "MAX MEM" and "Command" inside an output ๐Ÿ’€
  • get_lsf_version() โ€” gets the current LSF version ๐ŸŒˆ
  • check_lsf_json_output_supported() โ€” checks if the current LSF system supports bjobs json output ๐Ÿ‘‘
  • parse_memory(mem) โ€” parses the memory parameter ๐Ÿ“
  • per_core_reservation() โ€” returns True if the cluster is configured for reservations to be per core, ๐ŸŽ€

โœจ Module Contents โœจ

okay the module contents are where it's at, we're getting the full details ๐Ÿ”ฅ these constants are the main character energy of this module:

toil.batchSystems.lsfHelper.LSB_PARAMS_FILENAME = 'lsb.params'
toil.batchSystems.lsfHelper.LSF_CONF_FILENAME = 'lsf.conf'
toil.batchSystems.lsfHelper.LSF_CONF_ENV = ['LSF_CONFDIR', 'LSF_ENVDIR']
toil.batchSystems.lsfHelper.DEFAULT_LSF_UNITS = 'KB'
toil.batchSystems.lsfHelper.DEFAULT_RESOURCE_UNITS = 'MB'
toil.batchSystems.lsfHelper.LSF_JSON_OUTPUT_MIN_VERSION = '10.1.0.2'
toil.batchSystems.lsfHelper.logger

Now the functions, one by one ๐Ÿ’–

toil.batchSystems.lsfHelper.find(basedir, string)

walk basedir and return all files matching string ๐Ÿ”

toil.batchSystems.lsfHelper.find_first_match(basedir, string)

return the first file that matches string starting from basedir ๐Ÿฆ‹

toil.batchSystems.lsfHelper.get_conf_file(filename, env)

toil.batchSystems.lsfHelper.apply_conf_file(fn, conf_filename)

toil.batchSystems.lsfHelper.per_core_reserve_from_stream(stream)

toil.batchSystems.lsfHelper.get_lsf_units_from_stream(stream)

toil.batchSystems.lsfHelper.tokenize_conf_stream(conf_handle)

convert the key=val pairs in a LSF config stream to tuples of tokens ๐Ÿงš

toil.batchSystems.lsfHelper.apply_bparams(fn)

apply fn to each line of bparams, returning the result โœจ

toil.batchSystems.lsfHelper.apply_lsadmin(fn)

apply fn to each line of lsadmin, returning the result โœจ

toil.batchSystems.lsfHelper.get_lsf_units(resource=False)

okay this one's a whole vibe ๐Ÿ’œ it checks if we can find LSF_UNITS_FOR_LIMITS in lsadmin and lsf.conf files, and it prefers the value in bparams, then lsadmin, then the lsf.conf file.

Parameters

  • resource (bool, see /usr/share/doc/python3/html/library/functions.html#bool)

Return type

  • str, see /usr/share/doc/python3/html/library/stdtypes.html#str

toil.batchSystems.lsfHelper.parse_mem_and_cmd_from_output(output)

Use regex to find "MAX MEM" and "Command" inside of an output. ๐Ÿ’€

Parameters

  • output (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.batchSystems.lsfHelper.get_lsf_version()

Get current LSF version ๐ŸŒˆ

toil.batchSystems.lsfHelper.check_lsf_json_output_supported()

Check if the current LSF system supports bjobs json output. ๐Ÿ‘‘

toil.batchSystems.lsfHelper.parse_memory(mem)

Parse memory parameter. ๐Ÿ“

Parameters

  • mem (float, see /usr/share/doc/python3/html/library/functions.html#float)

Return type

  • str, see /usr/share/doc/python3/html/library/stdtypes.html#str

toil.batchSystems.lsfHelper.per_core_reservation()

returns True if the cluster is configured for reservations to be per core, False if it is per job ๐ŸŽ€


โœจ toil.batchSystems.mesos โœจ

okay we're moving on to the mesos bit ๐Ÿฆ‹

Submodules

  • toil.batchSystems.mesos.batchSystem

โœจ toil.batchSystems.mesos.batchSystem โœจ

Attributes

  • log โ€” no value listed for this one ๐Ÿ™ˆ

Classes

  • MesosBatchSystem โ€” A Toil batch system implementation that uses Apache Mesos to distribute toil jobs as Mesos ๐ŸŒธ

Module Contents

The attribute first, bestie:

toil.batchSystems.mesos.batchSystem.log

Now the class, and it's giving full main character ๐Ÿ‘‘

class toil.batchSystems.mesos.batchSystem.MesosBatchSystem(config, maxCores, maxMemory, maxDisk)

Bases: toil.batchSystems.local_support.BatchSystemLocalSupport, toil.batchSystems.abstractBatchSystem.AbstractScalableBatchSystem, pymesos.Scheduler

A Toil batch system implementation that uses Apache Mesos to distribute toil jobs as Mesos tasks over a cluster of agent nodes. A Mesos framework has a scheduler and an executor. This class is the scheduler, and it's typically run on the master node that also runs the Mesos master process, which it talks to through a driver component. The executor is a separate class that runs on each agent node and talks to the Mesos agent process through its own driver object. The scheduler can also run on a separate node from the master, which is somewhat ambiguously called the driver node ๐Ÿซถ

Parameters

  • config (toil.common.Config)
  • maxCores (float, see /usr/share/doc/python3/html/library/functions.html#float)
  • maxMemory (float, /usr/share/doc/python3/html/library/functions.html#float) ๐Ÿง  this one's the memory cap for a job
  • maxDisk (int, /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ’พ and this one's the disk cap

๐Ÿ’… classmethod supportsAutoDeployment()

Okay so this tells you whether the batch system can auto-deploy the user script itself ๐Ÿš€ If it can, you're allowed to call setUserScript() to hand over the resource object for the user script โœจ

Note to implementors: If your implementation returns True here, it should also override

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿฆ‹ classmethod supportsWorkerCleanup()

This one checks whether the batch system calls BatchSystemSupport.workerCleanup() after the last job for a workflow run finishes ๐Ÿงน Quick vibe check on terms: a worker means a whole node, not just a worker process. A worker process can run several jobs one after another, and more than one worker process can be running on the same node for the same workflow ๐ŸŒธ The batch system is said to shut down once the last worker process terminates.

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿงš class ExecutorInfo(nodeAddress, agentId, nodeInfo, lastSeen)

Parameters:

  • nodeAddress (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • agentId (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • nodeInfo (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • lastSeen (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Attributes: nodeAddress, agentId, nodeInfo, lastSeen ๐Ÿ’œ

๐ŸŒˆ userScript = None

Type: toil.resource.Resource

๐Ÿ“ Class attributes

These are all just sitting there on the class, no descriptions, just vibes:

  • jobQueues
  • mesos_endpoint
  • mesos_name
  • mesos_timeout = 60
  • killedJobIds
  • killJobIds
  • intendedKill
  • hostToJobIDs
  • nodeFilter = []
  • runningJobMap
  • taskResources
  • updatedJobsQueue
  • driver = None
  • frameworkId = None
  • executors
  • agentsByID
  • nonPreemptibleNodes
  • executor
  • lastTimeOfferLogged = 0
  • logPeriod = 30
  • ignoredNodes

๐ŸŽ€ setUserScript(userScript)

Set the user script for this workflow โœจ This has to be called before the first job is issued to this batch system, and it only works if supportsAutoDeployment() returns True. Otherwise it'll raise an exception ๐Ÿ’€

Parameters:

  • userScript (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the resource object representing the user script or module, plus the modules it depends on

Return type: None

๐Ÿ›‘ ignoreNode(nodeAddress)

This tells the batch system to stop sending jobs to a node ๐Ÿ™…โ€โ™€๏ธ It's used in autoscaling, when the autoscaler is ready to kill a node but jobs are still running on it. Ignoring it lets the node get terminated once its current jobs wrap up.

Parameters:

  • nodeAddress (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” IP address of the node to ignore

Return type: None

โœ… unignoreNode(nodeAddress)

Stop ignoring this address ๐Ÿซถ This is presumably what happens after a node with this address has been terminated. It leaves room for a brand-new node to pop up with the same address as one that got terminated.

Parameters:

  • nodeAddress (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None

๐Ÿš€ issueBatchJob(command, jobNode, job_environment=None)

This issues the command you give it and returns a unique jobID ๐ŸŽฏ command is the string to run. The memory argument is an int for how many bytes the job needs, and cores is how many CPUs the job needs. The error-file is the path where any std-err/std-out gets stashed ๐Ÿ—‚๏ธ

Parameters:

  • command (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • jobNode (toil.job.JobDescription)
  • job_environment (Optional[dict[str, str]], with /usr/share/doc/python3/html/library/stdtypes.html#dict for the dict and /usr/share/doc/python3/html/library/stdtypes.html#str for both str parts)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

โ˜ ๏ธ killBatchJobs(jobIDs)

Kills the given job IDs, no mercy ๐Ÿ’… Once it returns, the killed jobs won't show up in getRunningBatchJobIDs anymore, and they won't come back from getUpdatedBatchJob either.

Parameters:

  • jobIDs โ€” list of IDs of the jobs to kill

๐Ÿ“‹ getIssuedBatchJobIDs()

Gets all the jobs that are currently issued ๐Ÿ“

Returns: a list of jobs (as job ID numbers) that are currently issued. They might be running, or just waiting to run. Even though it's a list, don't depend on the ordering, bestie ๐Ÿ™ˆ

๐Ÿƒ getRunningBatchJobIDs()

Gets a map of the job ID numbers that are currently running (not just waiting) along with how long each one has been running, in seconds โฑ๏ธ

Returns: a dictionary with the currently running job ID numbers as keys, and how many seconds they've been running as the values.

๐ŸŽ getUpdatedBatchJob(maxWait)

Returns info about a job that has updated its status, meaning it stopped running either successfully or with an error ๐Ÿ Each job only gets returned exactly once, so no double-dipping.

It doesn't return info for jobs killed by killBatchJobs, though those might cause None to come back sooner than maxWait.

Parameters:

  • maxWait โ€” the number of seconds to block while waiting for a result

Returns: if a result is available, you get an UpdatedBatchJobInfo back. Otherwise you get None. The wallTime is the number of seconds (a strictly positive float) of wall-clock time the job ran for, or None if this batch system doesn't support tracking wall time โณ

๐Ÿ” nodeInUse(nodeIP)

This checks whether a worker node is running any tasks ๐Ÿ‘€ If the node doesn't exist, it should simply return False.

Parameters:

  • nodeIP (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the worker node's private IP address

Returns: True if the worker node has been issued any tasks, otherwise False.

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

โฒ๏ธ getWaitDuration()

Gets the wait period (a floating point number, in seconds) between checks for missing or overlong jobs ๐Ÿ•ฐ๏ธ

๐ŸŒ™ shutdown()

Called at the end of a toil invocation ๐ŸŒ™ It should cleanly terminate all worker threads, no messy leftovers.

Return type: None

๐Ÿค registered(driver, frameworkId, masterInfo)

Invoked when the scheduler successfully registers with a Mesos master ๐ŸŽ‰

๐Ÿšจ error(driver, message)

Invoked when Mesos reports an unrecoverable error ๐Ÿ˜ญ

๐ŸŽŸ๏ธ resourceOffers(driver, offers)

Invoked when resources have been offered to this framework ๐ŸŽ

๐Ÿ“ฌ statusUpdate(driver, update)

Invoked when the status of a task changes. For example, an agent gets lost and takes its task with it, or a task finishes and an executor sends a status update about it, etc. โœจ

Important: returning from this callback acknowledges receipt of the status update! If the scheduler aborts during this callback (or the process exits), another status update will be delivered. Just know that this is currently not true if the agent sending the status update gets lost or fails during that time ๐Ÿ’€

๐Ÿ’Œ frameworkMessage(driver, executorId, agentId, message)

Invoked when an executor sends a message ๐Ÿ’ฌ

๐Ÿ”Ž getNodes(preemptible=None, timeout=None)

Returns all nodes that match:

  • preemptible status (None includes all)
  • timeout period (seen within the last # seconds, or None for all)

Parameters:

  • preemptible (Optional[bool], /usr/share/doc/python3/html/library/functions.html#bool)
  • timeout (Optional[int], /usr/share/doc/python3/html/library/functions.html#int)

๐Ÿ’– reregistered(driver, masterInfo)

This one fires when the scheduler reconnects to a newly elected Mesos master, so it's basically Toil going "wait, we're back?" ๐Ÿ‘‘

๐ŸŒธ executorLost(driver, executorId, agentId, status)

Invoked when an executor has exited or terminated abnormally. Honestly it's giving "something went very wrong" ๐Ÿ˜ญ

๐Ÿฆ‹ get_default_mesos_endpoint()

Classmethod. This grabs the default IP/hostname and port that Toil will look for Mesos at ๐Ÿงš

Return type: str

โœจ add_options(parser)

Classmethod. If this batch system has any command line options, it tosses them into the parser you give it ๐ŸŽ€

Parameters:

  • parser (Union[argparse.ArgumentParser, argparse._ArgumentGroup])

Return type: None

๐Ÿ’… setOptions(setOption)

Classmethod. Processes the command line or configuration options that matter to this batch system ๐Ÿ’œ

Parameters:

  • setOption (toil.batchSystems.options.OptionSetter) โ€” basically a helper function with the signature setOption(option_name, parsing_function=None, check_function=None, default=None, env=None). It returns nothing and quietly updates the run configuration as a side effect ๐Ÿ”ฅ

๐Ÿงš toil.batchSystems.mesos.conftest

Attributes

  • collect_ignore

Module Contents

toil.batchSystems.mesos.conftest.collect_ignore = []

๐ŸŒˆ toil.batchSystems.mesos.executor

Attributes

  • log

Classes

  • MesosExecutor โ€” Part of Toil's Mesos framework. It runs on a Mesos agent, and a Toil job gets passed to it through the task.data field and launched via call(toil.command) โœจ

Functions

  • main()

Module Contents

toil.batchSystems.mesos.executor.log
class toil.batchSystems.mesos.executor.MesosExecutor

Bases: pymesos.Executor

This is the star of the show: Toil's Mesos framework piece that runs on a Mesos agent. A Toil job is handed over via the task.data field, then launched via call(toil.command) ๐Ÿ‘‘

Attributes:

  • popenLock
  • runningTasks
  • workerCleanupInfo = None
  • address = None
  • id = None

Methods:

๐Ÿฆ‹ registered(driver, executorInfo, frameworkInfo, agentInfo)

Invoked once the executor driver has successfully connected with Mesos. We're in! ๐ŸŽ‰

๐ŸŒธ reregistered(driver, agentInfo)

Invoked when the executor re-registers with a restarted agent ๐Ÿซถ

๐Ÿ’– disconnected(driver)

Invoked when the executor becomes "disconnected" from the agent. This happens when the agent is restarting, like during an upgrade ๐Ÿ˜ญ

๐Ÿ’… killTask(driver, taskId)

Kills the parent task process along with all of its spawned children. Bye bye, everything ๐Ÿ’€

๐Ÿ”ฅ shutdown(driver)

๐Ÿšจ error(driver, message)

Invoked when a fatal error has occurred with the executor and/or the executor driver. Not it ๐Ÿ’€

๐Ÿงš launchTask(driver, task)

Invoked by SchedulerDriver when a Mesos task should be launched by this executor ๐ŸŒˆ

๐ŸŽ€ frameworkMessage(driver, message)

Invoked when a framework message has arrived for this executor ๐Ÿ’œ

toil.batchSystems.mesos.executor.main()

๐Ÿฆ‹ toil.batchSystems.mesos.test

Attributes

  • log

Classes

  • MesosTestSupport โ€” A mixin for test cases that need a running Mesos master and agent on the local host ๐Ÿ“

Package Contents

toil.batchSystems.mesos.test.log
class toil.batchSystems.mesos.test.MesosTestSupport

A mixin for test cases that need a running Mesos master and agent on the local host. It's the setup crew for your tests ๐ŸŽฌ

๐Ÿ’ซ wait_for_master()

๐ŸŒŸ Nested class: MesosThread(numCores)

Bases: toil.lib.threading.ExceptionalThread

This is a thread whose join() method re-raises exceptions that were raised during run(). join() is idempotent, but the exception only gets re-raised on the first call to join() that successfully joins the thread. If join() times out, no exception gets re-raised, even if one might already have happened inside run(). ๐Ÿ˜ญ

When you subclass this thread, override tryRun() instead of run(). Don't say I didn't warn you ๐Ÿ™ˆ

>>> def f():
...     assert 0
>>> t = ExceptionalThread(target=f)
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

>>> class MyThread(ExceptionalThread):
...     def tryRun( self ):
...         assert 0
>>> t = MyThread()
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

Attributes:

  • lock
  • numCores

Methods:

๐Ÿฅบ mesosCommand()

Abstract method. Subclasses have to fill this in ๐Ÿซ 

๐Ÿง  tryRun()

๐Ÿ” findMesosBinary(names)

๐ŸŒŸ Nested class: MesosMasterThread(numCores)

Bases: MesosThread

This is a thread whose join() method re-raises exceptions that were raised during run(). join() is idempotent, but the exception only gets re-raised on the first call to join() that successfully joins the thread. If join() times out, no exception gets re-raised, even if one might already have happened inside run(). ๐Ÿ˜ญ

When you subclass this thread, override tryRun() instead of run(). Don't say I didn't warn you ๐Ÿ™ˆ

>>> def f():
...     assert 0
>>> t = ExceptionalThread(target=f)
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

>>> class MyThread(ExceptionalThread):
...     def tryRun( self ):
...         assert 0
>>> t = MyThread()
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

Methods:

๐Ÿ‘‘ mesosCommand()

๐ŸŒŸ Nested class: MesosAgentThread(numCores)

Bases: MesosThread

This is a thread whose join() method re-raises exceptions that were raised during run(). join() is idempotent, but the exception only gets re-raised on the first call to join() that successfully joins the thread. If join() times out, no exception gets re-raised, even if one might already have happened inside run(). ๐Ÿ˜ญ

When you subclass this thread, override tryRun() instead of run(). Don't say I didn't warn you ๐Ÿ™ˆ

>>> def f():
...     assert 0
>>> t = ExceptionalThread(target=f)
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

>>> class MyThread(ExceptionalThread):
...     def tryRun( self ):
...         assert 0
>>> t = MyThread()
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

Methods:

๐Ÿซถ mesosCommand()

๐ŸŒธ toil.batchSystems.mesos

๐Ÿฆ‹ Classes

okay so the mesos module has a whole squad of classes ๐Ÿ’… (the chart is a bit messy, so here's the lineup):

  • TaskData: a tuple-based class for task info ๐ŸŽ€
  • JobQueue: the job line-up, sorted by type ๐Ÿซถ
  • MesosShape: represents a job or a node's "shape", aka how much memory, cores, disk and wall-time it needs or gets ๐Ÿ”ฅ
  • ToilJob: another tuple-based class, for the job itself ๐Ÿงš

โœจ Package Contents โœจ

๐Ÿง class toil.batchSystems.mesos.TaskData

Bases: tuple (see /usr/share/doc/python3/html/library/stdtypes.html#tuple)

Its attributes are:

  • startTime
  • agentID
  • agentIP
  • executorID
  • memory
  • cores

๐Ÿ“ class toil.batchSystems.mesos.JobQueue

Its attributes are:

  • queues
  • sortedTypes = []
  • jobLock

And its methods are:

  • insertJob(job, jobType)
  • jobIDs()
  • nextJobOfType(jobType)
  • typeEmpty(jobType)

๐Ÿ’œ class toil.batchSystems.mesos.MesosShape

class toil.batchSystems.mesos.MesosShape(wallTime, memory, cores, disk,
preemptible)

Bases: toil.provisioners.abstractProvisioner.Shape (see #toil.provisioners.abstractProvisioner.Shape)

Represents a job or a node's "shape", in terms of the dimensions of memory, cores, disk and wall-time allocation. Main character energy ๐Ÿ‘‘

The wallTime attribute stores the number of seconds of a node allocation, e.g. 3600 for AWS. FIXME: and for jobs? ๐Ÿ™ˆ

The memory and disk attributes store the number of bytes required by a job (or provided by a node) in RAM or on disk (SSD or HDD), respectively. ๐Ÿ’–

Parameters

  • wallTime (Union[int, float])
  • memory (int)
  • cores (Union[int, float])
  • disk (int)
  • preemptible (bool)

๐Ÿซง __gt__(other)

This one is inverted ๐Ÿ™ƒ It returns True if self is less than other, else it returns False.

The reason: jobTypes are sorted in decreasing order, and that was done on purpose so that expensive jobs get priority. Iconic. ๐Ÿ‘‘

๐ŸŒˆ class toil.batchSystems.mesos.ToilJob

Bases: tuple (see /usr/share/doc/python3/html/library/stdtypes.html#tuple)

Its attributes are:

  • jobID
  • name
  • resources
  • command
  • userScript
  • environment
  • workerCleanupInfo

๐Ÿงš toil.batchSystems.options

๐Ÿซง Attributes

  • logger

๐ŸŽ€ Classes

  • OptionSetter: a Protocol for the setOption function. It's how we get to set up CLI options for each batch system ๐Ÿ’… The actual functionality lives in the Config class.

๐ŸŒท Functions

  • set_batchsystem_options(batch_system, set_option): calls set_option for all the options for the given named batch system, or for all batch systems if no name is provided ๐Ÿฆ‹
  • add_all_batchsystem_options(parser): adds the options to the parser ๐Ÿซถ

โœจ Module Contents โœจ

๐Ÿ’– toil.batchSystems.options.logger

๐Ÿ”ฅ class toil.batchSystems.options.OptionSetter

Bases: Protocol

This is the Protocol for the setOption function we get to let us set up CLI options for each batch system. Actual functionality is defined in the Config class. โœจ

Its attribute is:

  • OptionType

Its method is:

__call__(option_name, parsing_function=None, check_function=None,
default=None, env=None, old_names=None)

Parameters

  • option_name (str)
  • parsing_function (Optional[Callable[[Any], OptionType]])
  • check_function (Optional[Callable[[OptionType], Union[None, bool]]])
  • default (Optional[OptionType])
  • env (Optional[list[str]])
  • old_names (Optional[list[str]])

Return type

bool

๐ŸŒธ toil.batchSystems.options.set_batchsystem_options

toil.batchSystems.options.set_batchsystem_options(batch_system,
set_option)

Calls set_option for all the options for the given named batch system, or for all batch systems if no name is provided. ๐ŸŒˆ

Parameters

  • batch_system (Optional[str])
  • set_option (OptionSetter)

Return type

None

๐Ÿง toil.batchSystems.options.add_all_batchsystem_options

toil.batchSystems.options.add_all_batchsystem_options(parser)

Parameters

  • parser (Union[argparse.ArgumentParser, argparse._ArgumentGroup])

Return type

None


๐Ÿ“ toil.batchSystems.registry

๐Ÿซถ Attributes

  • logger
  • DEFAULT_BATCH_SYSTEM

โœจ Functions โœจ

okay so this is the quick cheat sheet for the batch system registry ๐Ÿ’… these are the functions and factories you can call, no cap

  • add_batch_system_factory(key, class_factory) โ€” adds a batch system to the registry, whether it's a workflow one or a plugin-supplied one ๐Ÿงš
  • get_batch_systems() โ€” gets the names of every batch system that's available ๐ŸŒธ
  • get_batch_system(key) โ€” grabs a batch system class by its name โœจ
  • aws_batch_batch_system_factory() ๐Ÿฆ‹
  • gridengine_batch_system_factory() ๐Ÿฆ‹
  • lsf_batch_system_factory() ๐Ÿฆ‹
  • single_machine_batch_system_factory() ๐Ÿฆ‹
  • mesos_batch_system_factory() ๐Ÿฆ‹
  • slurm_batch_system_factory() ๐Ÿฆ‹
  • torque_batch_system_factory() ๐Ÿฆ‹
  • htcondor_batch_system_factory() ๐Ÿฆ‹
  • kubernetes_batch_system_factory() ๐Ÿฆ‹

๐ŸŒˆ Module Contents ๐ŸŒˆ

okay the module contents are where it's at, bestie ๐Ÿซถ

  • toil.batchSystems.registry.logger

๐Ÿ’– toil.batchSystems.registry.add_batch_system_factory(key, class_factory) ๐Ÿ’–

this is the one that adds a batch system to the registry for workflow or plugin-supplied batch systems ๐Ÿ”ฅ

  • Parameters
    • class_factory (Callable[[], type[toil.batchSystems.abstractBatchSystem.AbstractBatchSystem]], see /usr/share/doc/python3/html/library/functions.html#type) โ€” a function that returns a batch system class (NOT an instance), and that class implements toil.batchSystems.abstractBatchSystem.AbstractBatchSystem ๐Ÿ’…
    • key (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒธ

๐ŸŒธ toil.batchSystems.registry.get_batch_systems() ๐ŸŒธ

gets you the names of all the available batch systems, ngl so useful ๐Ÿงš

  • Return type
    • collections.abc.Sequence[str] (see /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Sequence and /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿฆ‹ toil.batchSystems.registry.get_batch_system(key) ๐Ÿฆ‹

grabs a batch system class by name ๐Ÿ‘‘

  • Raises KeyError if the key isn't the name of a batch system, and ImportError if the batch system's class can't be loaded ๐Ÿ’€
  • Parameters
    • key (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿซถ
  • Return type
    • type[toil.batchSystems.abstractBatchSystem.AbstractBatchSystem] (see /usr/share/doc/python3/html/library/functions.html#type) โœจ

๐Ÿ“ toil.batchSystems.registry.DEFAULT_BATCH_SYSTEM ๐Ÿ“

the default is 'single_machine', so if you don't pick one, that's the one you get ๐ŸŒˆ

  • toil.batchSystems.registry.DEFAULT_BATCH_SYSTEM = 'single_machine'

๐Ÿงš Factory functions ๐Ÿงš

all of these are just factory functions for their own batch system, and none of them have a description in the original page, so here they are, serving face ๐Ÿ’…

  • toil.batchSystems.registry.aws_batch_batch_system_factory()
  • toil.batchSystems.registry.gridengine_batch_system_factory()
  • toil.batchSystems.registry.lsf_batch_system_factory()
  • toil.batchSystems.registry.single_machine_batch_system_factory()
  • toil.batchSystems.registry.mesos_batch_system_factory()
  • toil.batchSystems.registry.slurm_batch_system_factory()
  • toil.batchSystems.registry.torque_batch_system_factory()
  • toil.batchSystems.registry.htcondor_batch_system_factory()
  • toil.batchSystems.registry.kubernetes_batch_system_factory()

๐Ÿฆ‹ toil.batchSystems.singleMachine ๐Ÿฆ‹

this is the single machine batch system module, the main character of this section, periodt ๐Ÿ‘‘

๐ŸŒธ Attributes ๐ŸŒธ

  • logger (no description given, just vibes ๐Ÿซถ)

๐Ÿ’œ Classes ๐Ÿ’œ

  • SingleMachineBatchSystem โ€” the interface for running jobs on a single machine. it runs all the jobs you give it, but the description just cuts off right there at "runs all the jobs you" ๐Ÿ™ˆ
  • Info โ€” a record for a running job ๐Ÿฆ‹

๐ŸŒˆ Module Contents ๐ŸŒˆ

  • toil.batchSystems.singleMachine.logger

๐Ÿ’– class toil.batchSystems.singleMachine.SingleMachineBatchSystem(config, maxCores, maxMemory, maxDisk, max_jobs=None) ๐Ÿ’–

Bases: toil.batchSystems.abstractBatchSystem.BatchSystemSupport (see /usr/share/doc/python3/html/library/functions.html#float and friends for the type links)

the interface for running jobs on a single machine, which runs all the jobs you give it as they come in, but in parallel. it's giving multitasking ๐Ÿ”ฅ

it uses a single "daddy" thread to manage a fleet of child processes ๐Ÿงš

communication with the daddy thread happens through two queues: one queue of jobs waiting to be run (the input queue), and one queue of jobs that are finished or stopped and need to be returned by getUpdatedBatchJob (the output queue) ๐Ÿ“ฌ

when the batch system is shut down, the daddy thread is stopped ๐Ÿ›‘

if it's running in debug-worker mode, jobs run immediately as they're sent to the batch system, in the sending thread, and the daddy thread doesn't run at all. the queues are still used though ๐Ÿ™ˆ

  • Parameters
    • config (toil.common.Config) ๐Ÿซถ
    • maxCores (float, see /usr/share/doc/python3/html/library/functions.html#float) ๐Ÿ’…
    • maxMemory (float, see /usr/share/doc/python3/html/library/functions.html#float) ๐Ÿ’…
    • maxDisk (int, see /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ’…
    • max_jobs (Optional[int], see /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ’…

๐Ÿฆ‹ classmethod supportsAutoDeployment() ๐Ÿฆ‹

tells you whether this batch system can auto-deploy the user script itself ๐Ÿš€

if it can, setUserScript() can be invoked to set the resource object that represents the user script โœจ

Note to implementors: if your implementation returns True here, it should also override (the note cuts off right there, so keep that in mind ๐Ÿ’€)

๐ŸŒธ classmethod supportsWorkerCleanup() ๐ŸŒธ

tells you whether this batch system supports worker cleanup ๐Ÿงน

it shows whether this batch system invokes BatchSystemSupport.workerCleanup() after the last job for a particular workflow invocation finishes. quick reminder that "worker" here means an entire node, not just a worker process. a worker process can run more than one job sequentially, and more than one concurrent worker process can exist on a worker node for the same workflow. the batch system is said to shut down after the last worker process terminates ๐Ÿ‘‘

๐Ÿ’œ Attributes ๐Ÿ’œ

  • numCores ๐Ÿ’…
  • minCores = 0.1 โ€” the minimal fractional CPU. tasks asking for fewer cores get rounded up to this value ๐ŸŒˆ
  • physicalMemory ๐Ÿ’…
  • config ๐Ÿ’…
  • physicalDisk ๐Ÿ’…
  • scale ๐Ÿ’…
  • debugWorker ๐Ÿ’…
  • jobIndex = 1 ๐Ÿ’…
  • jobIndexLock ๐Ÿ’…
  • jobs: dict[int, toil.job.JobDescription] (see /usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“ฆ
  • inputQueue ๐Ÿ’…
  • outputQueue ๐Ÿ’…
  • runningJobs: dict[int, Info] ๐ŸŒธ this is the VIP list of jobs that are running right now, keyed by job ID. Each value is an Info record. Type docs: dict lives at /usr/share/doc/python3/html/library/stdtypes.html#dict, int at /usr/share/doc/python3/html/library/functions.html#int, and Info at #toil.batchSystems.singleMachine.Info.
  • children: dict[int, subprocess.Popen] ๐Ÿ‘ถ the child processes, keyed by int. Type docs: dict at /usr/share/doc/python3/html/library/stdtypes.html#dict, int at /usr/share/doc/python3/html/library/functions.html#int, and subprocess.Popen at /usr/share/doc/python3/html/library/subprocess.html#subprocess.Popen.
  • childToJob: dict[int, str] ๐Ÿฆ‹ maps each int to a str. Type docs: dict at /usr/share/doc/python3/html/library/stdtypes.html#dict, int at /usr/share/doc/python3/html/library/functions.html#int, and str at /usr/share/doc/python3/html/library/stdtypes.html#str.
  • accelerator_identities โœจ just the name, no type or default given on the page.
  • resource_sources ๐Ÿ’… just the name, no type or default given on the page.
  • schedulingStatusMessage = None ๐Ÿ”ฅ starts out as None.
  • shuttingDown ๐Ÿ™ˆ just the name, no type or default given on the page.
  • daddyThread = None ๐Ÿ‘‘ the daddy thread lives here, and it starts as None.
  • daddyException: Exception | None = None ๐Ÿ’€ can be an Exception or None, and it starts as None. Type docs: Exception at /usr/share/doc/python3/html/library/exceptions.html#Exception and None at /usr/share/doc/python3/html/library/constants.html#None.

โœจ daddy()

Be the "daddy" thread. ๐Ÿ‘‘ Our job is to look at jobs from the input queue.

If a job fits in the available resources, we allocate resources for it and kick off a child process. ๐Ÿš€

We also check on our children. ๐Ÿ‘€

When a child finishes, we reap it, release its resources, and put its information in the output queue. ๐Ÿซถ


๐Ÿ’– getSchedulingStatusMessage()

Get a log message fragment for the user about anything that might be going wrong in the batch system, if one is available. ๐Ÿ”

If no useful message is available, return None. ๐Ÿ™ˆ

This can be used to report what resource is the limiting factor when scheduling jobs, for example. ๐Ÿง If the leader thinks the workflow is stuck, the message can be displayed to the user so they can diagnose why it might be stuck. ๐ŸŒธ

Returns

User-directed message about scheduling state.


๐Ÿฆ‹ check_resource_request(requirer)

Check that a resource request is not greater than what's available or allowed. ๐Ÿ›ก๏ธ

Parameters

  • requirer (toil.job.Requirer, see #toil.job.Requirer) โ€” the object whose requirements are being checked
  • job_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the job being checked, used to generate a useful error report
  • detail (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” a batch-system-specific message to include in the error

Raises

InsufficientSystemResources (see #toil.batchSystems.abstractBatchSystem.InsufficientSystemResources) โ€” raised when a resource is requested in an amount greater than allowed ๐Ÿ’€

Return type

None


๐Ÿงš issueBatchJob(command, job_desc, job_environment=None)

Adds the command and resources to a queue so it can be run. ๐Ÿƒโ€โ™€๏ธ

Parameters

  • command (str)
  • job_desc (toil.job.JobDescription, see #toil.job.JobDescription)
  • job_environment (Optional[dict[str, str]])

Return type

int


๐Ÿ“ killBatchJobs(jobIDs)

Kills jobs by ID. โ˜ ๏ธ

Parameters

jobIDs (list[int])

Return type

None


๐ŸŒˆ getIssuedBatchJobIDs()

Just returns all the jobs that have been run but not yet returned as updated. ๐Ÿ“ฆ

Return type

list[int]


โญ getRunningBatchJobIDs()

Gets a map of job ID numbers for jobs that are currently running (not just waiting), along with how long each has been running, in seconds. โฑ๏ธ

Returns

A dictionary with currently running job ID number keys and how many seconds they have been running as the value.

Return type

dict[int, float]


๐Ÿ›‘ shutdown()

Terminate cleanly and join the daddy thread. ๐Ÿซก

Return type

None


๐Ÿ’œ getUpdatedBatchJob(maxWait)

Returns a tuple of a no-longer-running job, the return value of its process, and its runtime, or None. ๐ŸŽ€

Parameters

maxWait (int)

Return type

Optional[toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo] (see #toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo)


๐ŸŒธ classmethod add_options(parser)

If this batch system provides any command line options, add them to the given parser. ๐Ÿ’…

Parameters

parser (Union[argparse.ArgumentParser, argparse._ArgumentGroup])

Return type

None


๐Ÿ”ฅ classmethod setOptions(setOption)

Process command line or configuration options relevant to this batch system. โš™๏ธ

Parameters

setOption (toil.batchSystems.options.OptionSetter, see #toil.batchSystems.options.OptionSetter) โ€” a function with the signature setOption(option_name, parsing_function=None, check_function=None, default=None, env=None) that returns nothing and is used to update the run configuration as a side effect. ๐Ÿง


๐Ÿฆ‹ toil.batchSystems.singleMachine.Info(startTime, popen, resources, killIntended)

Record for a running job. ๐Ÿ“

It stores the start time of the job, the Popen object representing its child (or None), the tuple of (coreFractions, memory, disk) it is using (or None), and whether the job is supposed to be being killed. ๐ŸŒ™

  • time ๐Ÿ•ฐ๏ธ
  • popen ๐Ÿญ
  • resources ๐ŸŽ
  • killIntended ๐Ÿ›‘

โœจ toil.batchSystems.slurm

๐ŸŒธ Attributes

  • logger
  • TERMINAL_STATES
  • NONTERMINAL_STATES

๐Ÿง Classes

  • SlurmBatchSystem โ€” a partial implementation of BatchSystemSupport for batch systems run on a

๐Ÿซง Functions

  • parse_slurm_time(slurm_time) โ€” Parse a Slurm-style time duration like 7-00:00:00 to a number of seconds. โฐ
  • option_detector(long[, short]) โ€” get a function that returns true if it sees the long or short
  • any_option_detector(options) โ€” get a function that returns true if it sees any of the long

๐Ÿ’ซ Module Contents

  • toil.batchSystems.slurm.logger
  • toil.batchSystems.slurm.TERMINAL_STATES: dict[str, toil.batchSystems.abstractBatchSystem.BatchJobExitReason] (see #toil.batchSystems.abstractBatchSystem.BatchJobExitReason, plus dict at /usr/share/doc/python3/html/library/stdtypes.html#dict and str at /usr/share/doc/python3/html/library/stdtypes.html#str)
  • toil.batchSystems.slurm.NONTERMINAL_STATES: set[str] (set at /usr/share/doc/python3/html/library/stdtypes.html#set and str at /usr/share/doc/python3/html/library/stdtypes.html#str)
  • toil.batchSystems.slurm.parse_slurm_time(slurm_time) โ€” Parse a Slurm-style time duration like 7-00:00:00 to a number of seconds. Raises ValueError if not parseable. ๐Ÿšจ

Okay so the only input for this one is slurm_time (str) ๐Ÿ•ฐ๏ธ, and it hands back an int ๐Ÿ’…

Parameters

  • slurm_time (str)

Return type

int

toil.batchSystems.slurm.option_detector(long, short=None) ๐Ÿ”

Bestie, this one builds you a little checker function โœจ. That checker returns True if it spots the long option or the short one.

Parameters

  • long (str)
  • short (str | None)

Return type

Callable[[str], bool]

toil.batchSystems.slurm.any_option_detector(options) ๐Ÿฆ‹

This is the upgraded version ๐Ÿ‘‘. It gives you back a checker that returns True if it sees any of the long options, or any long or short option pair.

Parameters

  • options (list[str | tuple[str, str]])

Return type

Callable[[str], bool]

class toil.batchSystems.slurm.SlurmBatchSystem(config, maxCores, maxMemory, maxDisk) ๐Ÿ–ฅ๏ธ

Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem

This is a partial implementation of BatchSystemSupport for batch systems that run on a standard HPC cluster ๐ŸŒธ. By default, auto-deployment is not implemented, so keep that in mind ๐Ÿ™ˆ.

Parameters

  • config (toil.common.Config)
  • maxCores (float)
  • maxMemory (float)
  • maxDisk (float)

class PartitionInfo ๐Ÿง

Bases: NamedTuple

This is the main character of the partition world. Each one has these fields:

  • partition_name: str
  • gres: bool
  • time_limit: float
  • priority: int
  • cpus: str
  • memory: str

class PartitionSet ๐Ÿ“

This is the set of available partitions that Toil detects on the Slurm batch system ๐Ÿ‘€.

  • default_gpu_partition: SlurmBatchSystem | None
  • all_partitions: list[SlurmBatchSystem]
  • gpu_partitions: set[str]

get_partition(time_limit) โฑ๏ธ

Gets the partition name to use for a job with the given time limit. It's giving precision ๐Ÿ’–.

Parameters

  • time_limit (float | None) โ€” the time limit in seconds.

Return type

str | None

class GridEngineThread(newJobsQueue, updatedJobsQueue, killQueue, killedJobsQueue, boss) ๐Ÿงต

Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem.GridEngineThread

This is a class that represents a thread of control ๐Ÿงต๐Ÿ’œ. It can be safely subclassed, but only in a limited fashion, so don't go wild ๐Ÿ˜ญ. There are two ways to set up the activity: pass a callable object to the constructor, or override the run() method in a subclass.

Parameters

  • newJobsQueue (queue.Queue)
  • updatedJobsQueue (queue.Queue)
  • killQueue (queue.Queue)
  • killedJobsQueue (queue.Queue)
  • boss (AbstractGridEngineBatchSystem)

boss: SlurmBatchSystem

getRunningJobIDs() ๐Ÿƒ

Gets a list of running job IDs. This is implementation-specific, and it gets called by the boss AbstractGridEngineBatchSystem implementation through AbstractGridEngineBatchSystem.getRunningBatchJobIDs() ๐Ÿซถ.

Return type

list

killJob(jobID) ๐Ÿ’€

Kills a specific job using the Toil job ID. This is implementation-specific too, and it gets called by GridEngineThread.killJobs() ๐Ÿ”ฅ.

Parameters

  • jobID (string) โ€” the Toil job ID.

Return type

None

prepareSubmission(cpu, memory, jobID, command, jobName, job_environment=None, gpus=None) ๐ŸŽ€

This is the prep work ๐Ÿ’… for putting together a command-line string that gets submitted to the batch system (through submitJob()).

  • int cpu
  • int memory
  • int jobID โ€” the Toil job ID.
  • string subLine โ€” the command line string to be called.
  • string jobName โ€” the name of the Toil job, which provides metadata to batch systems if they want it ๐Ÿงš.
  • dict job_environment โ€” the environment variables to be set on the worker.

Return type

List[str]

Parameters

  • cpu (int)
  • memory (int)
  • jobID (int)
  • command (str)
  • jobName (str)
  • job_environment (dict[str, str] | None)
  • gpus (int | None)

submitJob(subLine) ๐Ÿš€

This is a wrapper routine. It submits the actual command-line call, then processes the output to get the batch system job ID ๐ŸŽ€.

  • string subLine โ€” the literal command line string to be called.

Return type

string: the batch system job ID, which will be stored internally ๐ŸŒˆ.

Parameters

  • subLine (list[str])

coalesce_job_exit_codes(batch_job_id_list) ๐Ÿ‘‘

This one collects all the job exit codes in a single call. It's so efficient, I'm obsessed ๐Ÿ˜ญโœจ.

Parameters

  • batch_job_id_list (list[str]) โ€” a list of Job ID strings, where each string has the form <job>[.<task>].

Returns

A list of job exit codes, or exit code and exit reason pairs, associated with the list of job IDs.

Raises

  • CalledProcessErrorStderr โ€” if communicating with Slurm went wrong. ๐Ÿ’”
  • OSError โ€” ๐Ÿ˜ญ this one pops up when the job details just aren't available because a Slurm command couldn't even start. Rough day for Slurm ๐Ÿ’€

Return type ๐Ÿงพ list[int | tuple[int, toil.batchSystems.abstractBatchSystem.BatchJobExitReason | None] | None] | None

โœจ getJobExitCode(batchJobID)

Okay so this one is the exit code getter ๐Ÿ’… You hand it a batch job ID and it gives you back the job's exit code as an integer. โœจ

Parameters

  • batchJobID (str) โ€” the ID, which is a string shaped like "<job>[.<task>]" ๐ŸŽ€

Return type ๐Ÿงพ int | tuple[int, toil.batchSystems.abstractBatchSystem.BatchJobExitReason | None] | None

โœจ prepareSbatch(cpu, mem, jobID, jobName, job_environment, gpus)

This one builds the sbatch command line you run to queue up the job ๐ŸŒธ Basically the prep work before the job gets sent off.

Parameters

  • cpu (int) ๐Ÿ’–
  • mem (int) ๐Ÿ’–
  • jobID (int) ๐Ÿ’–
  • jobName (str) ๐Ÿ’–
  • job_environment (dict[str, str] | None) ๐Ÿ’–
  • gpus (int | None) ๐Ÿ’–

Return type ๐Ÿงพ list[str]

๐Ÿงฉ Attributes

  • partitions ๐Ÿฆ‹
  • start_time ๐Ÿฆ‹

โœจ issueBatchJob(command, job_desc, job_environment=None)

This is the main event ๐Ÿ”ฅ It sends a job with your chosen command to the batch system and hands back a unique job ID number so you can keep track of it. Iykyk.

Parameters

  • command (str) โ€” the command to run somewhere in order to start the Toil worker process ๐ŸŒˆ
  • job_desc (toil.job.JobDescription) โ€” the JobDescription for the job that's being run ๐Ÿ“
  • job_environment (dict[str, str] | None) โ€” a bundle of job-specific environment variables that get set on the worker ๐Ÿงš

Returns โ€” a unique job ID number that you can use to reference the newly issued job ๐Ÿ‘‘

Return type ๐Ÿงพ int

โœจ add_options(parser) (classmethod)

If this batch system comes with its own command line options, this is where they get added to the parser you hand over ๐ŸŽ€

Parameters

  • parser (argparse.ArgumentParser | argparse._ArgumentGroup) ๐Ÿ’œ

Return type ๐Ÿงพ None

๐Ÿงฉ Attributes

  • OptionType ๐Ÿฆ‹

โœจ setOptions(setOption) (classmethod)

This one processes the command line or config options that matter for this batch system. Main character energy ๐Ÿ‘‘

Parameters

  • setOption (toil.batchSystems.options.OptionSetter) โ€” a function with the signature setOption(option_name, parsing_function=None, check_function=None, default=None, env=None). It returns nothing and quietly updates the run configuration as a side effect ๐Ÿซถ

Return type ๐Ÿงพ None


๐Ÿ˜ toil.batchSystems.torque

๐Ÿงฉ Attributes

  • logger ๐ŸŒธ

๐ŸŽ€ Classes

  • TorqueBatchSystem โ€” a partial implementation of BatchSystemSupport for batch systems run on a standard HPC cluster ๐Ÿ’…

๐Ÿงฉ Module Contents

  • toil.batchSystems.torque.logger โœจ

โœจ class TorqueBatchSystem(config, maxCores, maxMemory, maxDisk)

Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem

This is a partial implementation of BatchSystemSupport for batch systems that run on a standard HPC cluster. Heads up though: auto-deployment is not implemented by default ๐Ÿ™ˆ

Parameters

  • config (toil.common.Config) ๐Ÿ’–
  • maxCores (float) ๐Ÿ’–
  • maxMemory (float) ๐Ÿ’–
  • maxDisk (float) ๐Ÿ’–

โœจ class GridEngineThread(newJobsQueue, updatedJobsQueue, killQueue, killedJobsQueue, boss)

Bases: toil.batchSystems.abstractGridEngineBatchSystem.AbstractGridEngineBatchSystem.GridEngineThread

This is a class that represents a thread of control ๐Ÿงต It's safe to subclass, but only in a limited way. You can set the activity in two ways: pass a callable object to the constructor, or override the run() method in a subclass.

getRunningJobIDs()

Gets a list of the running job IDs ๐Ÿ“‹ This is implementation-specific, and the boss AbstractGridEngineBatchSystem implementation calls it through AbstractGridEngineBatchSystem.getRunningBatchJobIDs().

Return type ๐Ÿงพ list

getUpdatedBatchJob(maxWait)

killJob(jobID)

This kills one specific job using its Toil job ID ๐Ÿ’€ It's implementation-specific, and GridEngineThread.killJobs() is the one who calls it.

Parameters

  • jobID (string) โ€” the Toil job ID ๐ŸŽ€

prepareSubmission(cpu, memory, jobID, command, jobName, job_environment=None, gpus=None)

This is the prep work for putting together a command-line string that gets submitted to the batch system (via submitJob()) โœจ

Parameters

  • cpu (int) ๐Ÿ’–
  • memory (int) ๐Ÿ’–
  • jobID (int) โ€” the Toil job ID ๐Ÿฆ‹
  • command (str) ๐Ÿ’–
  • jobName (str) โ€” the name of the Toil job, which gives metadata to batch systems if they want it ๐ŸŒˆ

Param ๐Ÿซถ int cpu

Param ๐Ÿซถ int memory

Param ๐Ÿซถ int jobID: Toil job ID

Param ๐Ÿซถ string subLine: the command line string to be called

Param ๐Ÿซถ string jobName: the name of the Toil job, to provide metadata to batch systems if desired

Param ๐Ÿซถ dict job_environment: the environment variables to be set on the worker

Return type ๐Ÿงพ List[str]

Parameters

  • cpu (int) ๐Ÿ’–
  • memory (int) ๐Ÿ’–
  • jobID (int) ๐Ÿ’–
  • command (str) ๐Ÿ’–
  • jobName (str) ๐Ÿ’–
  • job_environment (Optional[dict[str, str]])
  • gpus (Optional[int])
  • submitJob(subLine) โ€” the wrapper that sends off the actual command-line call, then digs through the output to snag the batch system job ID ๐ŸŽ€
    • Param string subLine โ€” the literal command line string to be called ๐Ÿ’Œ
    • Return type string โ€” the batch system job ID, which gets stored internally โœจ
  • getJobExitCode(torqueJobID) โ€” hands back the job's exit code and possibly an instance of abstractBatchSystem.BatchJobExitReason ๐Ÿ‘‘
    • Returns None if the job is still running ๐Ÿซถ
    • If the job isn't running but the exit code isn't available, you get EXIT_STATUS_UNAVAILABLE_VALUE ๐Ÿ’€
    • This one's implementation-specific, and it's called by GridEngineThread.checkOnJobs() ๐Ÿ”ฅ
    • The exit code will only be 0 if the job affirmatively succeeded. ๐Ÿ˜ญ
    • Parameters
      • batchjobID (string) โ€” the batch system job ID ๐ŸŒธ
  • prepareQsub(cpu, mem, jobID, job_environment) โ€” bestie, this one just wants its parameters and return type ๐Ÿ’…
    • Parameters
      • cpu (int)
      • mem (int)
      • jobID (int)
      • job_environment (Optional[dict[str, str]])
    • Return type list[str]
  • generateTorqueWrapper(command, jobID) โ€” a super simple script generator that just wraps the command you give it, and for now it goes to the default tempdir ๐Ÿงš

๐ŸŽ€ Exceptions

  • DeadlockException โ€” thrown by the Leader or BatchSystem when a deadlock pops up because there aren't enough resources to run the workflow ๐Ÿ’€

๐ŸŒธ Package Contents

Here's the exception class, bestie ๐Ÿ’–

exception toil.batchSystems.DeadlockException(msg)
  • Bases: Exception
  • Thrown by the Leader or BatchSystem when a deadlock is encountered due to insufficient resources to run the workflow ๐ŸŒˆ
  • Default message:
msg = 'Deadlock encountered: Uninferable'
  • __str__() โ€” stringifies the exception, message and all ๐Ÿงƒ

๐Ÿฆ‹ toil.bus

Okay so toil.bus is all about message types and a message bus for coordinating the leader's components ๐Ÿ’œ

Historically, the Toil Leader was all functions calling other functions to "handle" stuff, and it got SO brittle. The handler functions had to run in exactly the right order, or it would get confused and do the wrong thing ๐Ÿ˜ญ

The MessageBus fixes that by loosely coupling everything. Components talk by sending messages instead of calling each other directly ๐Ÿ’…

Say a job comes back from the batch system with a failed exit status. That gets turned into a message and sent to the bus. Every component that needs to react to it (like decrementing the retry count) listens for the messages it cares about. Adding a brand new component? Just plug it in, and it can receive and react to messages without messing with the existing components' ability to react to the same ones ๐Ÿ”ฅ

Eventually, the different parts of the Leader could become their own separate objects ๐ŸŒธ

By default, messages stay entirely inside the Toil leader process. They aren't saved anywhere, not even in the JobStore ๐Ÿ™ˆ

The MessageBus also doubles as an extension point! The leader can serialize its messages to a file (check out the --writeMessages option), and you can decode them with MessageBus.scan_bus_messages(), which is exactly what the Toil WES server backend does. Replay the messages and track their effects on job state, and you get an up-to-date picture of every job in a workflow: whether they're issued or running, and which ones have completely finished. That's info the JobStore doesn't persist, so it's giving main character energy ๐Ÿ‘‘

The leader process's MessageBus instance is owned by the Toil leader, but the BatchSystem gets a chance to connect to it and send or listen for messages. Right now it doesn't have to send or receive anything. The Leader polls it through the BatchSystem API and generates the events itself. But a BatchSystem implementation may send extra events, like JobAnnotationMessage ๐ŸŽ€

Right now the MessageBus is built on pypubsub, so messages are always handled on one thread: the Toil leader's main loop thread. If other components send events, they get shipped over to that thread inside the MessageBus. Processes can talk to each other using MessageBus.connect_output_file() and MessageBus.scan_bus_messages() ๐Ÿฆ‹

๐Ÿ’… Attributes

  • logger
  • MessageType

โœจ Classes โœจ

okay bestie, here's the whole message bus crew ๐Ÿซถ these classes basically tell toil what's happening to each job ๐Ÿ’…

heads up: a few of these descriptions just trail off mid-sentence in the original docs, so I've kept them exactly as they are ๐Ÿ˜ญ
  • Names โ€” stores literally every kind of name a job can have ๐ŸŽ€
  • JobIssuedMessage โ€” dropped when a job gets issued to run on the batch system ๐Ÿš€
  • JobUpdatedMessage โ€” dropped when a job is "updated" and ready for something to happen to it โœจ
  • JobCompletedMessage โ€” dropped when a job is completed, whether it went well or not ๐Ÿ
  • JobFailedMessage โ€” dropped when a job has completely failed and won't be retried again ๐Ÿ’€
  • JobMissingMessage โ€” dropped when a job goes missing: it should be in the batch system but isn't ๐Ÿ™ˆ
  • JobAnnotationMessage โ€” dropped when extra info shows up, like an AWS Batch job ID from the ๐Ÿงพ
  • ExternalBatchIdMessage โ€” dropped when you're using a batch system, and it links the toil assigned batch ID to ๐Ÿ”—
  • QueueSizeMessage โ€” dropped to describe the size of the queue of jobs that are issued but not yet ๐Ÿ“
  • ClusterSizeMessage โ€” Produced by the Toil-integrated autoscaler describe the number of ๐Ÿ“Š
  • ClusterDesiredSizeMessage โ€” Produced by the Toil-integrated autoscaler to describe the number of ๐ŸŽฏ
  • MessageBus โ€” holds messages that should cause jobs to change their scheduling states ๐Ÿšฆ
  • MessageBusClient โ€” the base class for clients (inboxes and outboxes) of a message bus. Handles ๐Ÿ’œ
  • MessageInbox โ€” a buffered connection to a message bus that lets us receive messages ๐Ÿ“ฌ
  • MessageOutbox โ€” a connection to a message bus that lets us publish messages ๐Ÿ“ค
  • MessageBusConnection โ€” a two-way connection to a message bus. Buffers incoming messages until you ๐Ÿ”
  • JobStatus โ€” records the status of a job ๐Ÿ“

โœจ Functions โœจ

okay now the little helper functions, and they're iconic ๐Ÿ‘‘

  • get_job_kind(names) โ€” returns an identifying string for the job ๐Ÿชช
  • message_to_bytes(message) โ€” converts a plain-old-data named tuple into a byte string ๐Ÿซง
  • bytes_to_message(message_type, data) โ€” converts bytes from message_to_bytes back into a message of the given type ๐Ÿ”„
  • replay_message_bus(path) โ€” replays all the messages and works out what they mean for jobs ๐ŸŽฌ
  • gen_message_bus_path([tmpdir]) โ€” returns a file path in tmp to store the message bus at ๐Ÿ—‚๏ธ

โœจ Module Contents โœจ

the module itself is giving main character energy ๐ŸŒŸ

  • toil.bus.logger

class toil.bus.Names

Bases: NamedTuple

Stores all the kinds of name a job can have ๐ŸŽ€ each of these is a str:

  • job_name: str
  • unit_name: str
  • display_name: str
  • stats_name: str
  • job_store_id: str

toil.bus.get_job_kind(names)

Return an identifying string for the job ๐Ÿชช

The result may contain spaces.

Returns: Either the unit name, job name, or display name, which identifies the kind of job it is to toil. Otherwise "Unknown Job" in case no identifier is available.

Parameters:

  • names (Names)

Return type: str

class toil.bus.JobIssuedMessage

Bases: NamedTuple

Produced when a job is issued to run on the batch system ๐Ÿš€ fields:

  • job_type: str
  • job_id: str
  • toil_batch_id: int

class toil.bus.JobUpdatedMessage

Bases: NamedTuple

Produced when a job is "updated" and ready to have something happen to it โœจ fields:

  • job_id: str
  • result_status: int

class toil.bus.JobCompletedMessage

Bases: NamedTuple

Okay so this one is for when a job wraps up, whether it slayed or flopped ๐Ÿ’…โœจ It gets sent out no matter what the outcome was:

  • job_type: str
  • job_id: str
  • exit_code: int

๐Ÿ’Œ toil.bus.JobFailedMessage

Bases: NamedTuple ๐Ÿ’€

This one is for when a job is completely cooked and won't be retried again ๐Ÿ˜ญ Fields:

  • job_type: str
  • job_id: str

๐Ÿซฅ toil.bus.JobMissingMessage

Bases: NamedTuple ๐Ÿ™ˆ

Sent when a job goes missing. It's supposed to be in the batch system, but it's just not there, bestie ๐Ÿ‘ป Fields:

  • job_id: str

๐Ÿท๏ธ toil.bus.JobAnnotationMessage

Bases: NamedTuple ๐ŸŽ€

This is extra info that goes along with a job, like an AWS Batch job ID from the AWSBatchBatchSystem. Fields:

  • job_id: str
  • annotation_name: str
  • annotation_value: str

๐Ÿ”— toil.bus.ExternalBatchIdMessage

Bases: NamedTuple ๐Ÿฆ‹

When you're using a batch system, this one links the batch ID Toil assigned to the batch system's own ID. That ID is whatever the local implementation returns, like a PID, a batch ID, etc. Fields:

  • toil_batch_id: int
  • external_batch_id: str
  • batch_system: str

๐Ÿ“ toil.bus.QueueSizeMessage

Bases: NamedTuple ๐ŸŒธ

This tells you how big the queue is for jobs that have been issued but aren't finished yet. Theoretically, you can recover this from other messages, so it's giving redundant but useful. Fields:

  • queue_size: int

๐Ÿ‘ toil.bus.ClusterSizeMessage

Bases: NamedTuple ๐ŸŒˆ

The Toil-integrated autoscaler sends this one to describe how many instances of a certain type are in a cluster. Fields:

  • instance_type: str
  • current_size: int

๐Ÿ”ฎ toil.bus.ClusterDesiredSizeMessage

Bases: NamedTuple ๐Ÿงš

Also from the Toil-integrated autoscaler! This one says how many instances of a certain type it thinks it's going to need. Fields:

  • instance_type: str
  • desired_size: int

๐Ÿงณ toil.bus.message_to_bytes(message)

This takes a plain-old-data named tuple and turns it into a byte string. Easy peasy ๐Ÿ“

Parameters

  • message (NamedTuple)

Return type

  • bytes

๐Ÿท๏ธ toil.bus.MessageType

Just a bare entry with nothing else attached. It's a type placeholder, so there's no drama here ๐Ÿ’…

๐Ÿ” toil.bus.bytes_to_message(message_type, data)

This is the undo button for message_to_bytes. It converts bytes back into a message of the type you give it โœจ

Parameters

  • message_type (type[MessageType])
  • data (bytes)

Return type

  • MessageType

๐ŸšŒ class toil.bus.MessageBus

Bases: none. This is the main hub for messages that make jobs change their scheduling states ๐ŸšŒ๐Ÿ’– Messages get put in and buffered, and you can take them out and handle them in batches whenever it's convenient. Every message is a NamedTuple object of some subtype. Message order is guaranteed to be preserved within a type, so you can trust it ๐Ÿซถ

publish(message) Puts a message onto the bus. You can call this from any thread, no cap ๐Ÿงต

  • Parameters: message (Any)
  • Return type: None

check() If we're in the owning thread, this delivers any messages sitting in the queue for us. You need to call it every once in a while in the main thread, and it can happen through inbox objects too ๐Ÿ‘€

  • Return type: None

MessageType Another bare placeholder. Nothing to see here, babe ๐ŸŒท

subscribe(message_type, handler) Registers the callable you give it so it gets called whenever messages of the given type are sent. It only gets messages sent after the subscription is created. This returns a subscription object, and when that object gets garbage collected, the subscription ends ๐Ÿ—‘๏ธ

  • Parameters:
    • message_type (type[MessageType])
    • handler (Callable[[MessageType], Any])
  • Return type: pubsub.core.listener.Listener

connect(wanted_types) Gets you a connection object that works as an inbox for messages of the given types. Those messages pile up in the inbox until it's destroyed, and you can check it whenever you want ๐Ÿ“ฅ

  • Parameters: wanted_types (list[type])
  • Return type: MessageBusConnection

outbox() Gets you a connection object that's only for sending messages. Send-only energy ๐Ÿ“ค

  • Return type: MessageOutbox

connect_output_file(file_path) Sends copies of all messages to the given output file ๐Ÿ“ It returns connection data that has to be kept alive for the connection to persist. That data is opaque, so you're not supposed to look at it, touch it, or do anything with it except store it somewhere or delete it.

โš ๏ธ Hands off the connection data, bestie. Just store it or delete it. Looking inside or poking at it is not the vibe.
  • Parameters: file_path (toil.lib.misc.FileDescriptorOrPath)
  • Return type: Any

classmethod scan_bus_messages(stream, message_types) Gives you an iterator over all the messages of the given types in the given log stream, in order. Any trailing partial messages get discarded ๐Ÿ—‚๏ธ

  • Parameters:
    • stream (IO[bytes])
    • message_types (list[type[NamedTuple]])
  • Return type: collections.abc.Iterator[Any]

๐Ÿค class toil.bus.MessageBusClient

Bases: none. This is the base class for clients, which means inboxes and outboxes. It handles keeping a reference to the message bus so you don't have to ๐Ÿซถ

๐Ÿ“ฅ class toil.bus.MessageInbox

Bases: MessageBusClient ๐Ÿ“ฅ

This is a buffered connection to a message bus that lets you receive messages. It holds incoming messages until you're ready for them. Heads up, though: it does not preserve ordering between messages of different types ๐Ÿ™ƒ

count(message_type) Gets the number of pending messages of the given type ๐Ÿ”ข

  • Parameters: message_type (type)
  • Return type: int

empty() Returns True if no messages are pending, and False otherwise ๐Ÿซ™

  • Return type: bool

MessageType Bare placeholder again, we love a consistent girl ๐Ÿ’…

for_each(message_type) Loops over all messages that are currently pending of the given type. Each one that gets handled without raising an exception will be removed ๐Ÿงน

๐Ÿ‘€ Messages sent while this function is running won't be yielded by the current call. They'll have to wait for the next one.
  • Parameters: message_type (type[MessageType])
  • Return type: collections.abc.Iterator[MessageType]

๐Ÿ“ค class toil.bus.MessageOutbox

Bases: MessageBusClient ๐Ÿ“ค

This is a connection to a message bus that lets you publish messages ๐Ÿ“ฃ

publish(message) Publishes the given message to the connected message bus. This exists so you don't have to store both the bus and your connection, which is honestly very thoughtful of it ๐Ÿ’–

  • Parameters: message (Any)
  • Return type: None

๐Ÿ”„ class toil.bus.MessageBusConnection

Bases: MessageInbox, MessageOutbox ๐Ÿ”„

This is a two-way connection to a message bus. It buffers incoming messages until you're ready for them, and it lets you send messages too. Full receive-and-send main character energy โœจ

๐Ÿ“Š class toil.bus.JobStatus

This one records the status of a job ๐Ÿ“Š When exit_code is -1, that means the job is either not observed or currently running. Fields:

  • job_store_id: str
  • name: str
  • exit_code: int
  • annotations: dict[str, str]
  • toil_batch_id โ€” an int, the Toil batch id ๐ŸŽ€
  • external_batch_id โ€” a str, the external batch id ๐ŸŒธ
  • batch_system โ€” a str, the batch system the job is running on ๐Ÿฆ‹
  • __repr__() ๐Ÿ’…
    • Return type: str
  • is_running() ๐Ÿƒโ€โ™€๏ธ
    • Return type: bool

โœจ toil.bus.replay_message_bus(path)

Okay so this one replays every message and figures out what each one means for jobs ๐Ÿ”โœจ. We keep track of each job's state and name by its ID here ๐Ÿ‘€. We'd normally use a list of two items, but MyPy can't understand a list with items of multiple types, so we made a whole new class instead ๐Ÿ™„๐Ÿ’….

It returns a dictionary keyed by job_id, where each value is a dataclass called JobStatus ๐Ÿ“ฆ. A JobStatus holds everything we pulled off the message bus about a job ๐Ÿ’–, including the job store id, the job's name, its exit code, any associated annotations, the Toil batch id, the external batch id, and the batch system the job is running on ๐Ÿงš.

  • path (toil.lib.misc.FileDescriptorOrPath)

Return type: dict[str, JobStatus]

โœจ toil.bus.gen_message_bus_path(tmpdir=None)

This one gives you a file path in tmp to store the message bus at ๐ŸŒˆ. Heads up bestie: whoever calls it is responsible for cleaning up the generated file ๐Ÿงนโš ๏ธ.

The tmpdir argument lets you override which directory the message bus gets made in ๐Ÿ—‚๏ธ. If you don't pass it, the standard tempfile order is used ๐Ÿซถ.

  • tmpdir (Optional[str])

Return type: str


๐Ÿงบ toil.common

Attributes

  • UUID_LENGTH ๐Ÿ”ข
  • logger ๐Ÿ“

Exceptions

  • ToilRestartException โ€” Common base class for all non-exit exceptions. ๐Ÿ”
  • ToilContextManagerException โ€” Common base class for all non-exit exceptions. ๐Ÿ™ˆ

Classes

  • Config โ€” Class to represent configuration operations for a Toil workflow run โš™๏ธ.
  • Toil โ€” A context manager that represents a Toil workflow ๐Ÿ‘‘.
  • ToilMetrics ๐Ÿ“Š

Functions

  • get_default_config_path() โ€” Get the default path where the Toil configuration file lives ๐Ÿ“.
  • ensure_config(filepath) โ€” If the config file at the filepath does not exist, create it ๐Ÿ› ๏ธ.
  • generate_config(filepath) โ€” Write a Toil config file to the given path โœ๏ธ.
  • update_config(filepath, key, new_value) โ€” Set the given top-level key to the given value in the given YAML config ๐Ÿงพ.
  • parser_with_common_options([provisioner_options, ...]) โ€” Get a command-line option parser for a Toil subcommand ๐Ÿ’ป.
  • addOptions(parser[, jobstore_as_flag, cwl, wdl]) โ€” Add all Toil command line options to a parser ๐ŸŽ€.
  • getNodeID() โ€” Return unique ID of the current node (host). The resulting string will be convertible to a uuid.UUID ๐Ÿ†”.
  • cacheDirName(workflowID) ๐Ÿ—ƒ๏ธ
  • getDirSizeRecursively(dirPath) โ€” This method will return the cumulative number of bytes occupied by the files ๐Ÿ“.
  • getFileSystemSize(dirPath) โ€” Return the free space, and total size of the file system hosting dirPath ๐Ÿ’พ.
  • safeUnpickleFromStream(stream) ๐Ÿฅ’

Module Contents

  • toil.common.UUID_LENGTH = 32 ๐Ÿ”ข
  • toil.common.logger ๐Ÿ“

โœจ toil.common.get_default_config_path()

Get the default path where the Toil configuration file lives ๐Ÿ“. The file at that path won't necessarily exist, so don't panic if it's missing ๐Ÿ™ˆ.

Return type: str

โœจ class toil.common.Config

Class to represent configuration operations for a Toil workflow run โš™๏ธ.

Here are the attributes, bestie ๐Ÿ’…:

  • logFile: str | None
  • logRotating: bool
  • cleanWorkDir: str
  • max_jobs: int
  • max_local_jobs: int
  • manualMemArgs: bool
  • run_local_jobs_on_workers: bool
  • coalesceStatusCalls: bool
  • mesos_endpoint โ€” ๐Ÿ’– str | None
  • mesos_framework_id โ€” โœจ str | None
  • mesos_role โ€” ๐ŸŽ€ str | None
  • mesos_name โ€” ๐Ÿฆ‹ str
  • kubernetes_host_path โ€” ๐ŸŒธ str | None
  • kubernetes_owner โ€” ๐Ÿ’… str | None
  • kubernetes_service_account โ€” ๐Ÿซถ str | None
  • kubernetes_pod_timeout โ€” โฑ๏ธ float
  • kubernetes_privileged โ€” ๐Ÿ”ฅ bool
  • kubernetes_pod_security_context โ€” ๐Ÿ” str | None
  • kubernetes_security_context โ€” ๐Ÿ” str | None
  • tes_endpoint โ€” ๐ŸŒˆ str
  • tes_user โ€” ๐Ÿงš str
  • tes_password โ€” ๐Ÿ™ˆ str
  • tes_bearer_token โ€” ๐Ÿ‘‘ str
  • aws_batch_region โ€” โ˜๏ธ str | None
  • aws_batch_queue โ€” ๐Ÿ“ str | None
  • aws_batch_job_role_arn โ€” ๐ŸŽญ str | None
  • scale โ€” โญ float
  • batchSystem โ€” ๐Ÿงƒ str
  • batch_logs_dir โ€” ๐Ÿ“‚ str | None The backing scheduler gets asked (if it's able to) to save its logs into this directory, so the leader can go read them. Lowkey so helpful ๐Ÿซถ
  • statePollingWait โ€” ๐Ÿ’œ float
  • state_polling_timeout โ€” โŒ› int
  • disableAutoDeployment โ€” ๐Ÿšซ bool
  • workflowID โ€” ๐Ÿ†” str | None This one is the main character ๐Ÿ‘‘ It uniquely identifies the job store, and therefore the whole workflow. It's what lets you tell apart two back-to-back workflows that share the same self.jobStore, like when someone reuses a job store name after a previous run finished successfully and its job store got cleaned up. Iykyk ๐Ÿ’…
  • workflowAttemptNumber โ€” ๐Ÿ” int
  • jobStore โ€” ๐Ÿ—„๏ธ str
  • logLevel โ€” ๐Ÿ“ฃ str
  • colored_logs โ€” ๐ŸŒˆ bool
  • workDir โ€” ๐Ÿ“ str | None
  • coordination_dir โ€” ๐Ÿค str | None
  • noStdOutErr โ€” ๐Ÿค bool
  • stats โ€” ๐Ÿ“Š bool
  • clean โ€” ๐Ÿงน str | None
  • clusterStats โ€” ๐Ÿ“ˆ str
  • restart โ€” ๐Ÿ”„ bool
  • caching โ€” ๐Ÿ’พ bool | None
  • symlinkImports โ€” ๐Ÿ”— bool
  • moveOutputs โ€” ๐Ÿšš bool
  • symlink_job_store_reads โ€” ๐Ÿ”— bool
  • provisioner โ€” ๐Ÿ—๏ธ str | None
  • nodeTypes โ€” ๐Ÿ–ฅ๏ธ list[tuple[set[str], float | None]]
  • minNodes โ€” ๐Ÿ“‰ list[int]
  • maxNodes โ€” ๐Ÿ“ˆ list[int]
  • targetTime โ€” ๐ŸŽฏ float
  • betaInertia โ€” ๐ŸŒ€ float
  • scaleInterval โ€” โฒ๏ธ int
  • preemptibleCompensation โ€” โš–๏ธ float
  • nodeStorage โ€” ๐Ÿ’ฝ int
  • nodeStorageOverrides โ€” ๐Ÿ—‚๏ธ list[str]
  • metrics โ€” ๐Ÿ“ bool
  • assume_zero_overhead โ€” ๐Ÿซง bool
  • maxPreemptibleServiceJobs โ€” ๐Ÿฆบ int
  • maxServiceJobs โ€” ๐Ÿ› ๏ธ int
  • deadlockWait โ€” ๐ŸงŠ float | int
  • deadlockCheckInterval โ€” ๐Ÿ” float | int
  • defaultMemory โ€” ๐Ÿง  int
  • defaultCores โ€” ๐Ÿงฎ float | int
  • defaultDisk โ€” ๐Ÿ’ฟ int
  • defaultPreemptible โ€” ๐Ÿซ  bool
  • defaultAccelerators โ€” ๐Ÿš€ list[toil.job.AcceleratorRequirement]
  • maxCores โ€” ๐Ÿงฎ int
  • maxMemory โ€” ๐Ÿง  int
  • maxDisk โ€” ๐Ÿ’ฟ int
  • retryCount โ€” ๐Ÿ”‚ int
  • stop_on_first_failure โ€” ๐Ÿ›‘ bool
  • enableUnlimitedPreemptibleRetries โ€” โ™พ๏ธ bool
  • doubleMem โ€” ๐Ÿฅž bool
  • maxJobDuration โ€” โณ int
  • rescueJobsFrequency โ€” ๐Ÿš‘ int
  • job_store_timeout โ€” โฐ float
  • maxLogFileSize โ€” ๐Ÿ“„ int
  • writeLogs โ€” โœ๏ธ str
  • writeLogsGzip โ€” ๐Ÿ—œ๏ธ str
  • writeLogsFromAllJobs โ€” ๐Ÿ“š bool
  • write_messages โ€” ๐Ÿ’Œ str | None
  • realTimeLogging โ€” โšก bool
  • publish_workflow_metrics โ€” ๐Ÿ“ก Literal['all'] | Literal['current'] | Literal['no'] | None
  • environment โ€” ๐ŸŒ dict[str, str]
  • disableChaining โ€” โ›“๏ธ bool
  • disableJobStoreChecksumVerification: bool ๐Ÿ’– is a true-or-false switch.
  • sseKey: str | None ๐Ÿ” is some text, or nothing at all.
  • servicePollingInterval: int ๐Ÿงš is a whole number.
  • useAsync: bool โญ is a true-or-false switch.
  • forceDockerAppliance: bool ๐Ÿณ is a true-or-false switch.
  • statusWait: int โณ is a whole number.
  • disableProgress: bool ๐ŸŒˆ is a true-or-false switch.
  • readGlobalFileMutableByDefault: bool ๐Ÿฆ‹ is a true-or-false switch.
  • debugWorker: bool ๐Ÿ™ˆ is a true-or-false switch.
  • disableWorkerOutputCapture: bool ๐ŸŽ€ is a true-or-false switch.
  • badWorker: float ๐Ÿ“ is a decimal number.
  • badWorkerFailInterval: float ๐Ÿ“ is a decimal number.
  • kill_polling_interval: int ๐Ÿ’€ is a whole number.
  • cwl: bool ๐ŸŒธ is a true-or-false switch.
  • memory_is_product: bool ๐Ÿ‘‘ is a true-or-false switch.

set_from_default_config() ๐ŸŒธ

Okay so this one doesn't come with a description, just a return type.

  • Return type: None

prepare_start() โœจ

After the options are set, this gets everything ready for the very first start of a workflow. Main character setup, bestie ๐Ÿ’…

  • Return type: None

prepare_restart() ๐Ÿ”

Before the restart options are set, this gets things ready for restarting a workflow. It sets up any execution-specific parameters and clears out any stale ones ๐Ÿงน

  • Return type: None

setOptions(options) ๐ŸŽ€

This one makes a config object out of the options object. Literally the whole point ๐Ÿซถ

  • Parameters
    • options (argparse.Namespace)
  • Return type: None

check_configuration_consistency() ๐Ÿ™ˆ

Old checks that couldn't be squeezed into an action class for argparse. Vintage, but still doing the job ๐Ÿ•ฐ๏ธ

  • Return type: None

__eq__(other) ๐Ÿ’œ

  • Parameters
    • other (object)
  • Return type: bool

__hash__() ๐Ÿ”ข

  • Return type: int

toil.common.ensure_config(filepath) ๐Ÿงš

If the config file at the filepath doesn't exist yet, this creates it. The parent directory should already exist before you call this, bestie ๐Ÿ“

It raises an error if the config file can't be created. It's safe to run at the same time in multiple processes. If this process is the one running the function, it will always see the config file existing with parseable contents, even if other processes are racing to create it. No process will ever see a new empty or partially-written config file ๐Ÿซง

The caller should still check to make sure there isn't a preexisting empty file here, iykyk ๐Ÿ‘€

  • filepath (str) โ€” path to config file
  • Returns: None
  • Return type: None

toil.common.generate_config(filepath) ๐Ÿ“

This writes a Toil config file to the given path. It's safe to run simultaneously in multiple processes, and no process will see an empty or partially-written file at that path. Obsessed ๐Ÿ˜ญ

Set include to "cwl" or "wdl" to include cwl options and wdl options, respectively. Choose your fighter ๐Ÿ’…

  • filepath (str)
  • Return type: None

toil.common.update_config(filepath, key, new_value) ๐Ÿ”ง

This sets the given top-level key to the given value in the given YAML config file. It doesn't dramatically mess with comments or formatting, and it doesn't make a partially-written file visible to anyone. Gentle giant energy ๐Ÿฆ‹

  • key (str) โ€” the setting you want to change
  • filepath (str)
  • new_value (Union[str, bool, int, float])
  • Return type: None
Heads up, bestie! The key has to be the command-line option name, NOT the destination variable name. Mixing those up is a whole mood ๐Ÿ’€

toil.common.parser_with_common_options(provisioner_options=False, jobstore_option=True, prog=None, default_log_level=None) ๐Ÿ“

This gets you a command-line option parser for a Toil subcommand. The parser only comes with the basic stuff (like version reporting and logging) that every Toil subcommand uses.

Toil Python workflows should use toil.job.Job.Runner.getDefaultArgumentParser() instead! That one makes sure you get all the important options for actually running a workflow. Don't skip it ๐Ÿ™…โ€โ™€๏ธ
  • provisioner_options (bool)
  • jobstore_option (bool)
  • prog (Optional[str])
  • default_log_level (Optional[int])
  • Return type: configargparse.ArgParser

toil.common.addOptions(parser, jobstore_as_flag=False, cwl=False, wdl=False) ๐ŸŽ€

This adds all the Toil command line options to a parser. It also gives you support for config files when you're using configargparse, and it checks and sets up the default config file while it's at it. Such a multitasker โœจ

  • jobstore_as_flag (bool) โ€” makes the job store option a --jobStore flag instead of a required jobStore positional argument
  • cwl (bool) โ€” whether CWL options are expected. If they are, CWL options won't get suppressed
  • wdl (bool) โ€” whether WDL options are expected. If they are, WDL options won't get suppressed
  • parser (argparse.ArgumentParser)
  • Return type: None

toil.common.getNodeID() ๐Ÿ†”

This returns the unique ID of the current node (host). The resulting string can be converted into a uuid.UUID. Very precise, very iconic ๐Ÿ’–

It tries several methods until one succeeds. The returned ID should be identical across calls from different processes on the same node, at least until the next OS reboot.

The last-resort method is uuid.getnode(), which in some rare OS configurations may return a random ID every time it's called. Honestly, this should never be reached on a Linux system, because reading from /proc/sys/kernel/random/boot_id gets tried first. If uuid.getnode() does get reached, it gets called twice, and an exception is raised if the two values aren't identical. Yikes ๐Ÿ˜ญ

  • Return type: str

class toil.common.Toil(options, workflow_name=None, trs_spec=None) ๐Ÿ‘‘

Bases: ContextManager[Toil]

This is a context manager that represents a Toil workflow. Specifically, it covers the batch system, the job store, and its configuration. It's giving main character ๐Ÿ’…

  • options (argparse.Namespace)
  • workflow_name (Optional[str])
  • trs_spec (Optional[str])

Attributes:

  • config: Config
  • options

__enter__() ๐Ÿšช

This derives the configuration from the command line options. Then it loads the job store and, on a restart, consolidates the derived configuration with the one from the previous invocation of the workflow.

  • Return type: Toil

__exit__(exc_type, exc_val, exc_tb) ๐Ÿงน

This cleans up after a workflow invocation. Depending on the configuration, it deletes the job store. Clean girl energy, no cap ๐Ÿซง

  • exc_type (Optional[type[BaseException]])
  • exc_val (Optional[BaseException])
  • exc_tb (Optional[types.TracebackType])
  • Return type: Literal[False]

start(rootJob) ๐Ÿš€

Invoke a Toil workflow with the given job as the root for an initial run. Let's gooo ๐Ÿ”ฅ

This one has to be called inside a with Toil(...) as toil: block, so no sneaking it in anywhere else ๐Ÿ™…โ€โ™€๏ธ And it shouldn't be called more than once for a workflow that hasn't finished yet, bestie, or things get messy ๐Ÿ’€

Parameters

  • rootJob (toil.job.Job) โ€” the root job of the workflow ๐ŸŒธ

Returns

  • The root job's return value โœจ

Return type

  • Any

restart()

Okay, this is your comeback move ๐Ÿ”„ If a workflow got interrupted, restart() brings it back to life.

Returns

  • The root job's return value โœจ

Return type

  • Any

JOB_STORE_TYPES

This is the lineup of job store types you can work with ๐Ÿงš

JOB_STORE_TYPES = ['file', 'aws', 'google']

classmethod getJobStore(locator)

This one is giving matchmaker energy ๐Ÿ’˜ You hand it a locator and it creates the right concrete job store implementation to match.

  • locator (str) โ€” the location of the job store that the new instance will represent ๐Ÿ“

Returns

  • an instance of a concrete subclass of AbstractJobStore ๐Ÿ’–

Return type

  • toil.jobStores.abstractJobStore.AbstractJobStore

static parseLocator(locator)

Parses a job store locator into a type string and the data that implementation needs to connect ๐Ÿ” Heads up: it does not check whether the job store type is one of the valid ones, so it's not the bouncer ๐Ÿ™ˆ

If the locator isn't written in the right syntax, this one raises RuntimeError ๐Ÿ’€ Double-check your locator before you pass it in.

Parameters

  • locator (str)

Return type

  • tuple[str, str]

static buildLocator(name, rest)

The opposite vibe of parseLocator. This one builds a locator string out of its pieces ๐Ÿงฉ

Parameters

  • name (str)
  • rest (str)

Return type

  • str

classmethod canonical_locator(locator)

Turns a job store locator into one that works from any directory ๐Ÿ—บ๏ธ It also always spells out the explicit type of job store, so no guessing games ๐Ÿซถ

Parameters

  • locator (str)

Return type

  • str

classmethod resumeJobStore(locator)

Gets you back into an existing job store ๐Ÿฆ‹

Parameters

  • locator (str)

Return type

  • toil.jobStores.abstractJobStore.AbstractJobStore

static createBatchSystem(config)

Creates the batch system that your config asked for โš™๏ธ It's basically the setup crew for the job runner ๐Ÿ‘ทโ€โ™€๏ธ

  • config (Config) โ€” the current configuration

Returns

  • an instance of a concrete subclass of AbstractBatchSystem ๐Ÿ”ฅ

Return type

  • toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

url_exists(src_uri)

Checks whether a URI actually exists ๐Ÿ‘€

Parameters

  • src_uri (str)

Return type

  • bool

importFile and import_file

These bring a file from a URL into the job store ๐Ÿ“ฅ Here are all the signatures, the overloads included, so you can see what each version hands back ๐Ÿ’…

importFile(srcUrl: str, sharedFileName: str, symlink: bool = True) -> None
importFile(srcUrl: str, sharedFileName: None = None, symlink: bool = True) -> toil.fileStores.FileID
import_file(src_uri: str, shared_file_name: str, symlink: bool = True, check_existence: bool = True) -> None
import_file(src_uri: str, shared_file_name: None = None, symlink: bool = True, check_existence: Literal[True] = True) -> toil.fileStores.FileID
import_file(src_uri: str, shared_file_name: None = None, symlink: bool = True, check_existence: bool = True) -> toil.fileStores.FileID | None

Imports the file at the given URL into the job store ๐ŸŒˆ By default, it returns None if the file does not exist.

  • check_existence โ€” if true, it raises FileNotFoundError when the file doesn't exist. If false, it returns None when the file doesn't exist ๐Ÿ™ƒ

For the full tea, see toil.jobStores.abstractJobStore.AbstractJobStore.importFile() ๐Ÿ“š


exportFile(jobStoreFileID, dstUrl)

The reverse of importing: this sends a file out of the job store ๐Ÿ“ค

Parameters

  • jobStoreFileID (toil.fileStores.FileID)
  • dstUrl (str)

Return type

  • None

export_file(file_id, dst_uri)

Exports a file to the destination pointed at by the destination URL ๐Ÿš€

For a full description, see toil.jobStores.abstractJobStore.AbstractJobStore.exportFile() ๐Ÿ’œ

Parameters

  • file_id (toil.fileStores.FileID)
  • dst_uri (str)

Return type

  • None

static normalize_uri(uri, check_existence=False, dir_path=None)

Given a URI with no scheme, this makes it a properly quoted file: URI ๐ŸŽ€

Parameters

  • check_existence (bool) โ€” if set, it raises FileNotFoundError when a URI points to a local file that doesn't exist ๐Ÿ‘ป
  • dir_path (Optional[str]) โ€” if specified, relative paths get interpreted relative to this directory instead of the current one ๐Ÿ—‚๏ธ
  • uri (str)

Return type

  • str

static getToilWorkDir(configWorkDir=None)

Returns a path to a writable directory that holds the per-workflow directories ๐Ÿ“

This directory is always required to exist on a machine, even if the Toil worker hasn't run yet ๐Ÿซ  If your workers and leader have different temp directories, you may need to set TOIL_WORKDIR.

Parameters

  • configWorkDir (Optional[str]) โ€” the value passed to the program using the --workDir flag ๐Ÿ“

Returns

  • Path to the Toil work directory, constant across all machines ๐ŸŒ

Return type

  • str

classmethod get_toil_coordination_dir(config_work_dir, config_coordination_dir)

Returns a path to a writable directory, which will live in memory if that's convenient ๐Ÿง  This is the one to use for file locking and coordination ๐Ÿ”’

Parameters

  • config_work_dir (Optional[str]) โ€” the value passed to the program using the --workDir flag โœจ
  • config_coordination_dir (Optional[str], linked to /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” ๐Ÿ’– whatever value got passed to the program with the --coordinationDir flag.
  • workflow_id โ€” ๐Ÿงš used when a tmpdir_prefix exists, so it can build full directory paths that are unique to each workflow.

Returns ๐ŸŒธ the path to the Toil coordination directory. It should sit on a POSIX filesystem that lets you delete directories even when they still contain open files.

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿฆ‹ static get_workflow_path_component(workflow_id)

Gets a filesystem-safe path component for a workflow. It stays consistent for all processes on a given machine, and it's different for all processes on different machines. Very reliable, very iconic. ๐Ÿ‘‘

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the current Toil workflow.

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ’… classmethod getLocalWorkflowDir(workflowID, configWorkDir=None)

Returns the directory where worker directories and the cache will live for this workflow on this machine. Main character energy. โœจ

  • configWorkDir (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the value passed to the program with the --workDir flag.
  • workflowID (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Returns ๐ŸŒˆ the path to the local workflow directory on this machine.

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿซถ classmethod get_local_workflow_coordination_dir(workflow_id, config_work_dir, config_coordination_dir)

Returns the directory where coordination files should go for this workflow on this machine. These include Toil's internal databases and the lock files for the machine. ๐Ÿ”’

If an in-memory filesystem is available, it gets used. Otherwise, it falls back to the local workflow directory, which might be on a shared network filesystem.

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the unique ID of the current workflow.
  • config_work_dir (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the value used for the work directory in the current Toil Config.
  • config_coordination_dir (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the value used for the coordination directory in the current Toil Config.

Returns ๐Ÿ“ the path to the local workflow coordination directory on this machine.

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐ŸŽ€ exception toil.common.ToilRestartException(message)

Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)

The common base class for all non-exit exceptions. ๐Ÿ™ˆ

  • message (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŽ€ exception toil.common.ToilContextManagerException

Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)

Also the common base class for all non-exit exceptions. Same iconic energy. ๐ŸŒธ


๐Ÿ”ฅ class toil.common.ToilMetrics(bus, provisioner=None)

  • bus (toil.bus.MessageBus, <#toil.bus.MessageBus>)
  • provisioner (Optional[toil.provisioners.abstractProvisioner.AbstractProvisioner], <#toil.provisioners.abstractProvisioner.AbstractProvisioner>)

Attributes ๐Ÿ’œ

mtailImage = 'quay.io/ucsc_cgl/toil-mtail:9.1.2-355b72ba0e425619c0367562caf2a337078dba65-py3.13'
grafanaImage = 'quay.io/ucsc_cgl/toil-grafana:9.1.2-355b72ba0e425619c0367562caf2a337078dba65-py3.13'
prometheusImage = 'quay.io/ucsc_cgl/toil-prometheus:9.1.2-355b72ba0e425619c0367562caf2a337078dba65-py3.13'
  • nodeExporterProc: subprocess.Popen[bytes] | None = None (subprocess.Popen at /usr/share/doc/python3/html/library/subprocess.html#subprocess.Popen, bytes at /usr/share/doc/python3/html/library/stdtypes.html#bytes, None at /usr/share/doc/python3/html/library/constants.html#None)

Methods ๐Ÿงš

  • startDashboard(clusterName, zone) โ€” starts the dashboard. โœจ
    • clusterName (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
    • zone (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • add_prometheus_data_source() โ€” adds the Prometheus data source. ๐Ÿฆ‹
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • log(message) โ€” logs a message. ๐Ÿ’ฌ
    • message (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • logClusterSize(m) โ€” logs the cluster size. ๐Ÿ“
    • m (toil.bus.ClusterSizeMessage, <#toil.bus.ClusterSizeMessage>)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • logClusterDesiredSize(m) โ€” logs the desired cluster size. ๐ŸŽฏ
    • m (toil.bus.ClusterDesiredSizeMessage, <#toil.bus.ClusterDesiredSizeMessage>)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • logQueueSize(m) โ€” logs the queue size. ๐Ÿ“ฌ
    • m (toil.bus.QueueSizeMessage, <#toil.bus.QueueSizeMessage>)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • logMissingJob(m) โ€” logs a missing job. ๐Ÿซฅ
    • m (toil.bus.JobMissingMessage, <#toil.bus.JobMissingMessage>)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • logIssuedJob(m) โ€” logs an issued job. ๐Ÿš€
    • m (toil.bus.JobIssuedMessage, <#toil.bus.JobIssuedMessage>)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • logFailedJob(m) โ€” logs a failed job. ๐Ÿ’€
    • m (toil.bus.JobFailedMessage, <#toil.bus.JobFailedMessage>)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • logCompletedJob(m) โ€” logs a completed job. ๐ŸŽ‰
    • m (toil.bus.JobCompletedMessage, <#toil.bus.JobCompletedMessage>)
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)
  • shutdown() โ€” shuts everything down. ๐ŸŒ™
    • Return type: None (/usr/share/doc/python3/html/library/constants.html#None)

๐ŸŒท toil.common.cacheDirName(workflowID)

Returns ๐Ÿซง the name of the cache directory.

  • workflowID (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ“ฆ toil.common.getDirSizeRecursively(dirPath)

This one adds up the number of bytes taken up by files on disk in the directory and all of its subdirectories. ๐Ÿงฎ

If it can't access a file or directory, whether because of insufficient permissions or because the file or directory was removed while the function was walking through it, the error is handled internally. You'll get back a lower bound on the size of the directory, which could even be 0. ๐Ÿ™ˆ

  • dirPath (toil.lib.misc.StrPath, <#toil.lib.misc.StrPath>) โ€” a valid path to a directory or file.

Returns ๐Ÿ“ the total size, in bytes, of the file or directory at dirPath.

Return type: int (/usr/share/doc/python3/html/library/functions.html#int)


๐ŸŒŠ toil.common.getFileSystemSize(dirPath)

Returns the free space and the total size of the filesystem that hosts dirPath. ๐Ÿ’พ

  • dirPath (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” a valid path to a directory.

Returns ๐Ÿซถ the free space and total size of the file system, as a pair.

Return type: tuple[int, int] (/usr/share/doc/python3/html/library/stdtypes.html#tuple, with int at /usr/share/doc/python3/html/library/functions.html#int)


๐Ÿฅž toil.common.safeUnpickleFromStream(stream)

  • stream (IO[Any])

Return type: Any


๐ŸŒˆ toil.cwl

Submodules ๐Ÿงš

  • toil.cwl.conftest

๐Ÿ’– toil.cwl.conftest

Attributes

  • collect_ignore โ€” empty right now. ๐Ÿซง

Module Contents

toil.cwl.conftest.collect_ignore = []

๐Ÿฆ‹ toil.cwl.cwltoil

Implements support for the Common Workflow Language (CWL) in Toil. ๐ŸŒธ

โœจ Attributes โœจ

okay so this next bit is the attributes list, bestie ๐Ÿ’… the page just names them without giving any extra description, so here's the full lineup ๐Ÿซถ

  • logger ๐Ÿชต
  • DEFAULT_TMPDIR ๐Ÿ“‚
  • DEFAULT_TMPDIR_PREFIX ๐ŸŒธ
  • MISSING_FILE ๐Ÿ™ˆ
  • V โญ
  • ProcessType ๐Ÿ”ฅ
  • T ๐Ÿฆ‹
  • usage_message ๐Ÿ’œ

โœจ Exceptions โœจ

and now the exceptions, which are giving main character energy ๐Ÿ‘‘

  • NoAvailableJobStoreException ๐Ÿ’€ โ€” this one gets thrown when no job store name is available, so if you see it, check that you actually gave Toil a job store name ๐ŸŽ€

โœจ Classes โœจ

okay bestie, here's the whole class lineup ๐Ÿ’… (tables don't render in the terminal, so it's bullets for us ๐Ÿซถ)

  • UnresolvedDict โ€” a tag that says "hey, this dict is still full of promises that need resolving" ๐ŸŽ€
  • SkipNull โ€” an internal sentinel object, basically a secret handshake only Toil knows ๐Ÿ™ˆ
  • Conditional โ€” holds a conditional expression on ice until we're actually ready to evaluate it ๐ŸงŠ
  • ResolveSource โ€” applies the linkMerge and pickValue operators to values coming into a port ๐Ÿ”—
  • StepValueFrom โ€” a workflow step input with a valueFrom expression attached ๐Ÿ’ซ
  • DefaultWithSource โ€” a workflow step input that has both a source and a default value ๐ŸŒธ
  • JustAValue โ€” a simple value dressed up as a 'resolve'-able object, lowkey iconic ๐Ÿ’โ€โ™€๏ธ
  • ToilPathMapper โ€” keeps track of files the Toil way ๐Ÿ—‚๏ธ
  • ToilSingleJobExecutor โ€” a SingleJobExecutor that doesn't assume it's at the top level of the workflow ๐Ÿงš
  • ToilTool โ€” a mixin that hooks Toil into a cwltool tool type ๐Ÿ”Œ
  • ToilCommandLineTool โ€” subclasses the cwltool command line tool to provide the custom ToilPathMapper ๐Ÿ› ๏ธ
  • ToilExpressionTool โ€” subclasses the cwltool expression tool to provide the custom ToilPathMapper ๐Ÿงฎ
  • ToilFsAccess โ€” custom filesystem access class that handles Toil filestore references ๐Ÿ“‚
  • VisitFunc โ€” no description given in the original, so this one's a mystery ๐Ÿ•ต๏ธ
  • CWLNamedJob โ€” base class for all CWL jobs that do user work, giving them useful names ๐Ÿท๏ธ
  • ResolveIndirect โ€” a helper Job ๐Ÿค
  • CWLJobWrapper โ€” wraps a CWL job that uses the dynamic resources requirement ๐ŸŽ
  • CWLJob โ€” executes a CWL tool using cwltool.executors.SingleJobExecutor ๐Ÿƒโ€โ™€๏ธ
  • CWLScatter โ€” implements the workflow scatter step ๐ŸŒˆ
  • CWLGather โ€” follows on from a scatter Job, the clean-up crew ๐Ÿงน
  • SelfJob โ€” a fake job object that makes CWLWorkflow.run() easier to implement ๐ŸŽญ
  • CWLWorkflow โ€” a Toil Job that converts a CWL workflow graph into a Toil job graph ๐Ÿง 
  • CWLInstallImportsJob โ€” a class that represents a unit of work in toil ๐Ÿ“ฆ
  • CWLImportWrapper โ€” a Job that organizes importing files on workers instead of the leader ๐Ÿšš. It's responsible for extracting filenames and metadata,
  • CWLStartJob โ€” the Job responsible for starting the CWL workflow ๐Ÿš€

โœจ Functions โœจ

  • cwltoil_was_removed() โ€” yells at you that this entrypoint is deprecated ๐Ÿ˜ค
  • filter_skip_null(name, value) โ€” recursively filters out SkipNull objects from value ๐Ÿงผ
  • ensure_no_collisions(directory[, dir_description]) โ€” makes sure no items in the given CWL Directory share the same name ๐Ÿ‘ฏ
  • try_prepull(cwl_tool_uri, runtime_context, batchsystem) โ€” Give it a whirl at prepulling every container in a CWL workflow, using either Singularity or Docker. ๐Ÿณโœจ
  • resolve_dict_w_promises(dict_w_promises[, file_store]) โ€” Takes a dictionary full of promises, evaluates the expressions inside, and spits out the actual values. Iconic glow-up ๐Ÿ’…
  • simplify_list(maybe_list) โ€” Turns a length one list, the kind cwltool loves to hand you, into a plain scalar. Less clutter, more vibes ๐Ÿซถ
  • toil_make_tool(toolpath_object, loadingContext) โ€” Emits custom ToilCommandLineTools. Custom and proud ๐Ÿฆ‹
  • toil_get_file(file_store, index, existing, uri[, ...]) โ€” Sets up the given file or directory from the Toil jobstore at a file URI. Pull it up, bestie ๐Ÿ“‚
  • convert_file_uri_to_toil_uri(applyFunc, index, ...) โ€” Takes a file URI and converts it into a toil file URI. The applyFunc argument is the one doing the actual conversion work ๐Ÿ”„
  • path_to_loc(obj) โ€” Turns a path into a location. Literally that's it, it's giving simple ๐Ÿ“
  • extract_file_uri_once(fileindex, existing, file_metadata) โ€” Pulls the filename out of a CWL file record. Once. Just once ๐ŸŽ€
  • visit_files(func, fs_access, fileindex, existing, ...) โ€” Preps all the files and directories. Everybody gets prepared, no exceptions ๐ŸŒธ
  • upload_directory(directory_metadata, directory_contents) โ€” Uploads a Directory object. Up it goes โ˜๏ธ
  • extract_and_convert_file_to_toil_uri(convertfunc, ...) โ€” Pulls the file URI out of a file object and converts it into a Toil URI. Two-step glow-up ๐Ÿ’–
  • writeGlobalFileWrapper(file_store, fileuri) โ€” Wraps writeGlobalFile so it can accept <file://> URIs. Now it understands the assignment ๐Ÿงš
  • remove_empty_listings(rec) โ€” No description given ๐Ÿ™ˆ
  • toilStageFiles(toil, cwljob, outdir[, destBucket, ...]) โ€” Copies input files out of the global file store and updates their location and path. Moving day, but make it organised ๐Ÿšš
  • get_container_engine(runtime_context) โ€” No description given ๐Ÿ™ˆ
  • makeRootJob(tool, jobobj, runtime_context, ...) โ€” Creates the Toil root Job object for the CWL tool. It's the same as makeJob(), except this one also handles import logic. Main character energy, literally ๐Ÿ‘‘
  • makeJob(tool, jobobj, runtime_context, parent_name, ...) โ€” Creates the correct Toil Job object for the CWL tool. Right job, right time โญ
  • remove_pickle_problems(obj) โ€” Heads up! Doc_loader does not pickle correctly, which causes Toil errors, so this one removes the troublemakers from objects. Pickle drama, be gone ๐Ÿ’€
  • extract_workflow_inputs(options, ...) โ€” Collects all the workflow input files so they can be imported later. A little hoarding, but make it cute ๐Ÿงบ
  • import_workflow_inputs(jobstore, options, ...[, log_level]) โ€” Imports all workflow inputs on the leader. Leader gets all the credit ๐Ÿ‘‘
  • visitSteps(cmdline_tool, op) โ€” Iterates over a CWL Process object and runs the op on each tool description. Every step, every time ๐Ÿ’œ
  • rm_unprocessed_secondary_files(job_params) โ€” No description given ๐Ÿ™ˆ
  • filtered_secondary_files(unfiltered_secondary_files) โ€” Removes unprocessed secondary files. Bye bye, not today ๐Ÿ“
  • scan_for_unsupported_requirements(tool[, ...]): sweeps through the given CWL tool and flags any optional features Toil doesn't support yet ๐Ÿ™ˆ
  • determine_load_listing(tool): figures out what's going on with the directory.listing feature in CWL ๐Ÿ“‚
  • generate_default_job_store(batch_system_name, ...): picks a default job store that fits the requested batch system and
  • get_options(args): parses your args and neatly tucks any non-Toil arguments into the cwljob of the Namespace ๐ŸŽ€
  • main([args, stdout]): runs the main loop for toil-cwl-runner ๐Ÿ‘‘ the whole show
  • find_default_container(args, builder): finds the default constructor by checking in with a Toil.options object ๐Ÿงš

โœจ Module Contents โœจ

the module contents are giving full catalogue energy ๐Ÿ’…

toil.cwl.cwltoil.logger

toil.cwl.cwltoil.DEFAULT_TMPDIR

toil.cwl.cwltoil.DEFAULT_TMPDIR_PREFIX

toil.cwl.cwltoil.cwltoil_was_removed()

This one is a deprecation scolding for the old entrypoint ๐Ÿ™„

Return type: None

class toil.cwl.cwltoil.UnresolvedDict

Bases: dict[Any, Any]

A tag that says a dict still holds promises that need resolving ๐Ÿซถ

class toil.cwl.cwltoil.SkipNull

Internal sentinel object, so this one is strictly behind the scenes ๐Ÿคซ It marks a null value produced by each port of a skipped conditional step. The CWL 1.2 spec says to treat it exactly the same as a null value ๐Ÿ’€

toil.cwl.cwltoil.filter_skip_null(name, value)

Recursively filters out SkipNull objects from value ๐Ÿงน

  • Parameters
    • name (str): the name of the port that produced this value. It's only used when we find an unhandled null from a conditional step and print a warning. The name helps the user figure out which step/port caused the unhandled null ๐Ÿ•ต๏ธ
    • value (Any): port output value object

Return type: Any

toil.cwl.cwltoil.ensure_no_collisions(directory, dir_description=None)

Makes sure no items in the given CWL Directory share the same name. If any do, it raises a WorkflowException about a "File staging conflict" ๐Ÿšจ It does not recurse into subdirectories.

  • Parameters
    • directory (cwltool.utils.DirectoryType)
    • dir_description (Optional[str])

Return type: None

toil.cwl.cwltoil.try_prepull(cwl_tool_uri, runtime_context, batchsystem)

Tries to prepull all containers in a CWL workflow using Singularity or Docker ๐Ÿณ It will not prepull the default container specified on the command line.

  • Parameters
    • cwl_tool_uri (str): CWL workflow URL. Fragments are accepted too.
    • runtime_context (cwltool.context.RuntimeContext): runtime context of cwltool
    • batchsystem (str): type of Toil batchsystem

Return type: None

class toil.cwl.cwltoil.Conditional(expression=None, outputs=None, requirements=None, container_engine='docker')

Holds a conditional expression until we're ready to evaluate it ๐Ÿค” Evaluation happens before the enclosing step's inputs get type-checked.

  • Parameters
    • expression (Optional[str])
    • outputs (Union[dict[str, cwltool.utils.CWLOutputType], None])
    • requirements (Optional[list[cwltool.utils.CWLObjectType]])
    • container_engine (str)

Class attributes

  • expression = None
  • outputs
  • requirements = []
  • container_engine = 'docker'
  • is_false(job): checks whether the expression comes out to False given the completed step inputs.
    • job (cwltool.utils.CWLObjectType): job output object
    • Returns: bool
    • Return type: bool
  • skipped_outputs(): generates a dict of SkipNull objects that match the output structure ๐Ÿซง
    • Return type: dict[str, SkipNull]

class toil.cwl.cwltoil.ResolveSource(name, input, source_key, promises)

Applies the linkMerge and pickValue operators to values coming into a port ๐Ÿ”€

  • Parameters
    • name (str)
    • input (dict[str, cwltool.utils.CWLObjectType])
    • source_key (str)
    • promises (dict[str, toil.job.Job])

Attribute

  • promise_tuples: list[tuple[str, toil.job.Promise]] | tuple[str, toil.job.Promise]
  • __repr__(): allows for debug printing ๐Ÿ›
    • Return type: str
  • resolve(): applies linkMerge first, then pickValue, if either one is present
    • Return type: Any
  • link_merge(values): applies the linkMerge operator to the values object
    • values (cwltool.utils.CWLObjectType): result of step
    • Return type: Union[list[cwltool.utils.CWLOutputType], cwltool.utils.CWLOutputType]
  • pick_value(values): applies the pickValue operator to the values object
    • values (Union[list[Union[str, SkipNull]], Any]): intended to be a list, but other types get returned without modification
    • Returns
    • Return type: Any

class toil.cwl.cwltoil.StepValueFrom(expr, source, req, container_engine)

A workflow step input with a valueFrom expression attached to it ๐ŸŽ€

The valueFrom expression gets evaluated to spit out the actual input object for the step ๐Ÿ’…โœจ

๐ŸŽ€ Parameters

  • expr (str)
  • source (Any)
  • req (list[cwltool.utils.CWLObjectType])
  • container_engine (str)

The fields on this one are expr, source, context = None, req, and container_engine. ๐Ÿฆ‹

๐Ÿ’– __repr__()

Allow for debug printing. ๐ŸŒธ

Return type: str

๐Ÿซถ eval_prep(step_inputs, file_store)

Resolve the contents of any file in a set of inputs. ๐Ÿ“‚

The inputs must be associated with the StepValueFrom object's self.source. Bestie, this one is important ๐Ÿ˜ญ

This gets called when loadContents is specified. โœจ

๐ŸŽ€ Parameters

  • step_inputs (cwltool.utils.CWLObjectType) โ€” the workflow step inputs ๐Ÿ“
  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore) โ€” a Toil file store. You need it to resolve toilfile:// paths, so don't skip it ๐Ÿ’œ

Return type: None

๐Ÿ‘‘ resolve()

Resolve the promise in the valueFrom expression's context. It's giving promise-keeping ๐Ÿ”ฅ

Returns: an object that will serve as the expression context

Return type: Any

๐Ÿ’… do_eval(inputs)

Evaluate the valueFrom expression using the given input object. โญ

Parameters:

  • inputs (cwltool.utils.CWLObjectType)

Returns: an object

Return type: Any


๐Ÿงš class toil.cwl.cwltoil.DefaultWithSource(default, source)

A workflow step input that has both a source and a default value. Two options, one input, zero drama ๐ŸŒˆ

๐ŸŽ€ Parameters

  • default (Any)
  • source (Any)

The attributes are default and source. ๐Ÿฆ‹

๐Ÿ’– __repr__()

Allow for debug printing. ๐ŸŒธ

Return type: str

๐Ÿ‘‘ resolve()

Figure out the final input value when the time is right, meaning once the source can actually be resolved. Patience is a virtue, babe ๐Ÿ™ˆ

Returns: dict

Return type: Any


๐Ÿงš class toil.cwl.cwltoil.JustAValue(val)

A simple value dressed up as a resolve-able object. It's giving imposter, but make it cute ๐ŸŽ€

๐ŸŽ€ Parameters

  • val (Any)

The attribute here is val. ๐Ÿ’œ

๐Ÿ’– __repr__()

Allow for debug printing. ๐ŸŒธ

Return type: str

๐Ÿ‘‘ resolve()

Return the value. That's it, that's the whole method ๐Ÿ’…

Return type: Any


๐ŸŒˆ toil.cwl.cwltoil.resolve_dict_w_promises(dict_w_promises, file_store=None)

Resolve a dictionary of promises and evaluate expressions to produce the actual values. Main character energy for this function โœจ

๐ŸŽ€ Parameters

  • dict_w_promises (Union[UnresolvedDict, cwltool.utils.CWLObjectType, dict[str, Union[str, StepValueFrom]]]) โ€” the input dict for these values ๐Ÿ“
  • file_store (Optional[toil.fileStores.abstractFileStore.AbstractFileStore])

Returns: a dictionary of actual values

Return type: cwltool.utils.CWLObjectType


๐ŸŒธ toil.cwl.cwltoil.simplify_list(maybe_list)

Turn a length-one list loaded by cwltool into a scalar. Anything else gets passed through as-is, by reference. Simple, clean, iconic ๐Ÿฆ‹

Parameters:

  • maybe_list (Any)

Return type: Any


๐Ÿงš class toil.cwl.cwltoil.ToilPathMapper(referenced_files, basedir, stagedir, separateDirs=True, get_file=None, stage_listing=False, streaming_allowed=True)

Bases: cwltool.pathmapper.PathMapper

Okay so this class keeps track of files the Toil way ๐Ÿ—‚๏ธโœจ It maps between three things: the symbolic identifier of a file (the Toil FileID), its local path on the host (the value returned by readGlobalFile), and where the file lives inside the software container. Three identities, one file, very iykyk ๐Ÿ’…

๐ŸŽ€ Parameters

  • referenced_files (list[cwltool.utils.CWLObjectType])
  • basedir (str)
  • stagedir (str)
  • separateDirs (bool)
  • get_file (Union[Any, None])
  • stage_listing (bool)
  • streaming_allowed (bool)

The attributes are get_file = None, stage_listing = False, and streaming_allowed = True. ๐Ÿ’–

๐Ÿซถ visit(obj, stagedir, basedir, copy=False, staged=False)

Iterate over a CWL object and resolve File and Directory path references. This gets called on every File or Directory CWL object. Those all have location fields: for Files they come from upload_file(), and for Directories they come from upload_directory() or cwltool internally. With upload_directory(), the Directories and their children get locations by listing the Directories through ToilFsAccess. With cwltool, locations get set as absolute paths. Lots of moving parts, but it all works out ๐Ÿ”ฅ

๐ŸŽ€ Parameters

  • obj (cwltool.utils.CWLObjectType) โ€” the CWL File or Directory to process ๐Ÿ“
  • stagedir (str) โ€” the base path for target paths to be generated under, except when a File or Directory has an overriding parent directory in dirname
  • basedir (str) โ€” the directory relative paths get resolved from. It's used as the base directory for the StdFsAccess that generated the listing being processed ๐ŸŒฟ
  • copy (bool) โ€” if set, use writable types for Files and Directories โœ๏ธ
  • staged (bool) โ€” this starts as True at the top of the recursion. It gets set to False when entering a directory that we can actually download, so we don't stage files and subdirectories separately from the directory as a whole. It controls the staged flag on generated mappings, which decides whether files and directories actually get placed at their mapped-to target locations. If stage_listing is True, it stays True the whole way through and everything gets staged ๐Ÿซง

Return type: None

Each unique location for a File or Directory gets exactly one MapperEnt. Think of these as instructions for cwltool's stage_files function. You can check it out here: https://github.com/common-workflow-language/cwltool/blob/a3e3a5720f7b0131fa4f9c0b3f73b62a347278a6/cwltool/process.py#L254 ๐Ÿฆ‹

A MapperEnt has these fields:

  • resolved: an absolute local path anywhere on the filesystem where the file or directory can be found. It can also be the contents of a file to populate it with, if the type is CreateWritableFile or CreateFile. Or it can be a URI understood by the StdFsAccess in use, like toilfile:.
  • target: an absolute path under stagedir where cwltool will then place the file or directory. The exception is when a File or Directory has a dirname field giving its parent path. Then that gets used instead ๐Ÿ“
  • type: one of the following:
    • File: cwltool will copy or link the file from resolved to target, if possible.
    • CreateFile: cwltool will create the file at target, treating resolved as the contents.
    • WritableFile: cwltool will copy the file from resolved to target, making it writable.
    • CreateWritableFile: cwltool will create the file at target, treating resolved as the contents, and make it writable.
    • Directory: cwltool will copy or link the directory from resolved to target, if possible. Otherwise, if resolved starts with "_:", cwltool will make the directory at target. Otherwise it does nothing. ๐ŸŒท
  • WritableDirectory: okay so if it's possible, cwltool copies the directory from resolved over to target ๐Ÿ“. If it can't do that and resolved starts with "_:", cwltool makes a fresh directory at target ๐ŸŒธ. Otherwise it does absolutely nothing ๐Ÿ™ˆ.
  • staged: if you set this to False, cwltool won't make or copy anything for that entry ๐Ÿšซ. Main character decision ๐Ÿ’….

๐Ÿฆ‹ class toil.cwl.cwltoil.ToilSingleJobExecutor

Bases: cwltool.executors.SingleJobExecutor (docs at /usr/share/doc/cwltool/html/autoapi/cwltool/executors/index.html#cwltool.executors.SingleJobExecutor)

A SingleJobExecutor that does not assume it's at the top level of the workflow โœจ. Why does this matter? Otherwise every job thinks it's top level and tries to discover secondary files. Those files might exist even when they haven't actually been passed at the top level, so they aren't supposed to be visible ๐Ÿ‘€. Iykyk.

๐Ÿ’– run_jobs

run_jobs(process, job_order_object, logger, runtime_context)

This is run_jobs from SingleJobExecutor, just not in a top level runtime context ๐Ÿงš.

Parameters:

  • process (cwltool.process.Process, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)
  • job_order_object (cwltool.utils.CWLObjectType)
  • logger (logging.Logger, docs at /usr/share/doc/python3/html/library/logging.html#logging.Logger)
  • runtime_context (cwltool.context.RuntimeContext, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext)

Return type: None ๐Ÿซถ

๐ŸŒˆ class toil.cwl.cwltoil.ToilTool

class toil.cwl.cwltoil.ToilTool(*args, **kwargs)

This is a mixin that hooks Toil into a cwltool tool type ๐Ÿ”ฅ.

Parameters:

  • args (Any)
  • kwargs (Any)

๐ŸŽ€ connect_toil_job

connect_toil_job(job)

Attaches the Toil tool to the Toil job that's executing it ๐Ÿ”—. This lets it use the Toil job to stop at certain points if debugging flags are set ๐Ÿ›.

Parameters:

  • job (toil.job.Job, anchor #toil.job.Job)

Return type: None

๐Ÿ“ make_path_mapper

make_path_mapper(reffiles, stagedir, runtimeContext, separateDirs)

Creates the appropriate PathMapper for the situation ๐Ÿ—บ๏ธ.

Parameters:

  • reffiles (list[Any], docs at /usr/share/doc/python3/html/library/stdtypes.html#list)
  • stagedir (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)
  • runtimeContext (cwltool.context.RuntimeContext, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext)
  • separateDirs (bool, docs at /usr/share/doc/python3/html/library/functions.html#bool)

Return type: cwltool.pathmapper.PathMapper (docs at /usr/share/doc/cwltool/html/autoapi/cwltool/pathmapper/index.html#cwltool.pathmapper.PathMapper)

๐Ÿ’œ __str__

__str__()

Returns the string representation of this tool type ๐ŸŽค.

Return type: str (docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ‘‘ class toil.cwl.cwltoil.ToilCommandLineTool

class toil.cwl.cwltoil.ToilCommandLineTool(*args, **kwargs)

Bases: ToilTool, cwltool.command_line_tool.CommandLineTool (docs at /usr/share/doc/cwltool/html/autoapi/cwltool/command_line_tool/index.html#cwltool.command_line_tool.CommandLineTool)

This subclasses the cwltool command line tool so it can use the custom ToilPathMapper ๐Ÿ› ๏ธ.

Parameters:

  • args (Any)
  • kwargs (Any)

๐ŸŒธ class toil.cwl.cwltoil.ToilExpressionTool

class toil.cwl.cwltoil.ToilExpressionTool(*args, **kwargs)

Bases: ToilTool, cwltool.command_line_tool.ExpressionTool (docs at /usr/share/doc/cwltool/html/autoapi/cwltool/command_line_tool/index.html#cwltool.command_line_tool.ExpressionTool)

This subclasses the cwltool expression tool so it can use the custom ToilPathMapper ๐Ÿงฎ.

Parameters:

  • args (Any)
  • kwargs (Any)

๐Ÿงš toil.cwl.cwltoil.toil_make_tool

toil.cwl.cwltoil.toil_make_tool(toolpath_object, loadingContext)

This is a factory function that emits custom ToilCommandLineTools ๐Ÿญ. It's meant to be passed to cwltool.load_tool() ๐Ÿ’….

Parameters:

  • toolpath_object (ruamel.yaml.comments.CommentedMap)
  • loadingContext (cwltool.context.LoadingContext, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.LoadingContext)

Return type: cwltool.process.Process (docs at /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)

๐Ÿ™ˆ MISSING_FILE

toil.cwl.cwltoil.MISSING_FILE = 'missing://'

๐Ÿฆ‹ class toil.cwl.cwltoil.ToilFsAccess

class toil.cwl.cwltoil.ToilFsAccess(basedir, file_store=None)

Bases: cwltool.stdfsaccess.StdFsAccess (docs at /usr/share/doc/cwltool/html/autoapi/cwltool/stdfsaccess/index.html#cwltool.stdfsaccess.StdFsAccess)

This is a custom filesystem access class that handles Toil filestore references ๐Ÿ—ƒ๏ธ. Normal file paths get resolved relative to basedir ๐Ÿ“‚. But toilfile: and toildir: URIs get fulfilled from the Toil file store โœจ.

It also supports URLs that are supported by Toil job store implementations ๐ŸŒ.

Parameters:

  • basedir (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)
  • file_store (Optional[toil.fileStores.abstractFileStore.AbstractFileStore], anchor #toil.fileStores.abstractFileStore.AbstractFileStore)

๐ŸŒท Attributes

  • file_store: None
  • dir_to_download: dict[str, str] (docs at /usr/share/doc/python3/html/library/stdtypes.html#dict)

๐Ÿ“ glob

glob(pattern)

Returns a possibly empty list of absolute URI paths that match pathname ๐Ÿ”.

Parameters:

  • pattern (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: list[str] (docs at /usr/share/doc/python3/html/library/stdtypes.html#list)

๐ŸŽ€ open

open(fn, mode)

Parameters:

  • fn (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)
  • mode (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: IO[Any]

๐Ÿ’… exists

exists(path)

Tests for file existence ๐Ÿ‘€.

Parameters:

  • path (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: bool (docs at /usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿซถ size

size(path)

Parameters:

  • path (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: int (docs at /usr/share/doc/python3/html/library/functions.html#int)

๐ŸŒˆ isfile

isfile(fn)

Parameters:

  • fn (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: bool (docs at /usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿงš isdir

isdir(fn)

Parameters:

  • fn (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: bool (docs at /usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿ”ฅ listdir

listdir(fn)

Returns a list containing the absolute path URLs of the entries in the directory given by path ๐Ÿ“‹.

Parameters:

  • fn (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: list[str] (docs at /usr/share/doc/python3/html/library/stdtypes.html#list)

โญ join

join(path, *paths)

Joins one or more path segments intelligently ๐Ÿงฉ.

Parameters:

  • path (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)
  • paths (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ“ realpath

realpath(fn)

Parameters:

  • fn (str, docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ’– toil.cwl.cwltoil.toil_get_file

toil.cwl.cwltoil.toil_get_file(file_store, index, existing, uri, streamable=False, streaming_allowed=True, pipe_threads=None)

This sets up the given file or directory from the Toil jobstore at a file URI where it can be accessed locally ๐Ÿ“ฅ. It runs as part of tool setup, inside jobs on the workers ๐Ÿ—๏ธ. It's also used when reorganizing files so they get uploaded at the end of a tool ๐Ÿ“ค.

Parameters:

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore, anchor #toil.fileStores.abstractFileStore.AbstractFileStore): the Toil file store to download from ๐Ÿ’พ.
  • index (dict[str, str], docs at /usr/share/doc/python3/html/library/stdtypes.html#dict): maps from the downloaded file path back to the input Toil URI ๐Ÿ—บ๏ธ.
  • existing (dict[str, str]) โ€” it maps each URI to the path where that file got downloaded ๐Ÿ—บ๏ธ
  • uri (str) โ€” the URI of the file you want to download ๐ŸŒธ
  • streamable (bool) โ€” tells you whether the file has the 'streamable' flag set ๐Ÿ’…
  • streaming_allowed (bool) โ€” whether streaming is allowed โœจ
  • pipe_threads (Optional[list[tuple[threading.Thread, int]]]) โ€” a list of the threads doing the streaming, each paired with the open file descriptors for those files. You're on the hook for closing the file descriptors (that's how the pipes get broken) and joining the threads ๐Ÿงต

Return type str


๐Ÿฆ‹ toil.cwl.cwltoil.convert_file_uri_to_toil_uri

toil.cwl.cwltoil.convert_file_uri_to_toil_uri(applyFunc, index, existing, file_uri)

Okay so this one takes a file URI and turns it into a toil file URI โœจ It uses applyFunc to do the actual conversion. It runs once on every unique file URI, so no doubles ๐Ÿ’…

existing is a set of files that came in as inputs from toil_get_file. That's what makes sure they get mapped back to the same name if they get passed through ๐Ÿซถ

It returns a toil URI path to the object ๐ŸŒˆ

Parameters

  • applyFunc (Callable[[str], toil.fileStores.FileID])
  • index (dict[str, str])
  • existing (dict[str, str])
  • file_uri (str)

Return type str


๐Ÿงš toil.cwl.cwltoil.path_to_loc

toil.cwl.cwltoil.path_to_loc(obj)

This one turns a path into a location ๐Ÿ“ It's for CWL objects that have a "path" but not a "location".

Parameters

  • obj (cwltool.utils.CWLObjectType)

Return type None


๐ŸŒธ toil.cwl.cwltoil.extract_file_uri_once

toil.cwl.cwltoil.extract_file_uri_once(fileindex, existing, file_metadata, mark_broken=False, skip_remote=False)

This one pulls the filename out of a CWL file record ๐Ÿ“‚ It matches the predefined function signature in visit_files, which is how it ends up getting called on every file inside a CWL object ๐Ÿ”ฅ

It makes sure no duplicate files come back, going by fileindex. If a file hasn't been resolved yet (and had <file://> prepended), it resolves symlinks. Here's the tea on the params:

  • fileindex: the forward mapping of filename
  • existing: the reverse mapping of filename, which this function does not use ๐Ÿ™ˆ
  • file_metadata: the CWL file record
  • mark_broken: whether files should be marked as missing
  • skip_remote: whether to skip remote files
  • :return: has no description in the docs

Parameters

  • fileindex (dict[str, str])
  • existing (dict[str, str])
  • file_metadata (cwltool.utils.CWLObjectType)
  • mark_broken (bool)
  • skip_remote (bool)

Return type Optional[str]


๐Ÿ’œ toil.cwl.cwltoil.V

Just a type variable named V, nothing else documented for this one ๐Ÿ™ˆ


๐ŸŽ€ class toil.cwl.cwltoil.VisitFunc

Bases: Protocol[V]

__call__(fileindex, existing, file_metadata, mark_broken, skip_remote)

Parameters

  • fileindex (dict[str, str])
  • existing (dict[str, str])
  • file_metadata (cwltool.utils.CWLObjectType)
  • mark_broken (bool)
  • skip_remote (bool)

Return type V


๐ŸŒˆ toil.cwl.cwltoil.visit_files

toil.cwl.cwltoil.visit_files(func, fs_access, fileindex, existing, cwl_object, mark_broken=False, skip_remote=False, bypass_file_store=False)

Okay this one prepares all files and directories โœจ It runs from the leader or a worker, in the context of the given CWL tool, order, or output object, so the workers can use everything. It makes sure their sizes are set and imports all the files ๐Ÿ“ฆ

It recurses inside directories using fs_access to find files to upload and the subdirectory structure to encode, even if their listings aren't set or aren't recursive. Any listing fields get preserved ๐Ÿซถ

If a file can't be found (like an optional secondary file that doesn't exist), it fails. The exception is when mark_broken is set, then it applies a sentinel location instead ๐Ÿ˜ญ It also does some miscellaneous normalization ๐Ÿงน

Parameters

  • import_function โ€” the function used to upload a URI and get a Toil FileID for it
  • fs_access (cwltool.stdfsaccess.StdFsAccess) โ€” the CWL FS access object we use to get at the filesystem and find files to import. It needs to support the URI schemes used.
  • fileindex (dict[str, str]) โ€” the forward map to fill in from file URI to Toil storage location, which write_file uses to dedupe writes
  • existing (dict[str, str]) โ€” the reverse map to fill in from Toil storage location to file URI. It's never read from.
  • cwl_object (Optional[cwltool.utils.CWLObjectType]) โ€” the CWL tool (or workflow order) we're importing files for
  • mark_broken (bool) โ€” if True, files that can't be imported (because they e.g. don't exist) get their locations set to MISSING_FILE instead of failing with an error
  • skp_remote โ€” if True, remote URIs get left in place instead of imported
  • bypass_file_store (bool) โ€” if True, <file://> URIs get left in place instead of importing files and directories
  • log_level โ€” log imported files at the given level
  • func (VisitFunc[V])
  • skip_remote (bool)

Return type list[V]


๐Ÿ“ toil.cwl.cwltoil.upload_directory

toil.cwl.cwltoil.upload_directory(directory_metadata, directory_contents, mark_broken=False)

This one uploads a Directory object ๐Ÿ“ It ignores the listing (which may not be recursive, and isn't safe or efficient to touch) and uses directory_contents instead. That's a recursive dict structure going from filename to file URI, or to a subdirectory contents dict ๐ŸŒณ

It makes sure the directory actually exists and rewrites its location so it's something we can use on another machine ๐Ÿฆ‹

If mark_broken is set, it ignores missing directories and replaces them with directories holding the given (possibly empty) contents ๐Ÿซง

We can't rely on the directory's listing as the next tool sees it being a complete recursive description of the files we'll need to show the tool ๐Ÿ’€. Some tools need it cleared or single-level, but still expect to see its contents in the filesystem ๐Ÿ™ˆ

Parameters

  • directory_metadata (cwltool.utils.CWLObjectType)
  • directory_contents (toil.lib.directory.DirectoryContents)
  • mark_broken (bool) ๐Ÿ™ˆ

Return type: None

๐Ÿฆ‹ toil.cwl.cwltoil.extract_and_convert_file_to_toil_uri

toil.cwl.cwltoil.extract_and_convert_file_to_toil_uri(convertfunc, fileindex, existing, file_metadata, mark_broken=False, skip_remote=False)

Okay so this one is a whole vibe ๐Ÿ’… It pulls the file URI out of a file object and converts it into a Toil URI โœจ

It runs convertfunc on the file URI to handle the conversion, and it's what gets used when files are imported into the jobstore ๐Ÿงš

If a file doesn't exist, it fails with an errorโ€ฆ unless mark_broken is set, in which case the missing file gets a special sentinel location ๐Ÿ™ˆ

Unless skip_remote is set, it also runs on remote files and sets their locations to Toil URIs too ๐ŸŒˆ

Parameters

  • convertfunc (Callable[[str], toil.fileStores.FileID])
  • fileindex (dict[str, str])
  • existing (dict[str, str])
  • file_metadata (cwltool.utils.CWLObjectType)
  • mark_broken (bool)
  • skip_remote (bool)

Return type: None

๐ŸŽ€ toil.cwl.cwltoil.writeGlobalFileWrapper

toil.cwl.cwltoil.writeGlobalFileWrapper(file_store, fileuri)

This is basically writeGlobalFile with a glow-up: it accepts file:// URIs now ๐Ÿ’–

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)
  • fileuri (str)

Return type: toil.fileStores.FileID

๐ŸŒธ toil.cwl.cwltoil.remove_empty_listings

toil.cwl.cwltoil.remove_empty_listings(rec)

Parameters

  • rec (cwltool.utils.CWLObjectType)

Return type: None

๐Ÿ‘‘ class toil.cwl.cwltoil.CWLNamedJob

class toil.cwl.cwltoil.CWLNamedJob(cores=1, memory='1GiB', disk='1MiB', accelerators=None, preemptible=None, tool_id=None, parent_name=None, subjob_name=None, local=None)

Bases: toil.job.Job

Base class for all CWL jobs that do actual user work, so they get useful names ๐Ÿท๏ธโœจ

Parameters

  • cores (Union[float, None])
  • memory (Union[int, str, None])
  • disk (Union[int, str, None])
  • accelerators (Optional[list[toil.job.AcceleratorRequirement]])
  • preemptible (Optional[bool])
  • tool_id (Optional[str])
  • parent_name (Optional[str])
  • subjob_name (Optional[str])
  • local (Optional[bool])

๐Ÿงš class toil.cwl.cwltoil.ResolveIndirect

class toil.cwl.cwltoil.ResolveIndirect(cwljob, parent_name=None)

Bases: CWLNamedJob

A helper Job ๐Ÿซถ It takes an unresolved dict (the kind full of promises) and hands back a dictionary of actual values ๐Ÿ’œ

Parameters

  • cwljob (toil.job.Promised[cwltool.utils.CWLObjectType])
  • parent_name (Optional[str])

Attributes

  • cwljob

run(file_store)

Evaluates the promises and returns their values ๐Ÿ”ฅ

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type: cwltool.utils.CWLObjectType

๐Ÿ“ toil.cwl.cwltoil.toilStageFiles

toil.cwl.cwltoil.toilStageFiles(toil, cwljob, outdir, destBucket=None, log_level=logging.DEBUG)

This one copies input files out of the global file store and updates their location and path ๐Ÿ“ฆ

Parameters

  • toil (toil.common.Toil)
  • cwljob (Union[cwltool.utils.CWLObjectType, list[cwltool.utils.CWLObjectType]])
  • outdir (str)
  • destBucket (Union[str, None]) โ€” If set, it exports to this base URL instead of the local filesystem ๐ŸŒ
  • log_level (int) โ€” Logs each file transferred at the given level ๐Ÿ“

Return type: None

๐Ÿฆ‹ class toil.cwl.cwltoil.CWLJobWrapper

class toil.cwl.cwltoil.CWLJobWrapper(tool, cwljob, runtime_context, parent_name, conditional=None)

Bases: CWLNamedJob

Wraps a CWL job that uses a dynamic resources requirement ๐Ÿ’… When it runs, it creates a new child job with the correct resource requirement set โœจ

Parameters

  • tool (cwltool.process.Process)
  • cwljob (cwltool.utils.CWLObjectType)
  • runtime_context (cwltool.context.RuntimeContext)
  • parent_name (Optional[str])
  • conditional (Union[Conditional, None])

Attributes

  • cwltool
  • cwljob
  • runtime_context
  • conditional
  • parent_name

run(file_store)

Creates a child job with the correct resource requirements set ๐ŸŽ€

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type: Any

๐Ÿ’– class toil.cwl.cwltoil.CWLJob

class toil.cwl.cwltoil.CWLJob(tool, cwljob, runtime_context, parent_name=None, conditional=None)

Bases: CWLNamedJob

This is the one that actually runs a CWL tool, using cwltool.executors.SingleJobExecutor ๐Ÿ”ฅ๐Ÿ‘‘

Parameters

  • tool (cwltool.process.Process)
  • cwljob (cwltool.utils.CWLObjectType)
  • runtime_context (cwltool.context.RuntimeContext)
  • parent_name (Optional[str])
  • conditional (Union[Conditional, None])

Attributes

  • cwltool
  • conditional
  • cwljob
  • runtime_context
  • step_inputs
  • workdir: str

required_env_vars(cwljob)

Yields environment variables from EnvVarRequirement ๐ŸŒˆ

Parameters

  • cwljob (Any)

Return type: Iterator[tuple[str, str]]

populate_env_vars(cwljob)

Prepares the environment variables the job needs at runtime ๐Ÿซถ

Env vars specified in the CWL "requirements" section should already be loaded in self.cwltool.requirements. However, the ones specified with "EnvVarRequirement" take precedence and only get populated here. So this doesn't just return a dictionary with all the evaluated "EnvVarRequirement" env vars ๐Ÿ’… It also checks self.cwltool.requirements for any env vars with the same name and swaps their value for the one found in the "EnvVarRequirement" env var, if there is one โœจ

Parameters

  • cwljob (cwltool.utils.CWLObjectType)

Return type: dict[str, str]

run(file_store)

Executes the CWL document ๐Ÿš€

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type: Any

๐ŸŒˆ toil.cwl.cwltoil.get_container_engine

toil.cwl.cwltoil.get_container_engine(runtime_context)

Parameters

  • runtime_context โ€” the cwltool.context.RuntimeContext (/usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext) ๐ŸŒธ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str), a plain string, bestie โœจ

๐ŸŒณ toil.cwl.cwltoil.makeRootJob

toil.cwl.cwltoil.makeRootJob(tool, jobobj, runtime_context, initialized_job_order, options, toil)

okay so this one builds the root Job for your CWL tool ๐Ÿ’… It's basically the same as makeJob(), but it also handles the import logic, so it's the one you want for the very start of things ๐Ÿซถ

It can actually make a little subgraph of two jobs. The second one might be the follow on of the first. If it only makes one job, you get that same job back twice, which is giving consistency ๐Ÿงš

Returns: nothing is listed here, it's blank ๐Ÿ™ˆ

Parameters

  • tool โ€” a cwltool.process.Process (/usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process) ๐ŸŽ€
  • jobobj โ€” a cwltool.utils.CWLObjectType ๐ŸŽ€
  • runtime_context โ€” the cwltool.context.RuntimeContext (/usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext) ๐ŸŽ€
  • initialized_job_order โ€” a cwltool.utils.CWLObjectType ๐ŸŽ€
  • options โ€” a configargparse.Namespace ๐ŸŽ€
  • toil โ€” a toil.common.Toil (<#toil.common.Toil>) ๐ŸŽ€

Return type: CWLNamedJob (<#toil.cwl.cwltoil.CWLNamedJob>) ๐Ÿ’–


๐Ÿฆ‹ toil.cwl.cwltoil.makeJob

toil.cwl.cwltoil.makeJob(tool, jobobj, runtime_context, parent_name, conditional)

this is the one that creates the correct Toil Job object for your CWL tool, depending on what kind of tool it is ๐Ÿ”ฅ Same vibe as makeRootJob: it can make a subgraph of two jobs, where the second might be the follow on of the first, and if only one job gets made, it's returned twice ๐Ÿ‘‘

It's used for three types: workflow, job, or job wrapper for dynamic resource requirements ๐ŸŒˆ

Returns: "wfjob, followOn" if the input tool is a workflow, and "job, job" otherwise โœจ

Parameters

  • tool โ€” a cwltool.process.Process (/usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process) ๐ŸŽ€
  • jobobj โ€” a cwltool.utils.CWLObjectType ๐ŸŽ€
  • runtime_context โ€” the cwltool.context.RuntimeContext (/usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext) ๐ŸŽ€
  • parent_name โ€” an Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€
  • conditional โ€” a Union[Conditional] (<#toil.cwl.cwltoil.Conditional>), or None ๐ŸŽ€

Return type: a big union of tuples, so here it is verbatim ๐Ÿง 

Union[tuple[CWLWorkflow <#toil.cwl.cwltoil.CWLWorkflow>, ResolveIndirect <#toil.cwl.cwltoil.ResolveIndirect>],
tuple[CWLJob <#toil.cwl.cwltoil.CWLJob>, CWLJob <#toil.cwl.cwltoil.CWLJob>],
tuple[CWLJobWrapper <#toil.cwl.cwltoil.CWLJobWrapper>, CWLJobWrapper <#toil.cwl.cwltoil.CWLJobWrapper>]]

๐ŸŒธ toil.cwl.cwltoil.CWLScatter

class toil.cwl.cwltoil.CWLScatter(step, cwljob, runtime_context, parent_name, conditional)

Bases: toil.job.Job (<#toil.job.Job>) ๐Ÿ’œ

This is the workflow scatter step ๐Ÿฆ‹ When it runs, it makes a child job for every parameterization of the scatter. Main character energy, honestly ๐Ÿ‘‘

Parameters

  • step โ€” a cwltool.workflow.WorkflowStep (/usr/share/doc/cwltool/html/autoapi/cwltool/workflow/index.html#cwltool.workflow.WorkflowStep) ๐ŸŽ€
  • cwljob โ€” a cwltool.utils.CWLObjectType ๐ŸŽ€
  • runtime_context โ€” the cwltool.context.RuntimeContext (/usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext) ๐ŸŽ€
  • parent_name โ€” an Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€
  • conditional โ€” a Union[Conditional] (<#toil.cwl.cwltoil.Conditional>), or None ๐ŸŽ€

Attributes: step, cwljob, runtime_context, conditional, parent_name ๐Ÿ’…

๐Ÿ’– flat_crossproduct_scatter(joborder, scatter_keys, outputs, postScatterEval)

Cartesian product of the inputs, then flattened ๐ŸŒˆ

  • joborder โ€” a cwltool.utils.CWLObjectType ๐ŸŽ€
  • scatter_keys โ€” a list[str] (/usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€
  • outputs โ€” a list[toil.job.Promised[cwltool.utils.CWLObjectType]] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐ŸŽ€
  • postScatterEval โ€” a Callable[[cwltool.utils.CWLObjectType], cwltool.utils.CWLObjectType] ๐ŸŽ€

Return type: None ๐Ÿซถ

๐Ÿงš nested_crossproduct_scatter(joborder, scatter_keys, postScatterEval)

Cartesian product of the inputs ๐Ÿ’ซ

  • joborder โ€” a cwltool.utils.CWLObjectType ๐ŸŽ€
  • scatter_keys โ€” a list[str] (/usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€
  • postScatterEval โ€” a Callable[[cwltool.utils.CWLObjectType], cwltool.utils.CWLObjectType] ๐ŸŽ€

Return type: list[toil.job.Promised[cwltool.utils.CWLObjectType]] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿ“

๐Ÿ”ฅ run(file_store)

Generates the follow on scatter jobs ๐Ÿƒโ€โ™€๏ธ

  • file_store โ€” an toil.fileStores.abstractFileStore.AbstractFileStore (<#toil.fileStores.abstractFileStore.AbstractFileStore>) ๐ŸŽ€

Return type: list[toil.job.Promised[cwltool.utils.CWLObjectType]] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿ“


๐ŸŒˆ toil.cwl.cwltoil.CWLGather

class toil.cwl.cwltoil.CWLGather(step, outputs)

Bases: toil.job.Job (<#toil.job.Job>) ๐Ÿ’œ

This one follows on from a scatter Job ๐Ÿฆ‹ It gathers the outputs of each job in the scatter into an array, one array for each output parameter. So the scattered pieces all come back together, iykyk ๐Ÿซถ

Parameters

  • step โ€” a cwltool.workflow.WorkflowStep (/usr/share/doc/cwltool/html/autoapi/cwltool/workflow/index.html#cwltool.workflow.WorkflowStep) ๐ŸŽ€
  • outputs โ€” a toil.job.Promised[Union[cwltool.utils.CWLObjectType, list[cwltool.utils.CWLObjectType]]] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐ŸŽ€

Attributes: step, outputs ๐Ÿ’…

๐Ÿซง extract(obj, k) (static)

Pulls the given key out of the obj ๐Ÿ”‘ If the object is a list, it grabs that key from every member of the list โœจ

  • obj โ€” a Union[cwltool.utils.CWLObjectType, list[cwltool.utils.CWLObjectType]] ๐ŸŽ€
  • k โ€” a str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€

Return type: Union[cwltool.utils.CWLOutputType, list[cwltool.utils.CWLObjectType]] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿ“

๐ŸŒธ run(file_store)

Gathers all the outputs of the scatter ๐ŸŽ

  • file_store โ€” an toil.fileStores.abstractFileStore.AbstractFileStore (<#toil.fileStores.abstractFileStore.AbstractFileStore>) ๐ŸŽ€

Return type: dict[str, Any] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“


๐Ÿงš toil.cwl.cwltoil.SelfJob

class toil.cwl.cwltoil.SelfJob(j, v)

Bases: toil.job.Job (<#toil.job.Job>) ๐Ÿ’œ

This is a fake job object ๐Ÿ™ˆ It exists to make CWLWorkflow.run() easier to implement, and that's the whole tea โ˜•

Parameters

  • j โ€” a CWLWorkflow (<#toil.cwl.cwltoil.CWLWorkflow>) ๐ŸŽ€
  • v โ€” a cwltool.utils.CWLObjectType ๐ŸŽ€

Attributes: j, v ๐Ÿ’…

๐Ÿฆ‹ rv(*path)

Returns our properties dictionary ๐Ÿ“–

  • path โ€” an Any ๐ŸŽ€

Return type: Any ๐Ÿ“

๐Ÿ’– addChild(c)

Adds a child to our workflow ๐ŸŒฑ

  • c โ€” a toil.job.Job (<#toil.job.Job>) ๐ŸŽ€

Return type: Any ๐Ÿ“

๐Ÿซถ hasChild(c)

Checks if the given child is in our workflow ๐Ÿ‘€

  • c โ€” a toil.job.Job (<#toil.job.Job>) ๐ŸŽ€

Return type: Any ๐Ÿ“


๐Ÿ’œ toil.cwl.cwltoil.ProcessType

Just the name on this one, no description, bestie ๐Ÿซ 


๐Ÿซง toil.cwl.cwltoil.remove_pickle_problems(obj)

Doc_loader doesn't pickle correctly, which causes Toil errors, so this function removes it from objects ๐Ÿงน

See github issue: <https://github.com/mypyc/mypyc/issues/804> ๐Ÿ”—

  • obj โ€” a ProcessType ๐ŸŽ€

Return type: ProcessType ๐Ÿ“


๐Ÿ‘‘ toil.cwl.cwltoil.CWLWorkflow

class toil.cwl.cwltoil.CWLWorkflow(cwlwf, cwljob, runtime_context, parent_name=None, conditional=None)

Bases: CWLNamedJob ๐Ÿ’œ

This is the Toil Job that converts a CWL workflow graph into a Toil job graph โœจ The Toil job graph includes the appropriate dependencies, so everything is connected the right way ๐Ÿซถ

Parameters

  • cwlwf โ€” a cwltool.workflow.Workflow (/usr/share/doc/cwltool/html/autoapi/cwltool/workflow/index.html#cwltool.workflow.Workflow) ๐ŸŽ€
  • cwljob โ€” a cwltool.utils.CWLObjectType ๐ŸŽ€
  • runtime_context โ€” the cwltool.context.RuntimeContext (/usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext) ๐ŸŽ€

okay bestie, the list keeps going ๐Ÿ’–

  • parent_name โ€” Optional[str] (see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒธ
  • conditional โ€” Union[Conditional, None] (see toil.cwl.cwltoil.Conditional) โœจ

Attributes we get to peek at are cwlwf, cwljob, runtime_context, and conditional ๐Ÿฆ‹

๐Ÿงš run(file_store)

Okay so this one turns a CWL Workflow graph into a Toil job graph, and it is always run on the leader, because the batch system already knows to schedule it as a local job ๐Ÿ‘‘

Parameters ๐ŸŽ€

  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore

Return type ๐Ÿ’…

  • Union[UnresolvedDict, dict[str, SkipNull]], where the dict is /usr/share/doc/python3/html/library/stdtypes.html#dict, the str is /usr/share/doc/python3/html/library/stdtypes.html#str, UnresolvedDict is toil.cwl.cwltoil.UnresolvedDict, and SkipNull is toil.cwl.cwltoil.SkipNull ๐Ÿซถ

๐ŸŒˆ toil.cwl.cwltoil.CWLInstallImportsJob

class toil.cwl.cwltoil.CWLInstallImportsJob(initialized_job_order, tool,
basedir, skip_remote, bypass_file_store, import_data, **kwargs)

Bases: toil.job.Job. This class is a unit of work in toil, so it's giving job energy โœจ

Parameters ๐ŸŽ€

  • initialized_job_order โ€” toil.job.Promised[cwltool.utils.CWLObjectType]
  • tool โ€” toil.job.Promised[cwltool.process.Process] (see /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)
  • basedir โ€” str (see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • skip_remote โ€” bool (see /usr/share/doc/python3/html/library/functions.html#bool)
  • bypass_file_store โ€” bool (see /usr/share/doc/python3/html/library/functions.html#bool)
  • import_data โ€” list[toil.job.Promised[dict[str, toil.fileStores.FileID]]], where the list is /usr/share/doc/python3/html/library/stdtypes.html#list, the dict is /usr/share/doc/python3/html/library/stdtypes.html#dict, the str is /usr/share/doc/python3/html/library/stdtypes.html#str, and FileID is toil.fileStores.FileID ๐ŸŒธ
  • kwargs โ€” Any

Attributes ๐Ÿฆ‹ initialized_job_order, tool, basedir, skip_remote, bypass_file_store, import_data

๐Ÿ”ฅ fill_in_files(initialized_job_order, tool, candidate_to_fileid, basedir, skip_remote, bypass_file_store)

This is a static method, and it's lowkey iconic. Give it a mapping of filenames to Toil file IDs and it swaps every filename for its file ID all through the CWL object ๐Ÿ’–

Parameters ๐ŸŽ€

  • initialized_job_order โ€” cwltool.utils.CWLObjectType
  • tool โ€” cwltool.process.Process (see /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)
  • candidate_to_fileid โ€” dict[str, toil.fileStores.FileID], where the dict is /usr/share/doc/python3/html/library/stdtypes.html#dict, the str is /usr/share/doc/python3/html/library/stdtypes.html#str, and FileID is toil.fileStores.FileID
  • basedir โ€” str (see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • skip_remote โ€” bool (see /usr/share/doc/python3/html/library/functions.html#bool)
  • bypass_file_store โ€” bool (see /usr/share/doc/python3/html/library/functions.html#bool)

Return type ๐Ÿ’…

  • tuple[cwltool.process.Process, cwltool.utils.CWLObjectType], where the tuple is /usr/share/doc/python3/html/library/stdtypes.html#tuple, and the Process is /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process

๐Ÿงš run(file_store)

Okay so this one converts the filenames in the workflow inputs into URIs. It returns a Promise of the transformed workflow inputs, which is a tuple holding the job order and the process โญ

Parameters ๐ŸŽ€

  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore

Return type ๐Ÿ’…

  • Tuple[cwltool.process.Process, cwltool.utils.CWLObjectType] (cwltool.process.Process is /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)

๐Ÿฆ‹ toil.cwl.cwltoil.CWLImportWrapper

class toil.cwl.cwltoil.CWLImportWrapper(initialized_job_order, tool,
runtime_context, file_to_data, imported_files, options)

Bases: CWLNamedJob

Bestie, this job is the importer! It organizes importing files on the workers instead of the leader. It extracts the filenames and metadata, calls ImportsJob, applies the imports to the job objects, and schedules the start workflow job ๐Ÿซถ

This class is only used when runImportsOnWorkers is enabled. Don't go poking at it otherwise ๐Ÿ’€

Parameters ๐ŸŽ€

  • initialized_job_order โ€” cwltool.utils.CWLObjectType
  • tool โ€” cwltool.process.Process (see /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)
  • runtime_context โ€” cwltool.context.RuntimeContext (see /usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext)
  • file_to_data โ€” dict[str, toil.job.FileMetadata], where the dict is /usr/share/doc/python3/html/library/stdtypes.html#dict, the str is /usr/share/doc/python3/html/library/stdtypes.html#str, and FileMetadata is toil.job.FileMetadata
  • imported_files โ€” dict[str, toil.fileStores.FileID], where the dict is /usr/share/doc/python3/html/library/stdtypes.html#dict, the str is /usr/share/doc/python3/html/library/stdtypes.html#str, and FileID is toil.fileStores.FileID
  • options โ€” configargparse.Namespace

Attributes ๐ŸŒธ initialized_job_order, tool, runtime_context, file_to_data, imported_files, options

๐Ÿงš run(file_store)

Override this function to do the work and dynamically create successor jobs. It's giving customization energy ๐ŸŒˆ

Parameters ๐ŸŽ€

  • fileStore โ€” used to create local and globally sharable temporary files and to send log messages to the leader process.
  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore

Returns โœจ The return value can be passed to other jobs using toil.job.Job.rv().

Return type ๐Ÿ’…

  • Any

๐Ÿ’œ toil.cwl.cwltoil.CWLStartJob

class toil.cwl.cwltoil.CWLStartJob(tool, initialized_job_order,
runtime_context, **kwargs)

Bases: CWLNamedJob

This is the job that starts the CWL workflow. It takes in the workflow or tool and the inputs once every file has been imported, then creates the jobs that run those workflows ๐ŸŽ€

Parameters ๐ŸŽ€

  • tool โ€” toil.job.Promised[cwltool.process.Process] (see /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)
  • initialized_job_order โ€” toil.job.Promised[cwltool.utils.CWLObjectType]
  • runtime_context โ€” cwltool.context.RuntimeContext (see /usr/share/doc/cwltool/html/autoapi/cwltool/context/index.html#cwltool.context.RuntimeContext)
  • kwargs โ€” Any

Attributes ๐Ÿฆ‹ tool, initialized_job_order, runtime_context

๐Ÿงš run(file_store)

Override this function to do the work and dynamically create successor jobs, same vibe as before ๐Ÿ”ฅ

Parameters ๐ŸŽ€

  • fileStore โ€” used to create local and globally sharable temporary files and to send log messages to the leader process.
  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore

Returns โœจ The return value can be passed to other jobs using toil.job.Job.rv().

Return type ๐Ÿ’…

  • Any

๐Ÿ“ toil.cwl.cwltoil.extract_workflow_inputs

toil.cwl.cwltoil.extract_workflow_inputs(options, initialized_job_order,
tool)

Okay so this one collects all the workflow input files so they can be imported later ๐Ÿงš It takes options as a namespace, initialized_job_order as a CWL object, and tool as a tool object ๐Ÿ’–

Parameters ๐ŸŽ€

  • options โ€” configargparse.Namespace
  • initialized_job_order โ€” cwltool.utils.CWLObjectType
  • tool โ€” cwltool.process.Process (see /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)

Return type ๐Ÿ’…

  • list[str], where the list is /usr/share/doc/python3/html/library/stdtypes.html#list and the str is /usr/share/doc/python3/html/library/stdtypes.html#str

๐ŸŒธ toil.cwl.cwltoil.import_workflow_inputs

toil.cwl.cwltoil.import_workflow_inputs(jobstore, options,
initialized_job_order, tool, log_level=logging.DEBUG)

Bestie, this one imports all the workflow inputs on the leader. It runs when you're not importing on workers ๐Ÿ™ˆ It also takes a tool and a log_level, which defaults to logging.DEBUG, and it hands back nothing listed here, so no cap, that's the whole deal โœจ

Parameters ๐ŸŽ€

  • jobstore โ€” toil.jobStores.abstractJobStore.AbstractJobStore (the Toil jobstore)
  • options โ€” configargparse.Namespace (a namespace)
  • initialized_job_order โ€” cwltool.utils.CWLObjectType (the CWL object)
  • tool ๐ŸŽ€ (type cwltool.process.Process, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)
  • log_level ๐ŸŒธ (type int, docs at /usr/share/doc/python3/html/library/functions.html#int)

Return type ๐Ÿ’… None

โœจ toil.cwl.cwltoil.T

No details for this one, bestie. It's just a name sitting there ๐Ÿซ 

๐Ÿฆ‹ toil.cwl.cwltoil.visitSteps(cmdline_tool, op)

okay so this one iterates over a CWL Process object and runs op on each tool description CWL object ๐Ÿ”

Parameters ๐ŸŽ€

  • cmdline_tool (type cwltool.process.Process, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process)
  • op (type Callable[[ruamel.yaml.comments.CommentedMap], list[T]], docs for list at /usr/share/doc/python3/html/library/stdtypes.html#list)

Return type ๐Ÿ’– list[T] (docs for list at /usr/share/doc/python3/html/library/stdtypes.html#list)

๐ŸŒˆ toil.cwl.cwltoil.rm_unprocessed_secondary_files(job_params)

Parameters ๐ŸŽ€

  • job_params (type Any)

Return type None

๐Ÿซถ toil.cwl.cwltoil.filtered_secondary_files(unfiltered_secondary_files)

Removes unprocessed secondary files ๐Ÿ—‘๏ธ

Interpolated strings and optional inputs in secondary files only showed up in CWL 1.1 ๐Ÿ™ˆ.

The CWL libraries we call totally resolve those interpolated strings โœ…, but they also toss the resolved fields into the unresolved list, so we clean them out here after the fact.

We keep any secondary file whose location is anything other than MISSING_FILE ๐Ÿ“. The 'required' logic seems to live deeper in cwltool.builder.Builder(), and that's what correctly decides which files get imported ๐Ÿ’…. So we drop the files here. If one is SUPPOSED to exist, you'll still get the appropriate file does not exist error, just a bit further down the track ๐Ÿงš.

Parameters ๐ŸŽ€

  • unfiltered_secondary_files (type cwltool.utils.CWLObjectType)

Return type ๐Ÿ’– list[cwltool.utils.CWLObjectType] (docs for list at /usr/share/doc/python3/html/library/stdtypes.html#list)

๐Ÿ’€ toil.cwl.cwltoil.scan_for_unsupported_requirements(tool, bypass_file_store=False)

This one scans the given CWL tool for any unsupported optional features ๐Ÿ”. If it has them, it raises an informative UnsupportedRequirement ๐Ÿšจ.

Parameters ๐ŸŽ€

  • tool (type cwltool.process.Process, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process) โ€” the CWL tool to check for unsupported requirements.
  • bypass_file_store (type bool, docs at /usr/share/doc/python3/html/library/functions.html#bool) โ€” True if the Toil file store is not being used to transport files between nodes, and raw origin node <file://> URIs are exposed to tools instead.

Return type None

๐ŸŽ€ toil.cwl.cwltoil.determine_load_listing(tool)

In CWL, any input directory can have a DIRECTORY_NAME.listing (where DIRECTORY_NAME is any variable name) set to one of three options ๐Ÿ“‚:

  1. no_listing ๐Ÿ™… โ€” DIRECTORY_NAME.listing will be undefined. e.g.
inputs.DIRECTORY_NAME.listing == unspecified
  1. shallow_listing ๐ŸŒท โ€” DIRECTORY_NAME.listing will return a list one level deep of DIRECTORY_NAME's contents. e.g.
inputs.DIRECTORY_NAME.listing == [items in directory]
inputs.DIRECTORY_NAME.listing[0].listing == undefined
inputs.DIRECTORY_NAME.listing.length == # of items in directory
  1. deep_listing ๐ŸŒŠ โ€” DIRECTORY_NAME.listing will return a list of the entire contents of DIRECTORY_NAME. e.g.
inputs.DIRECTORY_NAME.listing == [items in directory]
inputs.DIRECTORY_NAME.listing[0].listing == [items in subdirectory if it exists and is the first item listed]
inputs.DIRECTORY_NAME.listing.length == # of items in directory

Check these out ๐Ÿ‘€: https://www.commonwl.org/v1.1/CommandLineTool.html#LoadListingRequirement and https://www.commonwl.org/v1.1/CommandLineTool.html#LoadListingEnum

Here's the priority order, periodt ๐Ÿ’…: DIRECTORY_NAME.listing should be determined first from loadListing. If that's not specified, it comes from LoadListingRequirement. Else, it defaults to "no_listing" if unspecified.

Parameters ๐ŸŽ€

  • tool (type cwltool.process.Process, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/process/index.html#cwltool.process.Process) โ€” ToilCommandLineTool

Return str ๐Ÿ’– One of 'no_listing', 'shallow_listing', or 'deep_listing'.

Return type Literal['no_listing', 'shallow_listing', 'deep_listing']

๐ŸŒธ exception toil.cwl.cwltoil.NoAvailableJobStoreException

Bases: Exception (docs at /usr/share/doc/python3/html/library/exceptions.html#Exception)

Basically means there's no job store name available ๐Ÿ’”.

๐Ÿงš toil.cwl.cwltoil.generate_default_job_store(batch_system_name, provisioner_name, local_directory)

This picks a default job store that fits the requested batch system and provisioner, plus whatever modules are installed ๐Ÿง . If there's no good default and you have to choose manually, it raises an error ๐Ÿšซ.

Parameters ๐ŸŽ€

  • batch_system_name (type Optional[str], docs for str at /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the registry name of the batch system the user requested, if any. If no name was requested, it should be None.
  • provisioner_name (type Optional[str], docs for str at /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the provisioner the user requested, if any. Recognized provisioners include 'aws' and 'gce'. None means no provisioner is in use.
  • local_directory (type str, docs for str at /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” path to a nonexistent local directory suitable for use as a file job store.

Return str ๐Ÿ’– The job store specifier for a usable job store โœจ.

Return type str (docs at /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ’œ toil.cwl.cwltoil.usage_message = Multiline-String

A multiline string that shows up as empty in the docs ๐Ÿซง

"""

"""

๐ŸŒˆ toil.cwl.cwltoil.get_options(args)

This one parses the given args and properly adds non-Toil arguments into the cwljob of the Namespace ๐Ÿงƒ.

Parameters ๐ŸŽ€

  • args (type list[str], docs for list at /usr/share/doc/python3/html/library/stdtypes.html#list and for str at /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” :param args: is the list of args from the command line.

Return type configargparse.Namespace โ€” :return: gives you the options namespace ๐Ÿ’ซ.

๐Ÿ”ฅ toil.cwl.cwltoil.main(args=None, stdout=sys.stdout)

This runs the main loop for toil-cwl-runner ๐Ÿƒโ€โ™€๏ธ.

Parameters ๐ŸŽ€

  • args (type Optional[list[str]], docs for list at /usr/share/doc/python3/html/library/stdtypes.html#list and for str at /usr/share/doc/python3/html/library/stdtypes.html#str)
  • stdout (type TextIO)

Return type ๐Ÿ’– int (docs at /usr/share/doc/python3/html/library/functions.html#int)

๐Ÿซง toil.cwl.cwltoil.find_default_container(args, builder)

Finds the default constructor by consulting a Toil.options object ๐Ÿ”Ž.

Parameters ๐ŸŽ€

  • args (type configargparse.Namespace)
  • builder (type cwltool.builder.Builder, docs at /usr/share/doc/cwltool/html/autoapi/cwltool/builder/index.html#cwltool.builder.Builder)

Return type Optional[str] (docs for str at /usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ’œ toil.cwl.utils

Utility functions used for Toil's CWL interpreter ๐Ÿงฐ.

๐ŸŽ€ Attributes

  • logger
  • CWL_UNSUPPORTED_REQUIREMENT_EXIT_CODE
  • CWL_UNSUPPORTED_REQUIREMENT_EXCEPTION
  • DownReturnType
  • UpReturnType
  • DirectoryStructure

No descriptions were given for any of these, so we're just vibing with the names ๐Ÿคท

๐ŸŒท Exceptions

  • CWLUnsupportedException โ€” Fallback exception.

โœจ Functions โœจ

okay so these are the helper functions living in toil.cwl.utils ๐Ÿ’… bestie, they're the little workhorses behind the CWL stuff ๐Ÿซถ

  • visit_top_cwl_class(rec, classes, op): runs op on every top-level CWL object whose class is one of the named CWL classes. It's like cwltool's visit_class, but it won't peek inside anything it visits ๐Ÿ‘€
  • visit_cwl_class_and_reduce(rec, classes, op_down, op_up): runs op_down top-down and op_up bottom-up on every CWL object with the named classes. op_up gets op_down's result plus a list of all the child op_up results, flattened across lists, with nodes of non-matching classes collapsed ๐ŸŒธ
  • get_from_structure(dir_dict, path): given a relative path, it follows that path through the directory structure ๐Ÿ—บ๏ธ
  • download_structure(file_store, index, existing, ...): downloads a nested dictionary from the Toil file store into a local path ๐Ÿ“ฅ
  • trim_mounts_op_down(file_or_directory): a no-op function for mount-point trimming. It literally does nothing, and that's the vibe ๐Ÿซฅ
  • sniff_location(file_or_directory): gets the local bare path for a CWL file or directory, or None if there isn't one ๐Ÿ”
  • trim_mounts_op_up(file_or_directory, op_down_ret, ...): removes subtrees of the CWL file or directory object tree that only have redundant stuff in them. Declutter era ๐Ÿงน
  • remove_redundant_mounts(cwljob): removes any redundant mount points from the listing. It modifies the CWL object in place, so no copies, just vibes โœ๏ธ

โœจ Module Contents โœจ

okay the module contents are next and they're giving organized ๐ŸŽ€

  • toil.cwl.utils.logger

toil.cwl.utils.CWL_UNSUPPORTED_REQUIREMENT_EXIT_CODE

toil.cwl.utils.CWL_UNSUPPORTED_REQUIREMENT_EXIT_CODE = 33

exception toil.cwl.utils.CWLUnsupportedException

Bases: Exception

This is the fallback exception, so it's the one you get when nothing more specific fits ๐Ÿ›Ÿ

toil.cwl.utils.CWL_UNSUPPORTED_REQUIREMENT_EXCEPTION

This one is a type, and it's either cwltool's UnsupportedRequirement or our CWLUnsupportedException ๐Ÿง

toil.cwl.utils.CWL_UNSUPPORTED_REQUIREMENT_EXCEPTION: type[cwltool.errors.UnsupportedRequirement] | type[CWLUnsupportedException]

toil.cwl.utils.visit_top_cwl_class(rec, classes, op)

Applies the given operation to all top-level CWL objects with the given named CWL class. Like cwltool's visit_class, but it doesn't look inside any object it visits ๐Ÿ‘€

Parameters

  • rec (Any)
  • classes (collections.abc.Iterable[str])
  • op (Callable[[Any], Any])

Return type: None

toil.cwl.utils.DownReturnType

toil.cwl.utils.UpReturnType

toil.cwl.utils.visit_cwl_class_and_reduce(rec, classes, op_down, op_up)

Applies the given operations to all CWL objects with the given named CWL class โœจ op_down runs top-down and op_up runs bottom-up. The up operation gets the down operation's result and a list of the up results for every child key. That list gets flattened across lists, and nodes of non-matching classes get collapsed ๐ŸŒˆ

Returns: the flattened list of up operation results from all calls.

Parameters

  • rec (Any)
  • classes (collections.abc.Iterable[str])
  • op_down (Callable[[Any], DownReturnType])
  • op_up (Callable[[Any, DownReturnType, list[UpReturnType]], UpReturnType])

Return type: list[UpReturnType]

toil.cwl.utils.DirectoryStructure

toil.cwl.utils.get_from_structure(dir_dict, path)

Given a relative path, follows it through the given directory structure ๐Ÿ—บ๏ธ

It returns the string URI for files, the directory dict for subdirectories, or None for things that don't exist ๐Ÿซฅ

Parameters

  • dir_dict (DirectoryStructure)
  • path (str)

Return type: Union[str, DirectoryStructure, None]

toil.cwl.utils.download_structure(file_store, index, existing, dir_dict, into_dir)

Downloads a nested dictionary from the Toil file store to a local path ๐Ÿ“ฅ

This one is guaranteed to fill the structure with real files, not symlinks pointing out of it to somewhere else. File URIs can be toilfile: URIs or any other URI that Toil's job store system can read ๐Ÿ”’

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore): the Toil file store to download from.
  • index (dict[str, str]): maps from the downloaded file path back to the input URI.
  • existing (dict[str, str]): maps from a file_store_id URI to the downloaded file path.
  • dir_dict (DirectoryStructure): a dict from string to string (for files) or dict (for subdirectories) describing a directory structure.
  • into_dir (str): the directory to download the top-level dict's files into.

Return type: None

toil.cwl.utils.trim_mounts_op_down(file_or_directory)

A no-op function for mount-point trimming. Literally does nothing, very chill ๐Ÿซฅ

Parameters

  • file_or_directory (cwltool.utils.CWLObjectType)

Return type: None

toil.cwl.utils.sniff_location(file_or_directory)

Gets the local bare path for a CWL file or directory, or None ๐Ÿ”

It returns None if there's no local path or file URI to be found.

Returns: None if we don't have a local path or file URI.

Parameters

  • file_or_directory (cwltool.utils.CWLObjectType)

Return type: Optional[str]

toil.cwl.utils.trim_mounts_op_up(file_or_directory, op_down_ret, child_results)

Removes subtrees of the CWL file or directory object tree that only have redundant stuff in them ๐Ÿงน Here's how "nonredundant" works, bestie:

  • For something in a directory, nonredundant means its path or location is not within the parent directory, or it doesn't match its basename.
  • For something in a secondary file, nonredundant means its path or location is not adjacent to the primary file, or it doesn't match its basename.

If it's a File: it returns True if anything in its secondary files is nonredundant, or if it has nonredundant children. Otherwise it returns False.

If it's a Directory: it returns True if anything in its top-level listing is nonredundant, or if it has nonredundant children. Otherwise it returns False. If something in the listing is redundant and all of its children are redundant too, it gets deleted ๐Ÿ’€

The docstring says the result is a boolean ๐ŸŽ€

Parameters

  • file_or_directory (cwltool.utils.CWLObjectType)
  • op_down_ret (None)
  • child_results (list[bool])

Return type: bool (see /usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’–

toil.cwl.utils.remove_redundant_mounts(cwljob)

Okay bestie, this one is a cleanup queen ๐Ÿงนโœจ It goes through the listing and removes any redundant mount points. Heads up: it modifies the CWL object in place, so no fresh copy comes back. It just edits the thing you handed it ๐Ÿ’…

Parameters

  • cwljob (cwltool.utils.CWLObjectType)

Return type: None ๐Ÿซถ

โœจ Functions โœจ

Okay so this section has one function in its little table ๐ŸŽ€

  • check_cwltool_version() โ€” checks if the installed cwltool version matches Toil's expected version ๐Ÿง

โœจ Package Contents โœจ

toil.cwl.check_cwltool_version()

Checks if the installed cwltool version matches Toil's expected version ๐Ÿ‘€ If the versions don't match, a warning gets printed to standard error. Toil doesn't assume logging is set up yet, so it doesn't rely on that. It's safe to call this as many times as you want, but only one warning will ever show up ๐ŸŒธ

Return type: None

โœจ toil.deferred โœจ

Attributes

  • logger

Classes

  • DeferredFunction
  • DeferredFunctionManager โ€” Implements a deferred function system. Each Toil worker will have

Module Contents

  • toil.deferred.logger

toil.deferred.DeferredFunction

Bases: namedtuple('DeferredFunction', 'function args kwargs name module') ๐Ÿงš

Here's a little doctest vibe check โœจ

>>> from collections import defaultdict
>>> df = DeferredFunction.create(defaultdict, None, {'x':1}, y=2)
>>> df
DeferredFunction(defaultdict, ...)
>>> df.invoke() == defaultdict(None, x=1, y=2)
True

classmethod create(function, *args, **kwargs)

Captures the given callable and arguments as an instance of this class ๐Ÿฆ‹

Parameters

  • function (callable) โ€” the deferred action to take, in the form of a function
  • args (tuple, see /usr/share/doc/python3/html/library/stdtypes.html#tuple) โ€” non-keyword arguments to the function
  • kwargs (dict, see /usr/share/doc/python3/html/library/stdtypes.html#dict) โ€” keyword arguments to the function

invoke()

Invokes the captured function with the captured arguments ๐Ÿ”ฅ

__str__()

Returns str(self) ๐Ÿ’œ

__repr__

Returns repr(self) ๐Ÿ’œ

toil.deferred.DeferredFunctionManager(stateDirBase)

Okay this one is the main character ๐Ÿ‘‘ It implements a deferred function system. Each Toil worker gets its own instance of this class. When a job runs, it happens inside a context manager from this class. If the job registers any "deferred" functions, they get executed when the context manager exits.

If the Python process dies before properly exiting the context manager and running the deferred functions, then one of two things picks them up. Either some other worker process enters or exits the per-job context manager of this class later on, or the DeferredFunctionManager gets shut down on the worker. Either way, the earlier job's deferred functions get picked up and run ๐Ÿซถ

Deferred function cleanup is on a best-effort basis, and deferred functions may end up getting executed multiple times. Not a vibe, but a warning ๐Ÿ’€

Under the hood, deferred functions are serialized into files in the given directory, and those files are locked by the owning process. If that process dies, other processes can detect that the files are able to be locked, and they'll take them over ๐ŸŒˆ

Parameters

  • stateDirBase (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

Constants

  • STATE_DIR_STEM = 'deferred'
  • PREFIX = 'func'
  • WIP_SUFFIX = '.tmp'

Attributes

  • stateDir
  • stateFileName
  • stateFileOut
  • stateFileIn

Methods

  • __del__() โ€” cleans up our state on disk. It assumes the deferred functions we manage have all been executed, and none are currently recorded ๐Ÿงฝ
  • open() โ€” yields a single-argument function that lets you register deferred functions of type toil.DeferredFunction. This design means deferred functions can only be registered inside this context manager ๐ŸŽ€
Not thread safe. Keep it away from your threads ๐Ÿ˜ฌ
  • classmethod cleanupWorker(stateDirBase) โ€” called by the batch system when it shuts down the node, after all workers are done, if the batch system supports worker cleanup. It checks once more for orphaned deferred functions and runs them ๐Ÿงน

Parameters

  • stateDirBase (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None

โœจ toil.exceptions โœจ

Neutral place for exceptions, so import cycles don't get tangled up ๐Ÿงถ

Attributes

  • logger

Exceptions

  • FailedJobsException โ€” common base class for all non-exit exceptions ๐Ÿ™ˆ

Module Contents

  • toil.exceptions.logger

exception toil.exceptions.FailedJobsException(job_store, failed_jobs, exit_code=1)

Bases: Exception (see /usr/share/doc/python3/html/library/exceptions.html#Exception) ๐ŸŒธ

Common base class for all non-exit exceptions.

Parameters

  • job_store (toil.jobStores.abstractJobStore.AbstractJobStore, see <#toil.jobStores.abstractJobStore.AbstractJobStore>)
  • failed_jobs (list, see /usr/share/doc/python3/html/library/stdtypes.html#list, of toil.job.JobDescription, see <#toil.job.JobDescription>)
  • exit_code (int, see /usr/share/doc/python3/html/library/functions.html#int)

Attributes

  • msg
  • exit_code = 1
  • jobStoreLocator
  • numberOfFailedJobs

__str__()

Stringifies the exception, including the message ๐Ÿ’…

Return type: str (see /usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ toil.fileStores โœจ

Submodules

  • toil.fileStores.abstractFileStore

โœจ toil.fileStores.abstractFileStore โœจ

Attributes

  • logger

Classes

  • AbstractFileStore โ€” interface used to allow user code run by Toil to read and write files ๐Ÿฆ‹

Module Contents

  • toil.fileStores.abstractFileStore.logger

class toil.fileStores.abstractFileStore.AbstractFileStore(jobStore, jobDesc, file_store_dir, waitForPreviousCommit)

Bases: abc.ABC (see /usr/share/doc/python3/html/library/abc.html#abc.ABC) ๐Ÿงš

This is the interface that lets user code run by Toil read and write files, and it's the one-stop shop for other Toil facilities that user code needs. That includes:

  • normal (non-real-time) logging
  • finding the correct temporary directory for scratch work
  • importing and exporting files into and out of the workflow

It stores user files in the jobStore, but keeps them separate from actual jobs. It may implement caching. It's passed as an argument to the toil.job.Job.run() (see <#toil.job.Job.run>) method ๐Ÿ’–

Access to files is only permitted inside the context manager provided by toil.fileStores.abstractFileStore.AbstractFileStore.open(). Stay inside that context manager or you're not getting in ๐Ÿ™…

It's also responsible for committing completed jobs back to the job store with an update operation, and for allowing that commit operation to be waited for โณ

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore, see <#toil.jobStores.abstractJobStore.AbstractJobStore>)
  • jobDesc (toil.job.JobDescription, see <#toil.job.JobDescription>)
  • file_store_dir (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • waitForPreviousCommit (Callable[[], Any])

Attributes

  • jobStore
  • jobDesc
  • localTempDir: str = b'.' (type link: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • workflow_dir: str (type link: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • coordination_dir: str (type link: /usr/share/doc/python3/html/library/stdtypes.html#str)

okay so the FileStore class has some attributes that are lowkey the backbone of the whole thing ๐Ÿ’–

jobName: str = ''

waitForPreviousCommit

logging_messages: list[dict[str, int | str]] = []

logging_user_streams: list[dict[str, str]] = []

filesToDelete: set[str]

jobName defaults to ''. logging_messages and logging_user_streams both start as empty lists ๐Ÿงš. filesToDelete is a set[str] with no default shown, and waitForPreviousCommit has no type or default listed ๐ŸŒธ.


โœจ createFileStore

static createFileStore(jobStore, jobDesc, file_store_dir,
waitForPreviousCommit, caching)

Okay, this one makes a concrete FileStore ๐ŸŽ€

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)
  • jobDesc (toil.job.JobDescription)
  • file_store_dir (str)
  • waitForPreviousCommit (Callable[[], Any])
  • caching (Optional[bool])

Return type

Union[toil.fileStores.nonCachingFileStore.NonCachingFileStore, toil.fileStores.cachingFileStore.CachingFileStore]


๐Ÿงน shutdownFileStore

static shutdownFileStore(workflowID, config_work_dir,
config_coordination_dir)

This one does the cleanup, and it's giving serious vibes ๐Ÿ’€ It carries out any filestore-specific cleanup it needs to.

This is a destructive operation, so it is important to ensure that there are no other running processes on the system that are modifying or using the file store for this workflow. ๐Ÿ˜ญ

This is meant to be the last call to the file store in a Toil run. The batch system cleanup function calls it when the batch system shuts down ๐Ÿฆ‹

Parameters

  • workflowID (str) โ€” the workflow ID for this run of the workflow ๐Ÿ“
  • config_work_dir (Optional[str]) โ€” the path to the work directory in the Toil Config
  • config_coordination_dir (Optional[str]) โ€” the path to the coordination directory in the Toil Config

Return type

None


๐Ÿšช open

open(job)

This creates the context manager that wraps the tasks that run before and after a job. File operations are only allowed inside the context manager, so keep that in mind bestie ๐Ÿซถ

Implementations must only yield from within with super().open(job):.

Parameters

  • job (toil.job.Job) โ€” the job instance of the toil job to run

Return type

collections.abc.Generator[None, None, None]


๐Ÿ“ get_disk_usage

get_disk_usage()

This gets the number of bytes of disk used by the last job that ran under open() โœจ Disk usage is measured at the end of the job.

TODO: Sample periodically and record peak usage. ๐Ÿ™ˆ

Return type

Optional[int]


๐Ÿ“ getLocalTempDir

getLocalTempDir()

This gets you a brand new local temporary directory to write files into ๐ŸŒˆ It only sticks around for the duration of the job.

Returns

The absolute path to a new local temporary directory. This directory exists for the duration of the job only, and it is guaranteed to be deleted once the job terminates, removing all the files it contains recursively ๐Ÿ’…

Return type

str


๐Ÿ“ getLocalTempFile

getLocalTempFile(suffix=None, prefix=None)

This gets a new local temporary file that will persist for the duration of the job ๐Ÿฆ‹

Parameters

  • suffix (Optional[str]) โ€” if not None, the file name ends with this string. Otherwise the default value ".tmp" is used
  • prefix (Optional[str]) โ€” if not None, the file name starts with this string. Otherwise the default value "tmp" is used

Returns

The absolute path to a local temporary file. This file exists for the duration of the job only, and it is guaranteed to be deleted once the job terminates ๐Ÿซง

Return type

str


๐Ÿ”ค getLocalTempFileName

getLocalTempFileName(suffix=None, prefix=None)

This gets a valid name for a new local file, but it does NOT actually create a file at that path ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • suffix (Optional[str]) โ€” if not None, the file name ends with this string. Otherwise the default value ".tmp" is used
  • prefix (Optional[str]) โ€” if not None, the file name starts with this string. Otherwise the default value "tmp" is used

Returns

Path to a valid file ๐Ÿ“

Return type

str


โฌ†๏ธ writeGlobalFile

abstractmethod writeGlobalFile(localFileName, cleanup=False)

This is an abstract method, so it's basically a promise that the subclass fills in the details ๐Ÿ’œ It uploads a file (given as a path) to the job store.

If the file lives in a FileStore-managed temporary directory (aka it came from toil.fileStores.abstractFileStore.AbstractFileStore.getLocalTempDir()), it becomes a local copy of the file. That copy is eligible for deletion by toil.fileStores.abstractFileStore.AbstractFileStore.deleteLocalFile() ๐Ÿงš

If an executable file on the local filesystem gets uploaded, its executability is preserved when it is downloaded again โญ

Parameters

  • localFileName (str) โ€” the path to the local file to upload. The last path component (the basename of the file) stays associated with the file in the file store, if the backing JobStore supports it, so the file can be searched for by name or name glob ๐Ÿ”
  • cleanup (bool) โ€” if True, the copy of the global file is deleted once the job and all its successors have finished running. If not, the global file must be deleted manually ๐Ÿงผ

Returns

An ID that can be used to retrieve the file ๐Ÿชช

Return type

toil.fileStores.FileID


๐ŸŒŠ writeGlobalFileStream

writeGlobalFileStream(cleanup=False, basename=None,
encoding=None, errors=None)

This is like writeGlobalFile, but it lets you write a stream to the job store ๐ŸŒธ You don't need to close the yielded file handle explicitly, and you should not do it either ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • encoding (Optional[str]) โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which means binary mode
  • errors (Optional[str]) โ€” how encoding errors are handled. Errors are the same as for open(). Defaults to 'strict' when an encoding is specified
  • cleanup (bool) โ€” works the same as in toil.fileStores.abstractFileStore.AbstractFileStore.writeGlobalFile()

๐Ÿ“Ž Cross-reference targets

/usr/share/doc/python3/html/library/stdtypes.html#str
/usr/share/doc/python3/html/library/stdtypes.html#list
/usr/share/doc/python3/html/library/stdtypes.html#dict
/usr/share/doc/python3/html/library/stdtypes.html#set
/usr/share/doc/python3/html/library/functions.html#int
/usr/share/doc/python3/html/library/functions.html#bool
/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator
  • basename (Optional[str]) โ€” okay so if the backing JobStore supports it ๐Ÿ’–, pass in a file basename. Then when someone searches the job store with a query matching that basename, the file will totally get detected ๐Ÿ”

Returns

You get back a context manager that yields a tuple of 1) a file handle you can write to โœ๏ธ and 2) the toil.fileStores.FileID of the resulting file in the job store ๐ŸŽ€

Return type

collections.abc.Iterator[tuple[toil.lib.io.WriteWatchingStream, toil.fileStores.FileID]]

logAccess(fileStoreID, destination=None)

This is how the job records that a file was read ๐Ÿ‘€ (it gets announced if the job fails ๐Ÿ’€).

If destination is not None, it gives the path the file was downloaded to. Otherwise, it's assumed the file was streamed ๐ŸŒŠ

It must be called by readGlobalFile() and readGlobalFileStream() implementations, no skipping ๐Ÿซถ

Parameters

  • fileStoreID (Union[toil.fileStores.FileID, str])
  • destination (Union[str, None])

Return type None

This one's marked abstractmethod ๐Ÿงฉ and its whole job is to make the file tied to fileStoreID available locally ๐Ÿ“‚

readGlobalFile(fileStoreID, userPath=None, cache=True, mutable=False, symlink=False)

If mutable is True, a copy of the file gets created locally, so the original isn't modified and doesn't change the file for other jobs ๐Ÿ™…โ€โ™€๏ธ. If mutable is False, a link can be created to the file instead, which saves disk resources ๐Ÿ’พ. The downloaded file will be executable if and only if it was originally uploaded from an executable file on the local filesystem โšก

If a userPath is specified, it's used as the destination. If not, the file gets stored in the local temp directory with an encoded name ๐Ÿ—‚๏ธ

The destination file must not be deleted by the user ๐Ÿ’€ it can only be deleted through deleteLocalFile.

Implementations must call logAccess() to report the download ๐Ÿ“ฃ

Parameters

  • fileStoreID (str) โ€” job store id for the file ๐Ÿ†”
  • userPath (Optional[str]) โ€” a path to the name of the file the global file gets copied or hard-linked to (see below) ๐Ÿ“
  • cache (bool) โ€” Described in toil.fileStores.CachingFileStore.readGlobalFile()
  • mutable (bool) โ€” Described in toil.fileStores.CachingFileStore.readGlobalFile()
  • symlink (bool) โ€” True if the caller can accept a symlink, False if the caller can only accept a normal file or hardlink ๐Ÿ”—

Returns an absolute path to a local, temporary copy of the file keyed by fileStoreID ๐Ÿ“

Return type str

readGlobalFileStream(...)

readGlobalFileStream(fileStoreID: str, encoding: Literal[None] = None, errors: str | None = None) -> ContextManager[IO[bytes]]
readGlobalFileStream(fileStoreID: str, encoding: str, errors: str | None = None) -> ContextManager[IO[str]]

Read a stream from the job store, kind of like readGlobalFile ๐ŸŒŠ The yielded file handle does not need to be closed explicitly, and it should not be closed explicitly either ๐Ÿ™ˆ

Parameters

  • encoding โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which represents binary mode ๐Ÿ”ค
  • errors โ€” an optional string that specifies how encoding errors are handled. Errors are the same as for open(). Defaults to 'strict' when an encoding is specified ๐Ÿšจ

Implementations must call logAccess() to report the download ๐Ÿ“ฃ

Returns a context manager yielding a file handle which can be read from.

getGlobalFileSize(fileStoreID)

Get the size of the file pointed to by the given ID, in bytes ๐Ÿ“

If it's a FileID or something else with a non-None 'size' field, that value is what gets used โœจ. Otherwise, the job store is asked to poll the file's size ๐Ÿ•ต๏ธ

Note that the job store may overestimate the file's size, for example if it's encrypted and had to be augmented with an IV or other encryption framing ๐Ÿ”

Parameters

  • fileStoreID (Union[toil.fileStores.FileID, str]) โ€” File ID for the file

Returns the file's size in bytes, as stored in the job store

Return type int

deleteLocalFile(fileStoreID)

This one's an abstractmethod too ๐Ÿงฉ Delete local copies of files associated with the provided job store ID ๐Ÿ—‘๏ธ

It raises an OSError with an errno of errno.ENOENT if no such local copies exist. That means it cannot be called multiple times in succession ๐Ÿ’€ one and done, bestie.

The files deleted are all those previously read from this file ID via readGlobalFile by the current job into the job's file-store-provided temp directory, plus the file that was written to create the given file ID, if that file was written by the current job from the job's file-store-provided temp directory ๐Ÿงน

Parameters

  • fileStoreID (Union[toil.fileStores.FileID, str]) โ€” File Store ID of the file to be deleted.

Return type None

deleteGlobalFile(fileStoreID)

Also an abstractmethod ๐Ÿงฉ Delete local files, and then permanently delete them from the job store ๐Ÿ’€

To make sure the job can be restarted if necessary, the delete won't happen until after the job's run method has completed โณ

Parameters

  • fileStoreID (Union[toil.fileStores.FileID, str]) โ€” the File Store ID of the file to be deleted.

Return type None

importFile(srcUrl, sharedFileName=None)

Parameters

  • srcUrl (str)
  • sharedFileName (Optional[str])

Return type Optional[toil.fileStores.FileID]

import_file(src_uri, shared_file_name=None)

Parameters

  • src_uri (str)
  • shared_file_name (Optional[str])

Return type Optional[toil.fileStores.FileID]

exportFile(jobStoreFileID, dstUrl)

Parameters

  • jobStoreFileID (toil.fileStores.FileID)
  • dstUrl (str)

Return type None

export_file(file_id, dst_uri)

This one's an abstractmethod as well ๐Ÿงฉ

Parameters

  • file_id (toil.fileStores.FileID)
  • dst_uri (str)

Return type: None

log_to_leader(text, level=logging.INFO)

Sends a logging message to the leader, bestie ๐Ÿ’Œ The worker logs the same message at the same level too. โœจ

This doesn't touch the commit system, so it's totally safe to use during an asynchronous commit or without a commit afterward. ๐Ÿซถ

Parameters

  • text (str, see </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” the string to log. ๐Ÿ“
  • level (int, see </usr/share/doc/python3/html/library/functions.html#int>) โ€” the logging level. ๐Ÿ“Š

Return type: None

logToMaster(text, level=logging.INFO)

This one's the older name for the same thing. ๐Ÿ•ฐ๏ธ

Parameters

  • text (str, see </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • level (int, see </usr/share/doc/python3/html/library/functions.html#int>)

Return type: None

log_user_stream(name, stream)

Sends a stream of UTF-8 text to the leader as a named log stream. ๐ŸŒŠ

This is super useful for things like the error logs of Docker containers. ๐Ÿณ The leader will show it to the user or organize it nicely as user-level log info. ๐Ÿ’…

Parameters

  • name (str, see </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” a hierarchical string delimited by ..
  • stream (IO[bytes, see </usr/share/doc/python3/html/library/stdtypes.html#bytes>]) โ€” a stream of encoded text. Encoding errors will be tolerated. ๐Ÿซง

Return type: None

startCommit(jobState=False) (abstractmethod)

Updates the status of the job on the disk. ๐Ÿ’พ

It might bump the job's version number, and it might kick off an asynchronous process. ๐Ÿƒโ€โ™€๏ธ Call waitForCommit() to wait on that process. You must call waitForCommit() before committing any more updates to the job. ๐Ÿšจ

While that async process is running, it's totally fine to modify the job. Those changes just won't get committed until the next call. ๐Ÿฆ‹

Parameters

  • jobState (bool, see </usr/share/doc/python3/html/library/functions.html#bool>) โ€” if True, commit the state of the FileStore's job and the file deletes. Otherwise, only commit file creates and updates. ๐ŸŽ€

Return type: None

waitForCommit() (abstractmethod)

Blocks while startCommit is running. โณ

This gets called by the job's successor, so it doesn't start messing with the job store until this job is done. ๐Ÿค

It might also get called when startCommit was never called on that particular instance, in which case it just doesn't block. ๐Ÿ™ƒ

Returns

Always returns True. ๐Ÿ’–

Return type: bool, see </usr/share/doc/python3/html/library/functions.html#bool>

shutdown(shutdown_info) (classmethod, abstractmethod)

Parameters

  • shutdown_info (Any)

Return type: None

Shuts down the filestore on this node. ๐ŸŒ™

This is meant to be called when the batch system shuts down. ๐Ÿ”Œ

Parameters

  • shutdown_info (Any) โ€” the implementation-specific shutdown info, used to shut down the file store, remove all its state, and delete all job-local temp directories from the node. ๐Ÿงน

Return type: None


โœจ toil.fileStores.cachingFileStore โœจ

๐Ÿ’Ž Attributes

  • logger
  • SQLITE_TIMEOUT_SECS

๐Ÿšจ Exceptions

  • CacheError โ€” error raised if the user tries to add a non-local file to the cache. ๐Ÿ™…โ€โ™€๏ธ
  • CacheUnbalancedError โ€” raised if the file store can't free up enough space for caching. ๐Ÿ˜ฉ
  • IllegalDeletionCacheError โ€” error raised if the caching code finds a file that represents a reference to a cached file that has gone missing. ๐Ÿ‘ป
  • InvalidSourceCacheError โ€” error raised if the user tries to add a non-local file to the cache. ๐Ÿ™…โ€โ™€๏ธ

๐ŸŽ€ Classes

  • CachingFileStore โ€” a cache-enabled file store. ๐Ÿง 

๐Ÿ“š Module Contents

toil.fileStores.cachingFileStore.logger

toil.fileStores.cachingFileStore.SQLITE_TIMEOUT_SECS = 60.0

exception toil.fileStores.cachingFileStore.CacheError(message)

Bases: Exception, see </usr/share/doc/python3/html/library/exceptions.html#Exception>

Error raised if the user tries to add a non-local file to the cache. ๐Ÿ™…โ€โ™€๏ธ

exception toil.fileStores.cachingFileStore.CacheUnbalancedError

Bases: CacheError

Raised if the file store can't free up enough space for caching. ๐Ÿ˜ญ

Its message is 'Unable unable to free enough space for caching. This error frequently arises due to jobs using...'. ๐Ÿ’€

exception toil.fileStores.cachingFileStore.IllegalDeletionCacheError(deletedFile)

Bases: CacheError

Error raised if the caching code finds a file that represents a reference to a cached file that has gone missing. ๐Ÿ‘ป

This can be a big problem if a hard link is moved, because then the cache won't be able to evict the file it links to. ๐Ÿ˜ฑ

Remember that files read with readGlobalFile may not be deleted by the user and need to be deleted with deleteLocalFile. ๐Ÿซต

exception toil.fileStores.cachingFileStore.InvalidSourceCacheError(message)

Bases: CacheError

Error raised if the user tries to add a non-local file to the cache. ๐Ÿ™…โ€โ™€๏ธ

class toil.fileStores.cachingFileStore.CachingFileStore(jobStore, jobDesc, file_store_dir, waitForPreviousCommit)

Bases: toil.fileStores.abstractFileStore.AbstractFileStore

A cache-enabled file store. ๐Ÿง โœจ

It hands out files as symlinks or hard links into a cache directory for the node, as long as the workflow allows it. ๐Ÿ”—

It also tries to write files back to the backing JobStore asynchronously, right after quickly taking them into the cache. Writes only have to finish when the job's actual state after running gets committed back to the job store. ๐Ÿซถ

Internally, it manages caching with a database. Each node has its own database, shared between all the workers on that node. ๐Ÿ—„๏ธ The database has several tables:

  • files has one entry for each file in the cache. Each entry knows the path to its data on disk, its global file ID, its state, and its owning worker PID. If the owning worker dies, another worker picks it up. It also knows its size. ๐Ÿ“‚

File states are:

  • "cached": happily stored in the cache. Reads can happen immediately. The owner is null. Anyone can adopt it and move it to "deleting", but only if it has no outstanding immutable references. ๐Ÿฅฐ
  • "downloading": in the process of being saved to the cache by a non-null owner. Reads have to wait until the state becomes "cached". If the worker dies, it goes to "deleting", because we don't know whether it was fully downloaded or whether anyone still needs it. No references can be created to a "downloading" file except by the worker responsible for downloading it. ๐Ÿšง
  • "uploadable": stored in the cache and ready to be written to the job store by a non-null owner. It transitions to "uploading" when a (thread of the) owning worker process picks it up and starts uploading it, either to free up cache space or to commit a completed job. If the worker dies, it goes to "cached", because it may still have outstanding immutable references from the dead-but-not-cleaned-up job that was going to write it. ๐Ÿ“ค
  • "uploading": stored in the cache and being written to the job store by a non-null owner. It transitions to "cached" once it's successfully uploaded. If the worker dies, it goes to "cached", because it may still have outstanding immutable references from the dead-but-not-cleaned-up job that was writing it. ๐Ÿฆ‹
  • "deleting" โ€” the file is getting yeeted out of the cache by a non-null owner ๐Ÿ—‘๏ธ and will eventually be removed from the database. Bye bestie ๐Ÿ‘‹

The refs table holds one entry for every outstanding reference to a cached file (hard link, symlink, or full copy) ๐Ÿ”—. It's called refs and not references because references is an SQL reserved word ๐Ÿ™…. It remembers which job ID has the reference and the path where that reference lives. References come in three states:

  • "immutable" โ€” a hardlink or symlink to a file in the cache ๐Ÿฆ‹. It dedicates the file's size in bytes from the job's disk requirement to the cache, so it can cache this file or keep other files without references around. It can get upgraded to "copying" if the link can't actually be created.
  • "copying" โ€” a file in the cache is mid-copy to a path โœจ. It'll eventually be upgraded to a mutable reference.
  • "mutable" โ€” a file from the cache was copied to a certain path ๐Ÿ’œ. These only exist to support the deleteLocalFile API. Only files with nothing but mutable references (or no references at all) are eligible for eviction.

The jobs table has one entry for each job currently running ๐Ÿƒโ€โ™€๏ธ. It keeps track of the job's ID, the worker that's supposed to be running it, the job's disk requirement, and the job's local temp dir path that needs cleaning up ๐Ÿงน. When workers check for jobs whose workers have died, they null out the old worker and grab ownership of the jobs and their references, cleaning up until the null-worker jobs are gone. Iconic cleanup behavior ๐Ÿ’….

The properties table holds key, value pairs for tracking total space available and whether caching is free for this run ๐ŸŒธ.


Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)
  • jobDesc (toil.job.JobDescription)
  • file_store_dir (str)
  • waitForPreviousCommit (Callable[[], Any])

Here's the attribute lineup, bestie ๐ŸŽ€:

forceNonFreeCaching = False
forceDownloadDelay = None
contentionBackoff = 15
localCacheDir
jobName: str = ''
jobID
jobDiskBytes: float | None = None
workflowAttemptNumber
dbPath
process_identity_lock
commitThread = None

as_process()

Assumes the process's identity so it can act on the caching database ๐Ÿชช. It yields the process's name in the caching database and holds onto a lock while your thread has it ๐Ÿ”’.

Return type: collections.abc.Generator[str, None, None]

con (property)

Gets the database connection to be used for the current thread ๐Ÿ’–.

Return type: sqlite3.Connection

cur (property)

Gets the main cursor to be used for the current thread โœจ.

Return type: sqlite3.Cursor

getCacheLimit()

Returns the total number of bytes the cache is limited to ๐Ÿ“. If no limit is available, it raises an error ๐Ÿ™ˆ.

getCacheUsed()

Returns the total number of bytes used in the cache ๐Ÿ“ฆ. If no value is available, it raises an error ๐Ÿ’€.

getCacheExtraJobSpace()

Returns the total number of bytes of disk space requested by jobs running against this cache but not yet used ๐Ÿซ . Here's the tea: the jobs on the node can take up all the space, and then they want to write to or read from the cache. So when that happens, we need to debit space from them somehow... ๐Ÿ˜ญ If no value is available, it raises an error.

getCacheAvailable()

Returns the total number of free bytes available for caching ๐ŸŒˆ. If the number is negative, it's the total number of bytes of cached files that need to be evicted to free up enough space for all the currently scheduled jobs. If no value is available, it raises an error.

getSpaceUsableForJobs()

Returns the total number of bytes that aren't taken up by job requirements, ignoring files and file usage ๐Ÿ“. We can never run more jobs than we actually have room for, even with caching. If it's not retrievable, it raises an error.

getCacheUnusedJobRequirement()

Returns the total number of bytes of disk space requested by the current job and not used by the files the job is using in the cache ๐Ÿง. Mutable references don't count, but immutable and uploading ones do. If no value is available, it raises an error.

adjustCacheLimit(newTotalBytes)

Adjusts the total cache size limit to the given number of bytes โš–๏ธ.

fileIsCached(fileID)

Returns true if the given file is currently cached, and false otherwise ๐Ÿ‘€. Be careful though, because this can't really be relied upon. A file may go from cached to deleting right after you look at it ๐Ÿ˜ฌ. If you need to do something with the file, do it in a transaction.

getFileReaderCount(fileID)

Returns the number of current outstanding reads of the given file ๐Ÿ“–. This counts mutable references too.

cachingIsFree()

Returns true if files can be cached for free, without taking up space, and false otherwise ๐Ÿ†“. This is true when you're working with certain job stores in certain configurations, most notably the FileJobStore ๐Ÿฆ‹.

open(job)

This context manager decorated method lets you do cache-specific operations before and after a job runs in worker.py ๐Ÿงš.

Parameters: job (toil.job.Job)

Return type: collections.abc.Generator[None, None, None]

writeGlobalFile(localFileName, cleanup=False)

Creates a file in the jobstore and returns a FileID reference ๐Ÿ“.

Makes the file associated with fileStoreID available locally ๐Ÿซถ. If mutable is True, a copy of the file gets created locally, so the original isn't modified and doesn't change the file for other jobs. If mutable is False, a link can be created instead, which saves disk resources ๐Ÿ’พ. The downloaded file will be executable if and only if it was originally uploaded from an executable file on the local filesystem โšก.

If a userPath is specified, it's used as the destination. If it isn't, the file is stored in the local temp directory with an encoded name ๐Ÿ—‚๏ธ.

The destination file must not be deleted by you. It can only be deleted through deleteLocalFile ๐Ÿšซ. Implementations must call logAccess() to report the download.

Parameters

  • fileStoreID โ€” job store id for the file
  • userPath โ€” a path to the name of the file to which the global file will be copied or hard-linked (see below).
  • cache โ€” described in toil.fileStores.CachingFileStore.readGlobalFile()
  • mutable โ€” described in toil.fileStores.CachingFileStore.readGlobalFile()
  • symlink โ€” True if the caller can accept a symlink, False if the caller can only accept a normal file or hardlink

Returns: An absolute path to a local, temporary copy of the file keyed by fileStoreID ๐ŸŒŸ.

readGlobalFileStream(fileStoreID, encoding=None, errors=None)

Reads a stream from the job store, similar to readGlobalFile ๐ŸŒŠ. The yielded file handle doesn't need to be closed explicitly, and you shouldn't do it either ๐Ÿ™….

Parameters

  • encoding โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which represents binary mode.
  • errors โ€” an optional string that specifies how encoding errors are handled. Errors are the same as for open(). Defaults to 'strict' when an encoding is specified.

Implementations must call logAccess() to report the download ๐Ÿ“ฃ.

Returns: a context manager yielding a file handle that can be read from ๐Ÿ’….

deleteLocalFile(fileStoreID)

Deletes the local copies of files associated with the provided job store ID ๐Ÿงผ.

Okay so, if there are no local copies to delete, this one raises an OSError with an errno of errno.ENOENT ๐Ÿ™ˆ which means you literally can't call it multiple times in a row, bestie ๐Ÿ’€

Here's what actually gets deleted โœจ all the files this job previously read from this file ID with readGlobalFile into the job's file-store-provided temp directory, PLUS the file that was written to create the given file ID, but only if the current job wrote it from that same file-store-provided temp directory ๐ŸŽ€

Parameters

  • fileStoreID โ€” the File Store ID of the file to be deleted ๐ŸŒธ

deleteGlobalFile(fileStoreID)

Okay, this one deletes the local files and then permanently deletes them from the job store ๐Ÿ˜ญ Plot twist: it waits. The delete won't happen until after the job's run method has finished, so the job can still be restarted if it needs to ๐Ÿซถ

Parameters

  • fileStoreID โ€” the File Store ID of the file to be deleted ๐ŸŒธ

exportFile(jobStoreFileID, dstUrl)

Parameters

  • jobStoreFileID (toil.fileStores.FileID)
  • dstUrl (str)

Return type

  • None

export_file(file_id, dst_uri)

Same energy, different outfit ๐Ÿ’…

Parameters

  • file_id (toil.fileStores.FileID)
  • dst_uri (str)

Return type

  • None

waitForCommit()

This one blocks while startCommit is running ๐Ÿ›‘ Its job is to make sure the successor job doesn't start messing with the job store until this job is done doing its thing. Bestie protecting the boundaries ๐Ÿงš

It might get called even when startCommit was never called on that particular instance, and in that case it just doesn't block. No drama ๐Ÿ’œ

Returns

  • Always returns True

Return type

  • bool

startCommit(jobState=False)

This updates the status of the job on disk ๐Ÿ’– It may bump the version number of the job, and it may kick off an asynchronous process. If it does, call waitForCommit() to wait on that process ๐Ÿฆ‹

You must call waitForCommit() before committing any further updates to the job, no exceptions ๐Ÿšจ While the async process is running, it's totally safe to modify the job. Those modifications just won't get committed until the next call โœจ

Parameters

  • jobState โ€” If True, commit the state of the FileStore's job, and file deletes. Otherwise, commit only file creates/updates ๐Ÿ“

startCommitThread(state_to_commit)

This runs in a thread and actually commits the current job ๐Ÿงต

Parameters

  • state_to_commit (Optional[toil.job.JobDescription])

classmethod shutdown(shutdown_info)

Parameters

  • shutdown_info (tuple[str, str]) โ€” a tuple of the coordination directory (where the cache database lives) and the cache directory (where the cached data lives) ๐Ÿ“ฆ

Return type

  • None

Job local temp directories get removed automatically because they show up in the database ๐Ÿงน

__del__()

Cleanup function that runs when the class instance gets destroyed. It makes sure all the file writing threads exit properly ๐ŸŒˆ


โœจ toil.fileStores.nonCachingFileStore โœจ

Attributes

  • logger

Classes

  • NonCachingFileStore โ€” Interface used to allow user code run by Toil to read and write files ๐Ÿ’–

Module Contents

toil.fileStores.nonCachingFileStore.logger: logging.Logger

class toil.fileStores.nonCachingFileStore.NonCachingFileStore(jobStore, jobDesc, file_store_dir, waitForPreviousCommit)

Bases: toil.fileStores.abstractFileStore.AbstractFileStore

This is the interface that lets user code run by Toil read and write files ๐ŸŽ€ It also gives user code access to other Toil facilities, including:

  • normal (non-real-time) logging ๐Ÿ“
  • finding the correct temporary directory for scratch work ๐Ÿ—‚๏ธ
  • importing and exporting files into and out of the workflow ๐Ÿฆ‹

It stores user files in the jobStore, but keeps them separate from actual jobs. It may implement caching ๐Ÿ’…

It gets passed as an argument to the toil.job.Job.run() method. File access is only allowed inside the context manager provided by toil.fileStores.abstractFileStore.AbstractFileStore.open() ๐Ÿ”’

It's also responsible for committing completed jobs back to the job store with an update operation, and it lets you wait on that commit operation too โณ

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)
  • jobDesc (toil.job.JobDescription)
  • file_store_dir (str)
  • waitForPreviousCommit (Callable[[], Any])

Attributes

  • jobStateFile: str | None = None
  • localFileMap: DefaultDict[str, list[str]]

static check_for_coordination_corruption(coordination_dir)

Checks that the coordination directory hasn't been deleted unexpectedly ๐Ÿ˜ฑ Slurm has been known to delete XDG_RUNTIME_DIR out from under the processes it promised to leave alone, so in certain misconfigured environments the coordination directory and everything in it could vanish. To catch that, this regularly makes sure the things we expect to exist actually exist, and aborts if they don't ๐Ÿšจ

Parameters

  • coordination_dir (Optional[str])

Return type

  • None

check_for_state_corruption()

Makes sure the state tracking information hasn't been deleted unexpectedly ๐Ÿ•ต๏ธโ€โ™€๏ธ

Return type

  • None

open(job)

This creates the context manager that wraps tasks before and after a job runs ๐ŸŽ€ File operations are only permitted inside this context manager.

Implementations must only yield from within with super().open(job):. Don't skip this or things get messy ๐Ÿ’€

Parameters

  • job (toil.job.Job) โ€” the job instance of the Toil job to run

Return type

  • collections.abc.Generator[None, None, None]

writeGlobalFile(localFileName, cleanup=False)

Uploads a file (as a path) to the job store โ˜๏ธ

If the file lives in a FileStore-managed temporary directory (i.e. one from toil.fileStores.abstractFileStore.AbstractFileStore.getLocalTempDir()), it becomes a local copy of the file, which makes it eligible for deletion by toil.fileStores.abstractFileStore.AbstractFileStore.deleteLocalFile() ๐Ÿ—‘๏ธ

If an executable file on the local filesystem gets uploaded, its executability is preserved when it's downloaded again ๐Ÿƒโ€โ™€๏ธ

Parameters

  • localFileName (str) โ€” the path to the local file to upload. The last path component (the basename of the file) stays associated with the file in the file store, if the backing JobStore supports it, so the file can be searched for by name or name glob ๐Ÿ”
  • cleanup (bool) โ€” when this is True, the copy of the global file gets deleted once the job and all of its successors are done running ๐Ÿงน. If it's False, the global file has to be deleted manually, so don't forget, bestie ๐Ÿ’….

You get back an ID ๐Ÿชช that you can use to pull the file up later.

Return type: toil.fileStores.FileID

๐ŸŽ€ readGlobalFile ๐ŸŽ€

readGlobalFile(fileStoreID, userPath=None, cache=True, mutable=False, symlink=False)

This makes the file tied to fileStoreID available locally ๐ŸŒธ.

If mutable is True, you get your own local copy, so the original stays untouched and doesn't change the file for any other jobs ๐Ÿ›ก๏ธ. If mutable is False, a link can be made to the file instead, which saves disk space ๐Ÿ’พ.

The downloaded file is executable if and only if it was originally uploaded from an executable file on the local filesystem โšก.

If you give a userPath, that's where the file goes. If you don't, the file lands in the local temp directory with an encoded name ๐Ÿ—‚๏ธ.

โš ๏ธ Don't delete the destination file yourself! The only way to delete it is through deleteLocalFile ๐Ÿ™…โ€โ™€๏ธ.

Implementations must call logAccess() to report the download ๐Ÿ“ฃ.

Parameters:

  • fileStoreID (str) โ€” the job store ID for the file
  • userPath (Optional[str]) โ€” a path to the name of the file where the global file gets copied or hard-linked (more on that below) ๐Ÿ“
  • cache (bool) โ€” described in toil.fileStores.CachingFileStore.readGlobalFile() ๐Ÿ’œ
  • mutable (bool) โ€” described in toil.fileStores.CachingFileStore.readGlobalFile() ๐Ÿ’œ
  • symlink (bool) โ€” True if the caller can accept a symlink, False if the caller can only accept a normal file or a hardlink ๐Ÿ”—

Returns: an absolute path to a local, temporary copy of the file keyed by fileStoreID ๐Ÿงš

Return type: str

๐Ÿฆ‹ readGlobalFileStream ๐Ÿฆ‹

readGlobalFileStream(fileStoreID: str, encoding: Literal[None] = None, errors: str | None = None) -> ContextManager[IO[bytes]]

readGlobalFileStream(fileStoreID: str, encoding: str, errors: str | None = None) -> ContextManager[IO[str]]

This reads a stream from the job store. It's basically the vibe of readGlobalFile, just streamed โœจ.

You do not need to close the yielded file handle, and you actually shouldn't close it explicitly ๐Ÿ™…โ€โ™€๏ธ.

Parameters:

  • encoding โ€” the name of the encoding used to decode the file. Encodings are the same as the ones for decode(). It defaults to None, which means binary mode ๐Ÿ”ข.
  • errors โ€” an optional string that says how encoding errors get handled. These are the same as the ones for open(). It defaults to 'strict' when an encoding is specified ๐Ÿšจ.

Implementations must call logAccess() to report the download ๐Ÿ“ฃ.

Returns: a context manager that yields a readable file handle ๐Ÿ“–.

๐ŸŒˆ exportFile ๐ŸŒˆ

exportFile(jobStoreFileID, dstUrl)

Parameters:

  • jobStoreFileID (toil.fileStores.FileID)
  • dstUrl (str)

Return type: None

๐ŸŒธ export_file ๐ŸŒธ

export_file(file_id, dst_uri)

Parameters:

  • file_id (toil.fileStores.FileID)
  • dst_uri (str)

Return type: None

๐Ÿ’€ deleteLocalFile ๐Ÿ’€

deleteLocalFile(fileStoreID)

This deletes the local copies of files tied to the job store ID you pass in ๐Ÿ—‘๏ธ.

โš ๏ธ If there are no local copies to delete, it raises an OSError with an errno of errno.ENOENT. That means you can't call it multiple times in a row ๐Ÿ˜ญ.

The files it deletes are all the ones this job has previously read from this file ID with readGlobalFile into the job's file-store-provided temp directory ๐Ÿงบ. It also deletes the file that was written to create the given file ID, but only if the current job wrote it from that same file-store-provided temp directory ๐Ÿซถ.

Parameters:

  • fileStoreID (str) โ€” the File Store ID of the file to be deleted

Return type: None

๐Ÿ”ฅ deleteGlobalFile ๐Ÿ”ฅ

deleteGlobalFile(fileStoreID)

This deletes local files first, and then permanently deletes them from the job store ๐Ÿ’ฅ.

To keep the job restartable if it needs to be, the delete doesn't happen until after the job's run method has finished ๐Ÿ”.

Parameters:

  • fileStoreID (str) โ€” the File Store ID of the file to be deleted

Return type: None

โญ waitForCommit โญ

waitForCommit()

This blocks while startCommit is running โณ. The job's successor calls it so it doesn't start messing with the job store until this job is totally done ๐Ÿ™…โ€โ™€๏ธ.

It might get called when startCommit was never called on that particular instance. In that case, it just doesn't block ๐Ÿซ .

Returns: always returns True โœ…

Return type: bool

๐Ÿ‘‘ startCommit ๐Ÿ‘‘

startCommit(jobState=False)

This updates the status of the job on disk ๐Ÿ’พ.

It may bump the job's version number ๐Ÿ”ข.

It may also start an asynchronous process. Call waitForCommit() to wait on that process. You must call waitForCommit() before committing any further updates to the job ๐Ÿ›‘. While the async process is running, it's totally safe to modify the job, but any modifications made after this call won't get committed until the next call ๐Ÿง .

Parameters:

  • jobState (bool) โ€” if True, it commits the state of the FileStore's job and the file deletes. Otherwise, it only commits the file creates and updates ๐Ÿ“

Return type: None

๐Ÿงน __del__ ๐Ÿงน

__del__()

This is the cleanup function that runs when a class instance is getting destroyed. There's nothing to do here, since there are no async write events ๐Ÿ™ƒ.

Return type: None

๐Ÿฆ„ classmethod shutdown ๐Ÿฆ„

classmethod shutdown(shutdown_info)

Parameters:

  • shutdown_info (str) โ€” the coordination directory ๐Ÿ—‚๏ธ

Return type: None


โœจ Classes โœจ

  • FileID โ€” a small wrapper around Python's builtin string class ๐ŸŽ€

โœจ Package Contents โœจ

๐Ÿ’– class toil.fileStores.FileID ๐Ÿ’–

class toil.fileStores.FileID(fileStoreID, size, executable=False)

Bases: str

FileID is a small wrapper around Python's builtin string class ๐Ÿง. It represents a file's ID in the file store, and it has a size attribute that holds the file's size in bytes ๐Ÿ“. This object is what importFile and writeGlobalFile give you back ๐ŸŽ.

Calls into the file store can use bare strings too. If the size isn't in the ID, it gets queried from the job store ๐Ÿ”.

Parameters:

  • fileStoreID (str)
  • size (int)
  • executable (bool)

Attributes:

  • size
  • executable = False
  • pack() โ€” packs the FileID into a string so it can be passed through external code ๐Ÿ“ฆ

Okay so the return type here is str ๐Ÿ’–. The docs for it live at /usr/share/doc/python3/html/library/stdtypes.html#str if you wanna peek โœจ

๐Ÿช„ classmethod forPath(fileStoreID, filePath) ๐Ÿช„

classmethod forPath(fileStoreID, filePath)
  • Parameters
    • fileStoreID (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
    • filePath (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: FileID <#toil.fileStores.FileID> ๐Ÿฆ‹

๐ŸŽ€ classmethod unpack(packedFileStoreID) ๐ŸŽ€

classmethod unpack(packedFileStoreID)

Unpack the result of pack() into a FileID object. ๐Ÿซถ

  • Parameters
    • packedFileStoreID (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: FileID <#toil.fileStores.FileID> ๐Ÿ‘‘

๐Ÿงš toil.job ๐Ÿงš

๐ŸŒˆ Attributes ๐ŸŒˆ

These are the attributes in toil.job, no cap, and they're all lowkey iconic:

  • logger
  • REQUIREMENT_NAMES
  • ParsedRequirement
  • ParseableIndivisibleResource
  • ParseableDivisibleResource
  • ParseableFlag
  • ParseableAcceleratorRequirement
  • ParseableRequirement
  • T
  • Promised

๐Ÿ’ฅ Exceptions ๐Ÿ’ฅ

Here's the exception lineup. Some of these are a little dramatic, so read them carefully bestie ๐Ÿ˜ญ

  • JobPromiseConstraintError โ€” the job was asked to promise its return value, but that value isn't available yet ๐Ÿ™ˆ
  • ConflictingPredecessorError โ€” the common base class for all non-exit exceptions ๐Ÿงฑ
  • DebugStoppingPointReached โ€” raised when a job reaches a point where it was told to stop for debugging ๐Ÿ›
  • FilesDownloadedStoppingPointReached โ€” raised when a job stops because it was asked to download its files, and the files are downloaded โœ…
  • JobException โ€” the general job exception ๐Ÿ’…
  • JobGraphDeadlockException โ€” raised if a workflow has an unresolvable dependency, like a cycle. Check out toil.job.Job.checkJobGraphForDeadlocks() for more ๐Ÿ’€
  • TemporaryID ๐Ÿฆ‹ is a placeholder for a job ID that hasn't been registered yet, and a JobDescription uses it until registration happens.
  • AcceleratorRequirement โœจ is the requirement for one or more computational accelerators, like a GPU or FPGA. ๐Ÿ’ป
  • RequirementsDict ๐ŸŽ€ is typed storage for a job's requirements.
  • Requirer ๐Ÿงš is the base class that handles the storage and presentation of requirements.
  • JobBodyReference ๐Ÿ”— is a reference from a job description to its body.
  • JobDescription ๐Ÿ“‹ stores everything the Toil Leader could ever need to know about a Job. ๐Ÿ‘‘
  • ServiceJobDescription ๐ŸŒธ is a description of a job that hosts a service.
  • CheckpointJobDescription ๐Ÿ’พ is a description of a job that is a checkpoint.
  • Job ๐Ÿ’… is the class that represents a unit of work in toil. Main character energy, obviously.
  • FunctionWrappingJob ๐Ÿ“ is a job used to wrap a function. When its run method runs, the wrapped function gets called.
  • JobFunctionWrappingJob ๐ŸŒˆ is a job function, meaning a function whose first argument is a Job.
  • PromisedRequirementFunctionWrappingJob ๐Ÿฆ‹ handles dynamic resource allocation using toil.job.Promise instances.
  • PromisedRequirementJobFunctionWrappingJob ๐Ÿ’œ handles dynamic resource allocation for job functions.
  • EncapsulatedJob ๐Ÿซถ is a convenience Job class that makes a job subgraph look like a single job.
  • ServiceHostJob โญ is a job that runs a service. Toil uses it internally, so bestie, you should subclass Service instead of using this one ๐Ÿ™ˆ.
  • FileMetadata ๐Ÿ“ is metadata for a file.
  • CombineImportsJob ๐Ÿ”ฅ combines the outputs of multiple WorkerImportsJobs into one promise.
  • WorkerImportJob ๐Ÿงš is a job that does file imports on a worker instead of on the leader. It assumes all local and cloud files are accessible.
  • ImportsJob ๐Ÿ—‚๏ธ organizes and delegates files to individual WorkerImportJobs.
  • Promise ๐ŸŽ€ references a return value from a method as a promise before the method itself has run.
  • PromisedRequirement ๐Ÿ’– is a class for dynamically allocating job function resource requirements.
  • UnfulfilledPromiseSentinel ๐Ÿ’€ should be overwritten by a proper promised value. Don't leave it sitting there, periodt.

โœจ Functions โœจ

okay bestie, here's the lineup of helper functions ๐Ÿ’… each one has a very specific job, so let's go ๐ŸŽ€

  • parse_accelerator(spec) โ€” parses an AcceleratorRequirement that someone typed in as user code ๐ŸŽ€
  • accelerator_satisfies(candidate, requirement[, ignore]) โ€” checks whether a candidate partially satisfies the given requirement โœจ
  • accelerators_fully_satisfy(candidates, requirement[, ...]) โ€” figures out whether a whole set of accelerators satisfies a requirement ๐Ÿ”ฅ
  • potential_absolute_uris(uri, path[, importer, ...]) โ€” gets the potential absolute URIs to check for an imported file ๐Ÿฆ‹
  • get_file_sizes(filenames, file_source[, search_paths, ...]) โ€” resolves relative-URI files in the given environment and turns them into absolute normalized URIs ๐ŸŒธ it returns a dictionary of the string values from the WDL file values
  • unwrap(p) โ€” makes sure you actually have a promised value, and not just a promise ๐Ÿซถ
  • unwrap_all(p) โ€” makes sure you actually have a collection of promised values ๐Ÿ’€

โœจ Module Contents โœจ

  • toil.job.logger ๐Ÿงš โ€” just the logger, listed by name, no extra deets ๐Ÿ’…

๐Ÿ’œ JobPromiseConstraintError

exception toil.job.JobPromiseConstraintError(promisingJob, recipientJob=None)

  • Bases: RuntimeError

This error is for when a job asks to promise its return value, but that value isn't available yet ๐Ÿ˜ญ (it's because the return value hasn't been hit in the topological order of the job graph.)

  • Parameters:
    • promisingJob (Job) ๐ŸŽ€
    • recipientJob (Optional[Job]) ๐ŸŽ€
  • Attributes:
    • promisingJob
    • recipientJob = None

๐ŸŒˆ ConflictingPredecessorError

exception toil.job.ConflictingPredecessorError(predecessor, successor)

  • Bases: Exception

This is the common base class for all non-exit exceptions โœจ

  • Parameters:
    • predecessor (Job) ๐Ÿฆ‹
    • successor (Job) ๐Ÿฆ‹

๐Ÿ’€ DebugStoppingPointReached

exception toil.job.DebugStoppingPointReached

  • Bases: BaseException

Raised when a job reaches a point where it's been told to stop for debugging ๐Ÿ™ˆ

๐Ÿ“ FilesDownloadedStoppingPointReached

exception toil.job.FilesDownloadedStoppingPointReached(message, host_and_job_paths=None)

  • Bases: DebugStoppingPointReached

Raised when a job stops because it was asked to download its files, and the files have been downloaded ๐Ÿซถ

  • Parameters:
    • message (str) ๐ŸŒธ
    • host_and_job_paths (Optional[list[tuple[str, str]]]) ๐ŸŒธ
  • Attributes:
    • host_and_job_paths = None

๐Ÿงš TemporaryID

class toil.job.TemporaryID

This is a placeholder for an unregistered job ID that a JobDescription uses. Three places need to hold onto it:

  • JobDescription objects hold it to record normal relationships ๐Ÿ’–
  • Jobs hold it to key their connected-component registries, and to record predecessor relationships so an EncapsulatedJob can add itself as a child ๐ŸŒธ
  • Services hold it to tie back to their hosting jobs, so the service tree can be built up from Service objects โœจ
  • Methods:
    • __str__() โ†’ str ๐Ÿ’…
    • __repr__() โ†’ str ๐Ÿ’…
    • __hash__() โ†’ int ๐Ÿ’…
    • __eq__(other) โ†’ bool ๐Ÿ’…
      • other (Any)
    • __ne__(other) โ†’ bool ๐Ÿ’…
      • other (Any)

๐Ÿ”ฅ AcceleratorRequirement

class toil.job.AcceleratorRequirement

  • Bases: TypedDict

This is the requirement for one or more computational accelerators, like a GPU or FPGA ๐Ÿ”ฅ It has these fields:

  • count: int โ€” how many of the accelerator are needed to run the job ๐Ÿ‘‘
  • kind: str โ€” what kind of accelerator is required. It can be "gpu". Other kinds defined in the future might be "fpga", etc. ๐Ÿ’œ
  • model: typing_extensions.NotRequired[str] โ€” what model of accelerator is needed. The exact set of values depends on what the backing scheduler calls its accelerators, and strings like "nvidia-tesla-k80" might be expected to work. If a specific model isn't required, this should be absent ๐Ÿ™ˆ
  • brand: typing_extensions.NotRequired[str] โ€” what brand or manufacturer of accelerator is required. The exact set of values depends on what the backing scheduler calls the brands of its accelerators, and strings like "nvidia" or "amd" might be expected to work. If a specific brand isn't required (for example, because the job can use multiple brands of accelerator that support a given API), this should be absent ๐Ÿฆ‹
  • api: typing_extensions.NotRequired[str] โ€” what API is used to talk to the accelerator. It can be "cuda". Other APIs supported in the future might be "rocm", "opencl", "metal", etc. If the job doesn't need a particular API to talk to the accelerator, this should be absent ๐ŸŒˆ

๐ŸŒธ parse_accelerator

toil.job.parse_accelerator(spec)

This parses an AcceleratorRequirement specified by user code ๐ŸŽ€ It supports formats like these:

>>> parse_accelerator(8)
{'count': 8, 'kind': 'gpu'}

>>> parse_accelerator("1")
{'count': 1, 'kind': 'gpu'}

>>> parse_accelerator("nvidia-tesla-k80")
{'count': 1, 'kind': 'gpu', 'model': 'nvidia-tesla-k80', 'brand': 'nvidia'}

>>> parse_accelerator("nvidia-tesla-k80:2")
{'count': 2, 'kind': 'gpu', 'model': 'nvidia-tesla-k80', 'brand': 'nvidia'}

>>> parse_accelerator("gpu")
{'count': 1, 'kind': 'gpu'}

>>> parse_accelerator("cuda:1")
{'count': 1, 'kind': 'gpu', 'api': 'cuda', 'brand': 'nvidia'}

>>> parse_accelerator({"kind": "gpu"})
{'count': 1, 'kind': 'gpu'}

>>> parse_accelerator({"brand": "nvidia", "count": 5})
{'count': 5, 'kind': 'gpu', 'brand': 'nvidia'}

If nothing is specified, it assumes we're talking about GPUs, and about one of them ๐Ÿ”ฅ it knows that "gpu" is a kind, "cuda" is an API, and "nvidia" is a brand ๐Ÿ’…

  • Raises:
    • ValueError โ€” if it gets something it can't parse ๐Ÿ˜ญ
    • TypeError โ€” if it gets something it can't parse because it's the wrong type ๐Ÿ’€

Parameters ๐Ÿ’…

  • spec (Union[int, str, dict[str, Union[str, int]]]) โ€” the bestie of this function can be an int, a str, or a dict with str keys whose values are either a str or an int ๐ŸŽ€

Return type ๐Ÿฆ‹ AcceleratorRequirement

โœจ toil.job.accelerator_satisfies(candidate, requirement, ignore=[]) โœจ

Okay so this one checks if a candidate at least partially satisfies the given requirement ๐Ÿ’–

Returns ๐ŸŒธ True if the candidate at least partially satisfies the requirement. It checks every field except count, so the number of accelerators doesn't matter here ๐Ÿ™ˆ

Parameters ๐Ÿงš

  • candidate (AcceleratorRequirement)
  • requirement (AcceleratorRequirement)
  • ignore (list[str])

Return type ๐Ÿ‘‘ bool

โœจ toil.job.accelerators_fully_satisfy(candidates, requirement, ignore=[]) โœจ

This one is giving full check energy ๐Ÿ’… It figures out if a whole set of accelerators satisfies a requirement, and it ignores any fields listed in ignore ๐Ÿ”ฅ

Returns ๐ŸŒˆ True if the AcceleratorRequirement requirement is fully satisfied by the ones in the list, taken together. This time it checks every field, count included โญ

Parameters ๐Ÿ“

  • candidates (Optional[list[AcceleratorRequirement]])
  • requirement (AcceleratorRequirement)
  • ignore (list[str])

Return type ๐Ÿ’œ bool


๐ŸŽ€ class toil.job.RequirementsDict ๐ŸŽ€

Bases: TypedDict

This is the typed storage for a job's requirements, and it's lowkey iconic because each requirement can have a different type depending on what it is ๐Ÿฆ‹

  • cores โ€” typing_extensions.NotRequired[int | float]
  • memory โ€” typing_extensions.NotRequired[int]
  • disk โ€” typing_extensions.NotRequired[int]
  • accelerators โ€” typing_extensions.NotRequired[list[AcceleratorRequirement]]
  • preemptible โ€” typing_extensions.NotRequired[bool]

toil.job.REQUIREMENT_NAMES = ['disk', 'memory', 'cores', 'accelerators', 'preemptible'] ๐ŸŒธ

๐Ÿงš Parseable type aliases ๐Ÿงš

These are the type aliases Toil uses for parsing requirements. There's no extra description for them, so just know they exist ๐Ÿซถ

  • toil.job.ParsedRequirement
  • toil.job.ParseableIndivisibleResource
  • toil.job.ParseableDivisibleResource
  • toil.job.ParseableFlag
  • toil.job.ParseableAcceleratorRequirement
  • toil.job.ParseableRequirement

๐Ÿ’– class toil.job.Requirer(requirements) ๐Ÿ’–

Base class that handles storing and presenting requirements. It's the main character of the requirements world, and it has cores, memory, disk, and preemptability as properties โœจ

Parameters ๐ŸŒˆ

  • requirements (Mapping[str, ParseableRequirement])

assignConfig(config)

Assigns the given config object so it can provide default values. This has to be called exactly once on a loaded JobDescription before any requirements get queried, so don't forget ๐Ÿ’€

Parameters

  • config (toil.common.Config) โ€” the config object to query

Return type None

__getstate__()

Returns the dict that becomes the instance's __dict__ when pickling ๐Ÿ”ฎ

Return type dict[str, Any]

__copy__()

Returns a semantically-shallow copy of the object, for copy.copy() ๐Ÿฆ‹

Return type Requirer

__deepcopy__(memo)

Returns a semantically-deep copy of the object, for copy.deepcopy() ๐Ÿซง

Parameters

  • memo (Any)

Return type Requirer

property requirements

Gets the dict containing all non-None, non-defaulted requirements. Literally the full list of what the job needs ๐Ÿ“‹

Return type RequirementsDict

property disk

Gets the maximum number of bytes of disk required ๐Ÿ’พ

Return type int

property memory

Gets the maximum number of bytes of memory required ๐Ÿง 

Return type int

property cores

Gets the number of CPU cores required ๐Ÿ–ฅ๏ธ

Return type Union[int, float]

property preemptible

Says whether a preemptible node is permitted, or whether a nonpreemptible one is required. It's giving yes-or-no drama ๐Ÿ™ˆ

Return type bool

preemptable(val)

Parameters

  • val (ParseableFlag)

Return type None

property accelerators

Gets any accelerators that are needed, like GPUs ๐ŸŽฎ

Return type list[AcceleratorRequirement]

scale(requirement, factor)

Returns a copy of this object with the given requirement scaled up or down. It only works on requirements where scaling actually makes sense, so no scaling your vibes ๐Ÿ˜ญ

Parameters

  • requirement (str)
  • factor (float)

Return type Requirer

requirements_string()

Gets a nice human-readable string of our requirements ๐Ÿ“

Return type str


๐Ÿ“ class toil.job.JobBodyReference ๐Ÿ“

Bases: NamedTuple

This is a reference from a job description to its body, basically the job's little pointer to where the actual work lives ๐Ÿงš

  • file_store_id (str) โ€” the File ID of the job's body. For the root job, it's a special shared file name instead ๐ŸŒธ
  • module_string (str) โ€” a stringified description of the module needed to load the body ๐Ÿ”ฎ

๐Ÿ‘‘ class toil.job.JobDescription(requirements, jobName, unitName='', displayName='', local=None, files=None) ๐Ÿ‘‘

Bases: Requirer

This is the one place that stores everything the Toil Leader ever needs to know about a Job. It's basically the job's whole resume ๐Ÿ’… It includes:

  • Resource requirements. ๐Ÿ’ช
  • Which jobs are children, follow-ons, or predecessors of this job. ๐Ÿ‘ฏ
  • A reference to the Job object in the job store. ๐Ÿ—‚๏ธ

You can get it from an actual, executable Job object, and you can use it to get the Job object back from the JobStore. It never holds other Jobs or JobDescriptions, though. Everything gets referenced by ID, no drama ๐Ÿซถ

It's subclassed into variants for checkpoint jobs and service jobs, which each have their own specific parameters ๐Ÿฆ‹

Parameters ๐ŸŒˆ

  • requirements (Mapping[str, Union[int, str, float, bool, list]])
  • jobName (str)
  • unitName (Optional[str])
  • displayName (Optional[str])

Okay so the leftover bits of the list first, bestie ๐Ÿ’…

  • local (Optional[bool]) ๐Ÿซถ
  • files (Optional[set[toil.fileStores.FileID]]) ๐ŸŽ€

Now the actual attributes, and yes they're all giving main character ๐Ÿ‘‘

  • local: bool, defaults to False ๐Ÿฆ‹
  • jobName ๐Ÿ’–
  • unitName, defaults to '' ๐ŸŒธ
  • displayName, defaults to '' โœจ
  • jobStoreID: str or TemporaryID (toil.job.TemporaryID) ๐Ÿงš
  • filesToDelete, defaults to [] ๐Ÿ’œ
  • predecessorNumber, defaults to 0 ๐Ÿ“
  • predecessorsFinished ๐Ÿ‘‘
  • childIDs: set[str] ๐ŸŒˆ
  • followOnIDs: set[str] ๐Ÿ”ฅ
  • successor_phases: list[set[str]] โญ
  • serviceTree ๐Ÿฆ‹
  • logJobStoreFileID, defaults to None ๐Ÿ’€
  • files_to_use ๐Ÿ™ˆ

get_names()

Okay this one is literally your ID card ๐Ÿชช It gets the names and ID of this job, bundled up as a named tuple.

Return type: toil.bus.Names

get_chain()

Ngl this is giving time travel โณ It gets all the jobs that ran in this job's chain, in order. Each job comes back as a named tuple with its various names plus its original job store ID. The jobs are listed in execution order. If the job hasn't run yet or it didn't chain, you just get a one-item list ๐ŸŒธ

Return type: list[toil.bus.Names]

serviceHostIDsInBatches()

This one finds all the batches of service host job IDs that can start at the same time ๐Ÿ”ฅ They come back in the order they need to start in.

Return type: Iterator[list[str]]

successorsAndServiceHosts()

Gets an iterator over all child, follow-on, and service job IDs ๐Ÿ’–

Return type: Iterator[str]

allSuccessors()

Gets an iterator over all child, follow-on, and chained, inherited successor job IDs. Follow-ons always come before children ๐Ÿซถ

Return type: Iterator[str]

successors_by_phase()

Gets an iterator over all child, follow-on, and chained inherited successor job IDs, along with their phase number on the stack ๐Ÿงš Phases run from higher numbers down to lower numbers.

Return type: Iterator[tuple[int, str]]

services (property)

Gets a collection of the IDs of service host jobs for this job, in arbitrary order โœจ It'll be empty if the job has no unfinished services.

has_body()

Returns True if we have a job body associated, and False otherwise ๐ŸŽ€

Return type: bool

attach_body(file_store_id, user_script)

Attaches a job body to this JobDescription ๐Ÿฆ‹ You give it the file store ID the body lives at, plus the required user script module. The file store ID can also be "firstJob" for the root job, which is stored as a shared file instead.

Parameters

  • file_store_id (str)
  • user_script (toil.resource.ModuleDescriptor)

Return type: None

detach_body()

Drops the body reference from a JobDescription ๐Ÿ™ˆ

Return type: None

get_body()

Gets the info you need to load the job body ๐Ÿ’… It returns a file store ID (or the magic shared file name "firstJob") and a user script module.

Return type: tuple[str, toil.resource.ModuleDescriptor]

Heads up bestie: this one fails if no body is attached, so check has_body() first ๐Ÿ’€

nextSuccessors()

Returns the collection of job IDs for the successors of this job that are ready to run ๐Ÿ”ฅ If those jobs have multiple predecessor relationships, they might still be blocked on other jobs.

It returns None when we're at the final phase (all successors are done). It returns an empty collection if there are more phases but they can't be entered yet, for example because we're still waiting on the job itself to run ๐ŸŒˆ

Return type: Optional[set[str]]

filterSuccessors(predicate)

Keeps only the successor jobs that the given predicate function approves ๐Ÿ‘‘ The predicate gets called with the job's ID. Every other successor gets treated as complete and forgotten, no cap ๐Ÿ’€

Parameters

  • predicate (Callable[[str], bool])

Return type: None

filterServiceHosts(predicate)

Keeps only the services that the given predicate approves ๐Ÿงš The predicate gets called with the service host job's ID. Every other service gets treated as complete and forgotten ๐Ÿ’œ

Parameters

  • predicate (Callable[[str], bool])

Return type: None

clear_nonexistent_dependents(job_store)

Removes all references to child, follow-on, and associated service jobs that don't exist anymore ๐Ÿซถ That means every one that's been completed and removed.

Parameters

  • job_store (toil.jobStores.abstractJobStore.AbstractJobStore)

Return type: None

clear_dependents()

Removes all references to successor and service jobs. Full clean slate ๐Ÿงนโœจ

Return type: None

is_subtree_done()

Checks if the subtree is done ๐Ÿฆ‹ It returns True if the job appears to be done, and all related child, follow-on, and service jobs appear to be finished and removed.

Return type: bool

replace(other)

Takes on the ID of another JobDescription while keeping our own state and type ๐ŸŒธ When it gets updated in the JobStore, we'll save over the other JobDescription.

This is super useful for chaining jobs, since the chained-to job can replace the parent job ๐Ÿ”ฅ It also merges the cleanup state and successors (other than this job) from the job being replaced into this one.

Parameters

  • other (JobDescription): the job description to replace

Return type: None

assert_is_not_newer_than(other)

Makes sure this JobDescription isn't newer than a prospective new version of the JobDescription ๐Ÿ™ˆ

Parameters

  • other (JobDescription)

Return type: None

is_updated_by(other)

Returns True if the passed JobDescription is a distinct, newer version of this one ๐Ÿ’–

Parameters

  • other (JobDescription)

Return type: bool

addChild(childID)

Makes the job with the given ID a child of the described job ๐Ÿงš

Parameters

  • childID (str)

Return type: None

addFollowOn(followOnID)

Makes the job with the given ID a follow-on of the described job ๐Ÿซถ

Parameters

  • followOnID (str)

Return type: None

addServiceHostJob(serviceID, parentServiceID=None)

Okay so this one is a whole vibe ๐Ÿ’… It makes the ServiceHostJob with the given ID a service of the job we're describing ๐Ÿฆ‹

If you pass a parent ServiceHostJob ID, that parent service gets started first ๐Ÿ”ฅ and it has to have already been added. No cutting the line, bestie ๐Ÿ™ˆ

hasChild(childID)

Checks if the job with the given ID is a child of the described job ๐ŸŒธ It returns True if it is.

Parameters

  • childID (str)

Return type: bool

hasFollowOn(followOnID)

Tests if the job with the given ID is a follow-on of the described job ๐Ÿ’œ

Parameters

  • followOnID (str)

Return type: bool

hasServiceHostJob(serviceID)

Tests if the ServiceHostJob is a service of the described job โœจ

Return type: bool

renameReferences(renames)

This applies the given dict of ID renames to every reference to jobs ๐Ÿฆ‹ It does not touch our own ID or the IDs of finished predecessors ๐Ÿ™…โ€โ™€๏ธ Any IDs that aren't in the renames dict stay exactly as they are.

Parameters

  • renames (dict[TemporaryID, str]) โ€” the rename operations to apply

Return type: None

addPredecessor()

Lets the JobDescription know that a predecessor has been added to its Job ๐ŸŽ€

Return type: None

onRegistration(jobStore)

Does setup work that needs the JobStore ๐Ÿงš The Job saving logic calls this once the JobDescription meets the JobStore and has its ID assigned.

It's overridden to handle setup like hooking up flag files for service jobs, which needs the JobStore to exist first ๐ŸŒˆ

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore) โ€” the job store we are being placed into

Return type: None

setupJobAfterFailure(exit_status=None, exit_reason=None)

This is the post-failure glow-up ๐Ÿ’– It reduces remainingTryCount if it's greater than zero, and bumps the memory up to at least the default memory. Why? Running out of memory is super common, so this is a preventative move ๐Ÿซถ

You need a configuration assigned first (see toil.job.Requirer.assignConfig()) or this won't work.

Parameters

  • exit_status (Optional[int]) โ€” the exit code from the job
  • exit_reason (Optional[toil.batchSystems.abstractBatchSystem.BatchJobExitReason]) โ€” why the job stopped, if the batch system can tell us

Return type: None

getLogFileHandle(jobStore)

Creates a context manager that yields a file handle to the log file ๐Ÿ“ It assumes logJobStoreFileID is already set, so make sure that's happening first ๐Ÿ’…

property remainingTryCount

Gets the number of tries left ๐Ÿ”ข This is the try count set on the JobDescription. If none is set, you get the default, which is based on the retry count in the config.

clearRemainingTryCount()

Clears remainingTryCount and resets it to its default value ๐Ÿงน

It returns True if the JobDescription was actually modified, and False if it wasn't.

Return type: bool

__str__()

Produces a useful logging string that identifies this job ๐Ÿชช

Return type: str

__repr__()

This one's listed without a description, so there's no extra tea on it here ๐Ÿต

reserve_versions(count)

Reserves job version numbers for later, so they can be journaled asynchronously ๐Ÿ“š

Parameters

  • count (int)

Return type: None

pre_update_hook()

Runs right before a created or updated version of this job gets pickled and saved ๐Ÿซง The job store is the one that calls it.

Return type: None


class toil.job.ServiceJobDescription(*args, **kwargs)

Bases: JobDescription

This is a description of a job that hosts a service ๐Ÿ 

terminateJobStoreID: str | None = None
startJobStoreID: str | None = None
errorJobStoreID: str | None = None

onRegistration(jobStore)

Sets up flag files ๐Ÿšฉ When a ServiceJobDescription first meets the JobStore, this is where it gets its flag files set up.


class toil.job.CheckpointJobDescription(*args, **kwargs)

Bases: JobDescription

This is a description of a job that is a checkpoint ๐Ÿ“

checkpoint: JobBodyReference | None = None
checkpointFilesToDelete = []

set_checkpoint()

Saves a body checkpoint into self.checkpoint ๐Ÿ’พ

Return type: str

restore_checkpoint()

Restores the body checkpoint from self.checkpoint โช

Return type: None

restartCheckpoint(jobStore)

Restarts a checkpoint after the total failure of the jobs in its subtree ๐Ÿ” The changes get written to the jobStore right away. All of the checkpoint's successors are deleted, but its try count does not go down.

It returns a list with the IDs of any successors that were deleted ๐Ÿ“‹

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)

Return type: list[str]


class toil.job.Job(memory=None, cores=None, disk=None, accelerators=None, preemptible=None, preemptable=None, unitName='', checkpoint=False, displayName='', descriptionClass=None, local=None, files=None)

This class represents a unit of work in toil ๐Ÿ‘‘ It's the main character of the whole show โœจ

Parameters

  • memory (Optional[ParseableIndivisibleResource])
  • cores (Optional[ParseableDivisibleResource])
  • disk (Optional[ParseableIndivisibleResource])
  • accelerators (Optional[ParseableAcceleratorRequirement])
  • preemptible (Optional[ParseableFlag])
  • preemptable (Optional[ParseableFlag])
  • unitName (Optional[str])
  • checkpoint (Optional[bool])
  • displayName (Optional[str])
  • descriptionClass (Optional[type])
  • local (Optional[bool])
  • files (Optional[set[toil.fileStores.FileID]])
userModule: toil.resource.ModuleDescriptor

__str__()

Produces a useful logging string that identifies this Job and sets it apart from its JobDescription ๐Ÿ”

Return type: str

check_initialized()

Makes sure that Job.__init__() has been called by any subclass __init__() ๐Ÿ›ก๏ธ This works because the self._description instance variable should always be set after __init__().

If __init__() hasn't been called, it raises an error ๐Ÿšจ

Return type: None

property jobStoreID: str | TemporaryID

Gets the ID of this Job ๐Ÿชช

Return type: Union[str, TemporaryID]

  • property description: JobDescription: okay bestie, this one exposes the JobDescription that describes this job ๐Ÿ’–
    • Return type: JobDescription
  • property disk: int: the max number of bytes of disk the job will need to run ๐Ÿ’พ
    • Return type: int
  • property memory: int: the max number of bytes of memory the job will need to run ๐Ÿง 
    • Return type: int
  • property cores: int | float: the number of CPU cores required ๐Ÿ”ฅ
    • Return type: Union[int, float]
  • property accelerators: list[AcceleratorRequirement]: any accelerators the job needs, like GPUs ๐ŸŽฎ
    • Return type: list[AcceleratorRequirement]
  • property preemptible: bool: whether the job can run on a preemptible node ๐Ÿฆ‹
    • Return type: bool
  • preemptable() ๐Ÿ™ˆ
    • Return type: bool
  • property checkpoint: bool: determines whether the job is a checkpoint job or not โœจ
    • Return type: bool
  • property files_to_use: set[toil.fileStores.FileID] ๐Ÿ“
    • Return type: set[toil.fileStores.FileID]
  • add_to_files_to_use(val) โž•
    • Parameters: val (toil.fileStores.FileID)
    • Return type: None
  • remove_from_files_to_use(val) โž–
    • Parameters: val (toil.fileStores.FileID)
    • Return type: None
  • assignConfig(config): assigns the given config object ๐ŸŽ€
    • It gets used by various actions inside the Job class, so it's kind of a big deal.
    • Parameters: config (toil.common.Config) -- the Config object to query
    • Return type: None
  • run(fileStore): override this one to do the actual work and dynamically create successor jobs ๐Ÿ’…
    • Parameters: fileStore (toil.fileStores.abstractFileStore.AbstractFileStore) -- this is what you use to make local and globally shareable temp files and send log messages to the leader process ๐Ÿ“
    • Returns: whatever the function returns can be passed to other jobs with toil.job.Job.rv() ๐ŸŽ
    • Return type: Any
  • addChild(childJob): adds a childJob to run as a child of this job ๐Ÿ‘ถ
    • Child jobs run right after this job's toil.job.Job.run() method finishes.
    • Returns: childJob, for call chaining
    • Parameters: childJob (Job)
    • Return type: Job
  • hasChild(childJob): checks if childJob is already a child of this job ๐Ÿ‘€
    • Returns: True if childJob is a child of the job, otherwise False.
    • Parameters: childJob (Job)
    • Return type: bool
  • addFollowOn(followOnJob): adds a follow-on job ๐ŸŒธ
    • Follow-on jobs run after the child jobs and their successors have finished.
    • Returns: followOnJob, for call chaining
    • Parameters: followOnJob (Job)
    • Return type: Job
  • hasPredecessor(job): checks if a given job is already a predecessor of this job ๐Ÿ”
    • Parameters: job (Job)
    • Return type: bool
  • hasFollowOn(followOnJob): checks if the given job is already a follow-on of this job ๐Ÿง
    • Returns: True if followOnJob is a follow-on of this job, otherwise False.
    • Parameters: followOnJob (Job)
    • Return type: bool
  • addService(service, parentService=None): adds a service, and services are iconic ๐ŸŒˆ
    • The service's toil.job.Job.Service.start() method gets called after run finishes but before any successors run. Its toil.job.Job.Service.stop() method gets called once the successors have run.
    • Services let things like databases and servers get started and accessed by jobs in a workflow. Literally the main character of workflows ๐Ÿ‘‘
    • > Raises toil.job.JobException if the service has already been made the child of a job or another service.
    • Parameters:
      • service (Job) -- the service to add
      • parentService (Optional[Job]) -- a service that gets started before service is started. This lets you build trees of services. parentService must be a service of this job.
    • Returns: a promise that gets replaced with the return value from toil.job.Job.Service.start() of the service, in any successor of the job โœจ
    • Return type: Promise
  • hasService(service): returns True if the given Service is a service of this job, and False otherwise ๐Ÿ’œ
    • Parameters: service (Job)
    • Return type: bool
  • addChildFn(fn, *args, **kwargs): adds a function as a child job ๐Ÿงš
    • Parameters: fn (Callable) -- the function to run as a child job, with *args and **kwargs as its arguments. See toil.job.FunctionWrappingJob for the reserved keyword arguments you use to set resource requirements.
    • Returns: the new child job that wraps fn
    • Return type: FunctionWrappingJob
  • addFollowOnFn(fn, *args, **kwargs): adds a function as a follow-on job ๐Ÿฆ‹
    • Parameters: fn (Callable) -- the function to run as a follow-on job, with *args and **kwargs as its arguments. See toil.job.FunctionWrappingJob for the reserved keyword arguments you use to set resource requirements.
    • Returns: the new follow-on job that wraps fn
    • Return type: FunctionWrappingJob
  • addChildJobFn(fn, *args, **kwargs): adds a job function as a child job ๐Ÿซถ
    • See toil.job.JobFunctionWrappingJob for what a job function is.
    • Parameters: fn (Callable) -- the job function to run as a child job, with *args and **kwargs as its arguments. See toil.job.JobFunctionWrappingJob for the reserved keyword arguments you use to set resource requirements.
    • Returns: the new child job that wraps fn
    • Return type: FunctionWrappingJob
  • addFollowOnJobFn(fn, *args, **kwargs): adds a follow-on job function ๐ŸŒŸ
    • See toil.job.JobFunctionWrappingJob for what a job function is.

Okay so the Parameters for this one are giving main character energy ๐Ÿ’–

  • fn (Callable) โ€” the job function that runs as a follow-on job, with *args and **kwargs passed along to it. Peep toil.job.JobFunctionWrappingJob for the reserved keyword arguments you use to set your resource requirements ๐Ÿ’…

Returns

  • The new follow-on job that wraps fn โœจ

Return type

  • FunctionWrappingJob (toil.job.FunctionWrappingJob) ๐Ÿฆ‹

๐ŸŒธ property tempDir: str

Okay bestie, this is just a shortcut for calling job.fileStore.getLocalTempDir() ๐Ÿงš The temp dir gets created on the very first call, and every call after that gives you the same one. No cap, it's consistent. โœจ :return: Path to tempDir. See job.fileStore.getLocalTempDir

Return type

  • str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’œ

๐Ÿ“ฃ log(text, level=logging.INFO)

This one logs using fileStore.log_to_leader() ๐Ÿ”ฅ

Parameters

  • text (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

  • None ๐Ÿ’€

๐ŸŽ€ static wrapFn(fn, *args, **kwargs)

Makes a Job out of a function, and it's literally so iconic ๐Ÿ˜ญ It's a convenience function for the constructor of toil.job.FunctionWrappingJob.

Parameters

  • fn โ€” the function to run with *args and **kwargs as its arguments. Check out toil.job.JobFunctionWrappingJob for the reserved keyword arguments used to set resource requirements ๐Ÿ“

Returns

  • The new function that wraps fn ๐ŸŒˆ

Return type

  • FunctionWrappingJob (toil.job.FunctionWrappingJob) โœจ

๐Ÿ‘‘ static wrapJobFn(fn, *args, **kwargs)

Makes a Job out of a job function. Also a convenience function, this time for the constructor of toil.job.JobFunctionWrappingJob ๐Ÿ’…

Parameters

  • fn โ€” the job function to run with *args and **kwargs as its arguments. Same deal as before: check toil.job.JobFunctionWrappingJob for the reserved keyword arguments used to set resource requirements ๐Ÿซถ

Returns

  • The new job function that wraps fn ๐Ÿ’–

Return type

  • JobFunctionWrappingJob (toil.job.JobFunctionWrappingJob) ๐Ÿฆ‹

๐Ÿงš encapsulate(name=None)

This encapsulates the job, so peep toil.job.EncapsulatedJob. It's a convenience function for the constructor of toil.job.EncapsulatedJob โœจ

Parameters

  • name (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” a human-readable name for the encapsulated job ๐ŸŒธ

Returns

  • An encapsulated version of this job ๐Ÿ”ฅ

Return type

  • EncapsulatedJob (toil.job.EncapsulatedJob) ๐Ÿ’œ

๐Ÿ”ฎ rv(*path)

This one creates a promise (toil.job.Promise) ๐Ÿฆ‹ The promise stands in for a return value of the job's run method, or, if it's a function-wrapping job, the wrapped function's return value. Lowkey the best way to pass results around.

Parameters

  • path ((Any)) โ€” an optional path for picking out a component of the promised return value. If it's absent or empty, you get the whole return value. Otherwise, the first element of the path selects one item from the return value. For that to work, the return value has to be a list, a dictionary, or any other type that implements the __getitem__() magic method. If the selected item is another composite value, the second element of the path can select an item from it, and so on and so forth ๐Ÿ’… For example, if the return value is [6,{'a':42}], then .rv(0) selects 6, rv(1) selects {'a':3}, and rv(1,'a') selects 3. To grab a slice from a slicable return value (like a tuple or list), make the path element a slice object. For example, if the return value is [6, 7, 8, 9], then .rv(slice(1, 3)) selects [7, 8]. Note that slicing really only makes sense at the end of the path, so keep that in mind ๐Ÿ‘€

Returns

  • A promise representing the return value of this job's toil.job.Job.run() method ๐ŸŒˆ

Return type

  • Promise (toil.job.Promise) โœจ

๐Ÿซง registerPromise(path)


๐Ÿ’Œ prepareForPromiseRegistration(jobStore)

This one sets things up so this job's promises can register themselves. It preps this job (the promisor) so its promises can register with it whenever the jobs they're promised to (the promisees) get serialized. The promisee holds the reference to the promise, usually as part of the job arguments, and when it gets pickled, so do the promises it refers to. Pickling a promise is what triggers it to be registered with the promisor ๐Ÿ“

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)

Return type

  • None โœจ

๐Ÿšง checkJobGraphForDeadlocks()

This ensures a graph of Jobs (one that hasn't been saved to the JobStore yet) doesn't have any pathological relationships between jobs that would cause deadlocks if we tried to run them. Bestie, deadlocks are not it ๐Ÿ˜ญ For more info, see toil.job.Job.checkJobGraphConnected(), toil.job.Job.checkJobGraphAcyclic() and toil.job.Job.checkNewCheckpointsAreLeafVertices().

โš ๏ธ Raises toil.job.JobGraphDeadlockException if the job graph is cyclic, contains multiple roots, or contains checkpoint jobs that aren't leaf vertices when defined (see toil.job.Job.checkNewCheckpointsAreLeaves()). Not a vibe.

๐ŸŒณ getRootJobs()

This returns the set of root job objects that contain this job. A root job is a job with no predecessors, which means it's not a child, follow-on, or service ๐Ÿฆ‹

Only deals with jobs created here, rather than jobs loaded from the job store ๐Ÿ™ˆ

Return type

  • set[Job] (/usr/share/doc/python3/html/library/stdtypes.html#set, toil.job.Job) ๐Ÿ’œ

๐Ÿงฉ checkJobGraphConnected()

โš ๏ธ Raises toil.job.JobGraphDeadlockException if toil.job.Job.getRootJobs() does not contain exactly one root job. Multiple roots is a whole deadlock situation ๐Ÿ’€

Return type

  • None ๐Ÿซถ

As execution always starts from one root job, having multiple root jobs will cause a deadlock to occur. Literally the one rule ๐Ÿ’…

Only deals with jobs created here, rather than jobs loaded from the job store โœจ

๐Ÿ•ธ๏ธ checkJobGraphAcylic()

โš ๏ธ Raises toil.job.JobGraphDeadlockException if the connected component of jobs containing this job contains any cycles of child/followOn dependencies in the augmented job graph (see below). Cycles like that are NOT allowed in valid job graphs ๐Ÿ™…โ€โ™€๏ธ

Return type

  • None ๐ŸŒธ

Okay so, a follow-on edge (A, B) between two jobs A and B is equivalent to adding a child edge to B from (1) A, (2) each child of A, and (3) the successors of each child of A. We call each of these an "implied" edge ๐Ÿ”ฎ The augmented job graph is a job graph that includes all the implied edges. Big brain stuff, but it's giving clarity โœจ

For a job graph G = (V, E), the algorithm is O(|V|^2). It's O(|V| + |E|) for a graph with no follow-ons. The former follow-on case could be improved! ๐ŸŒˆ

Only deals with jobs created here, rather than jobs loaded from the job store ๐Ÿงš

๐Ÿšฉ checkNewCheckpointsAreLeafVertices()

A checkpoint job is one that gets restarted if either it fails, or if any of its successors completely fails and exhausts their retries ๐Ÿ” A job is a leaf if it has no successors.

A checkpoint job has to be a leaf when it's first added to the job graph. Once its run method is invoked, it can then create direct successors. This restriction is made to simplify the implementation, so it's not you, it's the code ๐Ÿซถ

Only works on connected components of jobs that haven't been added to the JobStore yet ๐Ÿ™ˆ

โš ๏ธ Raises toil.job.JobGraphDeadlockException if there exists a job being added to the graph for which checkpoint=True and which is not a leaf. Not allowed, periodt ๐Ÿ’€

Return type

  • None ๐Ÿ’–

defer

defer(function, *args, **kwargs)

okay so defer is literally the cleanup crew ๐Ÿงนโœจ You register a deferred function (any callable) and Toil calls it once the current attempt at running this job wraps up. An attempt is considered concluded when the job function returns, raises an exception, or the process running it terminates abnormally. For class-based jobs, that means toil.job.Job.run() doing the same thing ๐Ÿ’…

The deferred function runs on the node that attempted the job, even if a later attempt happens on a different node ๐Ÿฆ‹

โš ๏ธ bestie, your deferred function should be idempotent ๐Ÿ’€ (safe to run more than once), because it might get called multiple times on the same node or even in the same process.

You can register more than one deferred function per attempt by calling defer again with different arguments. If you register the same function twice, with the same or different arguments, it gets called twice per attempt. So yeah, double registering means double calls ๐Ÿ‘ฏ

Typical examples are cleanup stuff that lives outside Toil's reach, like Docker containers, files sitting outside the work directory, etc. ๐Ÿงน๐ŸŒธ

Parameters

  • function (callable) โ€” the function that gets called after this job concludes ๐ŸŽฏ
  • args (list, see /usr/share/doc/python3/html/library/stdtypes.html#list) โ€” the arguments passed to the function
  • kwargs (dict, see /usr/share/doc/python3/html/library/stdtypes.html#dict) โ€” the keyword arguments passed to the function

Return type: None


class Runner

class Runner

This is the class that sets up and runs a Toil workflow, aka the main character ๐Ÿ‘‘ Its static methods are below.

getDefaultArgumentParser

static getDefaultArgumentParser(jobstore_as_flag=False)

Gets an argument parser with the Toil workflow options already added. This is the Right Way to get an argument parser in a Toil Python workflow ๐Ÿ’–

Parameters:

  • jobstore_as_flag (bool, see /usr/share/doc/python3/html/library/functions.html#bool) โ€” makes the job store option a --jobStore flag instead of a required jobStore positional argument

Returns: the argument parser used by a Toil workflow, with the Toil options added โœจ

Return type: configargparse.ArgParser

getDefaultOptions

static getDefaultOptions(jobStore=None, jobstore_as_flag=False)

Gets the default options for a Toil workflow ๐ŸŽ€

Parameters:

  • jobStore (Optional[toil.lib.misc.StrPath]) โ€” a string describing the job store for the workflow
  • jobstore_as_flag (bool, see /usr/share/doc/python3/html/library/functions.html#bool) โ€” makes the job store option a --jobStore flag instead of a required jobStore positional argument

Returns: the options used by a Toil workflow

Return type: argparse.Namespace (see /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

addToilOptions

static addToilOptions(parser, jobstore_as_flag=False)

Adds the default Toil options to an optparse (see /usr/share/doc/python3/html/library/optparse.html#module-optparse) or argparse (see /usr/share/doc/python3/html/library/argparse.html#module-argparse) parser object ๐Ÿง

๐Ÿ’… Honestly, just use getDefaultArgumentParser() instead. It makes a parser of the correct class so Toil's config file and environment variables actually work. If the parser you pass in here is just an argparse.ArgumentParser and not a configargparse.ArgParser, the Toil config file and environment variables will not be respected ๐Ÿ’€

Parameters:

  • parser (Union[optparse.OptionParser, argparse.ArgumentParser]) โ€” the options object you want to add Toil options to
  • jobstore_as_flag (bool, see /usr/share/doc/python3/html/library/functions.html#bool) โ€” makes the job store option a --jobStore flag instead of a required jobStore positional argument

Return type: None

startToil

static startToil(job, options)

Runs the Toil workflow using the given options ๐Ÿš€

โš ๏ธ This one is deprecated and has been replaced by toil.common.Toil.start. Sorry bestie, time to upgrade ๐Ÿฅบ

(see Job.Runner.getDefaultOptions and Job.Runner.addToilOptions) starting with this job. :param job: root job of the workflow :raises: toil.exceptions.FailedJobsException if, at the end of the function, there are still failed jobs. :return: the return value of the root job's run function.

Parameters:

  • job (Job, see <#toil.job.Job>) โ€” the root job of the workflow

Return type: Any


class Service

class Service(memory=None, cores=None, disk=None,
accelerators=None, preemptible=None, unitName='')

Bases: Requirer

This is an abstract class that defines the interface for a service ๐Ÿฆ‹ You should subclass it to define your own services. A service is not executed as a job. It runs inside a ServiceHostJob ๐Ÿ 

Parameters:

  • memory (Optional[ParseableIndivisibleResource])
  • cores (Optional[ParseableDivisibleResource])
  • disk (Optional[ParseableIndivisibleResource])
  • accelerators (Optional[ParseableAcceleratorRequirement])
  • preemptible (Optional[ParseableFlag])
  • unitName (Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str)

Class attributes

unitName = ''
jobName = 'Service'
hostID = None

start

abstractmethod start(job)

Starts the service ๐ŸŽฌ

Parameters:

  • job (ServiceHostJob, see <#toil.job.ServiceHostJob>) โ€” the underlying host job the service runs in. You can use it to register deferred functions, or to access the fileStore for making temporary files ๐Ÿงš

Returns: an object describing how to access the service. It must be pickleable, and jobs use it to access the service (see toil.job.Job.addService()) ๐Ÿ’œ

Return type: Any

stop

abstractmethod stop(job)

Stops the service. The function can block until it's complete ๐Ÿ›‘

Parameters:

  • job (ServiceHostJob, see <#toil.job.ServiceHostJob>) โ€” the underlying host job the service runs in. You can use it to register deferred functions, or to access the fileStore for making temporary files

Return type: None

check

check()

Checks that the service is still running ๐Ÿ‘€

Raises exceptions.RuntimeError: if the service failed, the service job gets labeled as failed ๐Ÿ’€

Returns: True if the service is still running, otherwise False. If it returns False, the service job is terminated and considered a success โœ…

โš ๏ธ Important point, bestie: if the service job exits because of a failure, it should raise a RuntimeError, not return False!

Return type: bool (see /usr/share/doc/python3/html/library/functions.html#bool)


getUserScript

getUserScript()

Return type: toil.resource.ModuleDescriptor (see <#toil.resource.ModuleDescriptor>) ๐Ÿ“œ

getTopologicalOrderingOfJobs

getTopologicalOrderingOfJobs()

Returns a list of jobs where, for every pair of indices i and j with i < j, the job at index i can run before the job at index j. It's giving order ๐Ÿง โœจ

Return type: list (see /usr/share/doc/python3/html/library/stdtypes.html#list) of Job (see <#toil.job.Job>)

This only considers jobs in this job's subgraph that are newly added, not jobs loaded from the job store. It ignores service jobs ๐Ÿ™ˆ

saveBody(jobStore)

Okay so this one saves the execution data for just this job into the JobStore ๐Ÿ’พโœจ, then fills in the JobDescription with everything needed to fetch it back later ๐Ÿฆ‹

bestie, the Job's JobDescription must have already been given a real jobStoreID before you call this ๐Ÿ™ˆ

Also, it does not save the JobDescription itself ๐Ÿ’€ lowkey a plot twist.

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore) โ€” the job store you're stashing the job body into ๐Ÿ—„๏ธ

Return type: None

saveAsRootJob(jobStore)

This one saves the job to the given jobStore as the root job of the whole workflow ๐Ÿ‘‘

Returns: the JobDescription describing this job ๐Ÿ’–

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)

Return type: JobDescription

classmethod loadJob(job_store, job_description)

Retrieves a toil.job.Job instance from a JobStore. It's giving retrieval queen energy ๐Ÿงš

Parameters

  • job_store (toil.jobStores.abstractJobStore.AbstractJobStore) โ€” the job store ๐Ÿ—„๏ธ
  • job_description (JobDescription) โ€” the JobDescription of the job you want to pull back out

Returns: the job referenced by the JobDescription ๐ŸŒธ

Return type: Job

set_debug_flag(flag)

Turns on the given debug option for the job ๐Ÿ”ฅ

Parameters

  • flag (str)

Return type: None

has_debug_flag(flag)

Returns true if the given debug flag is set. Quick vibe check, basically ๐Ÿ”

Parameters

  • flag (str)

Return type: bool

files_downloaded_hook(host_and_job_paths=None)

This is a function subclasses can call once they've finished downloading their input files ๐Ÿ“ฅโœจ

heads up: if the "download_only" debug flag is set, this will abort the job ๐Ÿ’€ so be careful!

You can hint it a list of file path pairs, one outside and one inside the job container. If you do, the container environment can be reconstructed ๐Ÿซถ

Parameters

  • host_and_job_paths (Optional[list[tuple[str, str]]])

Return type: None


exception toil.job.JobException(message)

Bases: Exception

This is the general job exception, the catch-all for when a job goes sideways ๐Ÿ˜ญ

Parameters

  • message (str)

exception toil.job.JobGraphDeadlockException(string)

Bases: JobException

This gets raised when a workflow has an unresolvable dependency, like a cycle ๐Ÿ”๐Ÿ’€ See toil.job.Job.checkJobGraphForDeadlocks().

class toil.job.FunctionWrappingJob(userFunction, *args, **kwargs)

Bases: Job

A job used to wrap a function. In its run method, the wrapped function gets called ๐ŸŽ€

Parameters

  • userFunction (Callable[[Ellipsis], Any])
  • args (Any)
  • kwargs (Any)

Attributes you can peek at:

  • userFunctionModule
  • userFunctionName = ''

run(fileStore)

Override this to do the actual work and dynamically spin up successor jobs ๐Ÿ’…

Parameters

  • fileStore (toil.fileStores.abstractFileStore.AbstractFileStore) โ€” used to make local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“

Returns: the return value of the function can be passed along to other jobs using toil.job.Job.rv() ๐Ÿฆ‹

Return type: Any

getUserScript()

Return type: str

class toil.job.JobFunctionWrappingJob(userFunction, *args, **kwargs)

Bases: FunctionWrappingJob

A job function is a function whose first argument is a Job instance, the wrapping job for the function. That means it can add successor jobs and use every method the Job class offers ๐Ÿ‘‘

To give the job function access to the toil.fileStores.abstractFileStore.AbstractFileStore instance (see toil.job.Job.run()), it gets made into a variable of the wrapping job called fileStore ๐Ÿซถ

To specify a job's resource requirements, you can pass these default keyword arguments:

  • memory
  • disk
  • cores
  • accelerators
  • preemptible

For example, to wrap a function into a job, you'd call:

Job.wrapJobFn(myJob, memory='100k', disk='1M', cores=0.1)

Parameters

  • userFunction (Callable[[Ellipsis], Any])
  • args (Any)
  • kwargs (Any)

property fileStore

Return type: toil.fileStores.abstractFileStore.AbstractFileStore โœจ

run(fileStore)

Override this to do the actual work and dynamically spin up successor jobs ๐Ÿ’…

Parameters

  • fileStore (toil.fileStores.abstractFileStore.AbstractFileStore) โ€” used to make local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“

Returns: the return value of the function can be passed along to other jobs using toil.job.Job.rv() ๐Ÿฆ‹

Return type: Any


class toil.job.PromisedRequirementFunctionWrappingJob(userFunction, *args, **kwargs)

Bases: FunctionWrappingJob

This handles dynamic resource allocation using toil.job.Promise instances ๐Ÿง  It spawns a child function using the parent function's parameters and the fulfilled promised resource requirements.

classmethod create(userFunction, *args, **kwargs)

Creates an encapsulated Toil job function with unfulfilled promised resource requirements ๐ŸŽ Once the promises get fulfilled, a child job function is created with the updated resource values. The subgraph is encapsulated so this child job function runs before any other children in the workflow. Otherwise, a different child might try to use an unresolved promise return value from the parent ๐Ÿ˜ญ

run(fileStore)

Override this to do the actual work and dynamically spin up successor jobs ๐Ÿ’…

Parameters

  • fileStore โ€” used to make local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“

Returns: the return value of the function can be passed along to other jobs using toil.job.Job.rv() ๐Ÿฆ‹

evaluatePromisedRequirements()

class toil.job.PromisedRequirementJobFunctionWrappingJob(userFunction, *args, **kwargs)

Bases: PromisedRequirementFunctionWrappingJob

This handles dynamic resource allocation for job functions. Check out toil.job.JobFunctionWrappingJob for more ๐Ÿ’–

run(fileStore)

Override this to do the actual work and dynamically spin up successor jobs ๐Ÿ’…

Parameters

  • fileStore โ€” used to make local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“

Returns: the return value of the function can be passed along to other jobs using toil.job.Job.rv() ๐Ÿฆ‹


class toil.job.EncapsulatedJob(job, unitName=None)

Bases: Job

A convenience Job class that makes a job subgraph appear to be a single job. It's giving illusion ๐Ÿช„

Say A is the root job of a job subgraph, and B is another job you want to run after A and all its successors have finished. For that, you use encapsulate:

#  Job A and subgraph, Job B
A, B = A(), B()
Aprime = A.encapsulate()
Aprime.addChild(B)
#  B will run after A and all its successors have completed, A and its subgraph of
# successors in effect appear to be just one job.

If the job you're encapsulating already has predecessors (aka it isn't the root job), the encapsulated job inherits them automatically ๐Ÿซถ. But bestie, if you add predecessors to the job being encapsulated after you make the encapsulated job, the encapsulating job will NOT inherit those ๐Ÿ˜ญ. So double-check that the encapsulated job has the right set of predecessors โœจ.

โš ๏ธ Careful! Predecessors added late don't carry over, so make sure the encapsulated job ends up with the full set it needs. ๐Ÿ’…

The return value of an encapsulated job (what you get from toil.job.Job.rv()) is the return value of the root job ๐Ÿ‘‘. That means A().encapsulate().rv() and A().rv() resolve to the same value once A or A.encapsulate() has run ๐Ÿ’–.

Parameters

  • job โ€” type: Optional[Job]
  • unitName โ€” type: Optional[str]

addChild(childJob)

Add a childJob to run as a child of this job ๐ŸŒธ. Child jobs kick off right after this job's toil.job.Job.run() method finishes.

Returns: childJob, so you can chain calls ๐Ÿ”—

Parameters: childJob (Job)

Return type: Job


addService(service, parentService=None)

Add a service ๐Ÿงš. The toil.job.Job.Service.start() method of the service gets called after the run method finishes, but before any successors run. Then its toil.job.Job.Service.stop() method gets called once the job's successors have all run ๐Ÿ.

Services are how things like databases and servers get started up and accessed by jobs in a workflow ๐ŸŽ€.

Raises toil.job.JobException โ€” if the service has already been made the child of a job or another service. Yikes ๐Ÿ’€

Parameters

  • service โ€” the Service to add.
  • parentService โ€” a Service that will be started before service is started. This lets you build trees of services ๐ŸŒณ. parentService must be a service of this job.

Returns: a promise that gets replaced with the return value from toil.job.Job.Service.start() of service, in any successor of the job ๐Ÿฆ‹.


addFollowOn(followOnJob)

Add a follow-on job ๐Ÿ’œ. Follow-on jobs run after the child jobs and their successors have all been run.

Returns: followOnJob, for call chaining

Parameters: followOnJob (Job)

Return type: Job


rv(*path)

Create a promise (toil.job.Promise) โœจ. This promise stands in for a return value of the job's run method. If the job is wrapping a function, it stands in for that function's return value instead.

Parameters: path ((Any)) โ€” an optional path for picking out one piece of the promised return value ๐Ÿ“. If the path is absent or empty, you get the entire return value. Otherwise, the first element of the path picks out an individual item from the return value. For that to work, the return value has to be a list, a dictionary, or some other type that implements the __getitem__() magic method. If the item you picked is another composite value, the second element of the path can pick an item out of that, and so on ๐Ÿช†.

Some examples, because they're iconic:

  • If the return value is [6,{'a':42}], then .rv(0) selects 6.
  • rv(1) selects {'a':3}.
  • rv(1,'a') selects 3.
  • To select a slice from a return value that can be sliced (like a tuple or list), the path element should be a slice object. Say the return value is [6, 7, 8, 9]. Then .rv(slice(1, 3)) selects [7, 8] ๐ŸŒˆ.
Heads up: slicing only really makes sense at the end of the path ๐Ÿ™ˆ.

Returns: a promise representing the return value of this job's toil.job.Job.run() method.

Return type: Promise


prepareForPromiseRegistration(jobStore)

Set things up so this job's promises can register themselves ๐Ÿ’…. You prepare this job (the promisor) so its promises can register with it whenever the jobs they're promised to (the promisees) get serialized.

The promisee holds the reference to the promise, usually as part of the job arguments. When it gets pickled, so do the promises it refers to. Pickling a promise is what triggers it to register with the promisor ๐Ÿ”—.


__reduce__()

Called during pickling to define the pickled representation of the job ๐Ÿฅน. We don't want to pickle our internal references to the job we encapsulate, so we leave them out. When it actually runs, we're just a no-op job that can maybe chain โ›“๏ธ.


getUserScript()


class toil.job.ServiceHostJob(service)

Bases: Job

A job that runs a service ๐Ÿ› ๏ธ. Toil uses this internally. Users should subclass Service instead of using this one, bestie ๐Ÿซถ.

Attributes:

  • serviceModule
  • service
  • pickledService = None

property fileStore โ€” Returns the file store, which the Service may need ๐Ÿ—‚๏ธ.


addChild(child)

Add a childJob to run as a child of this job ๐ŸŒธ. Child jobs run directly after this job's toil.job.Job.run() method has completed.

Returns: childJob, for call chaining


addFollowOn(followOn)

Add a follow-on job ๐Ÿ’œ. Follow-on jobs run after the child jobs and their successors have been run.

Returns: followOnJob, for call chaining


addService(service, parentService=None)

Add a service ๐Ÿงš. The toil.job.Job.Service.start() method of the service gets called after the run method finishes, but before any successors run. The service's toil.job.Job.Service.stop() method gets called once the job's successors have been run ๐Ÿ.

Services let things like databases and servers get started and accessed by jobs in a workflow ๐ŸŽ€.

Raises toil.job.JobException โ€” if the service has already been made the child of a job or another service ๐Ÿ’€.

Parameters

  • service โ€” the Service to add.
  • parentService โ€” a Service that will be started before service is started. This lets you build trees of services ๐ŸŒณ. parentService must be a service of this job.

Returns: a promise that gets replaced with the return value from toil.job.Job.Service.start() of service, in any successor of the job ๐Ÿฆ‹.


saveBody(jobStore)

Serializes the service itself before saving the host job's body ๐Ÿ“ฆ.


run(fileStore)

Override this to do your work and dynamically create successor jobs ๐Ÿ”ฅ.

Parameters: fileStore โ€” used to create local and globally sharable temporary files, and to send log messages to the leader process ๐Ÿ“ฃ.

Returns: the return value of the function can be passed to other jobs using toil.job.Job.rv() โœจ.


getUserScript()


class toil.job.FileMetadata

Bases: NamedTuple

Metadata for a file ๐Ÿงพ. Here's the breakdown:

  • source is the URL to grab the file from.
  • parent_dir is the parent directory of the source.
  • size is the size of the file. It's None if the filesize can't be retrieved ๐Ÿ™ˆ.

Fields:

  • source: str
  • parent_dir: str
  • size: int | None

toil.job.potential_absolute_uris(uri, path, importer=None, execution_dir=None)

Get the potential absolute URIs to check for an imported file ๐Ÿ”.

Given a URI or bare path, this yields, one at a time, every URI (with schemes) where we should actually try to find it. It considers the paths or URIs we want to search under or against, the current directory, and the importing WDL document if there is one ๐Ÿฆ‹.

Parameters

  • uri (str)
  • path (list[str])
  • importer (Optional[str])
  • execution_dir (Optional[str])

Return type: Iterator[str]

โœจ toil.job.get_file_sizes โœจ

toil.job.get_file_sizes(filenames, file_source, search_paths=None, include_remote_files=True, execution_dir=None)

okay bestie, this one is giving file detective ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿ” It takes relative-URI files in the environment you give it and turns them into absolute normalized URIs โœจ You get back a dictionary that maps the string values from the WDL file values to a tuple of the normalized URI, parent directory ID, and size of the file. The size can be None, which just means the size is unknown ๐Ÿ™ˆ

Parameters

  • filenames (List[str]) โ€” the list of filenames to evaluate on ๐Ÿ“‚
  • file_source (toil.jobStores.abstractJobStore.AbstractJobStore) โ€” the context to search for files with ๐Ÿ”Ž
  • task_path โ€” the dotted WDL name of the user-level code doing the importing (probably the workflow name) ๐Ÿ’–
  • search_paths (Optional[List[str]]) โ€” if you set this, it tries resolving the input location relative to the URLs or directories in this list ๐Ÿ—บ๏ธ
  • include_remote_files (bool) โ€” if set, files get imported from remote locations. If not, they stay as URI references ๐ŸŒ
  • execution_dir (Optional[str]) โ€” no description given, so we're vibing ๐Ÿคทโ€โ™€๏ธ

Return type

Dict[str, FileMetadata]


๐Ÿงฉ toil.job.CombineImportsJob ๐Ÿงฉ

class toil.job.CombineImportsJob(d, **kwargs)

Bases: Job

this job is the glue queen ๐Ÿ‘‘ It combines the outputs of multiple WorkerImportsJob into one promise โœจ

Parameters

  • d (Sequence[Promised[Dict[str, toil.fileStores.FileID]]]) ๐Ÿ’…

run(file_store) just merges the dicts ๐Ÿซถ

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type

Promised[Dict[str, toil.fileStores.FileID]]


๐Ÿฆ‹ toil.job.WorkerImportJob ๐Ÿฆ‹

class toil.job.WorkerImportJob(filenames, local=False, **kwargs)

Bases: Job

this one does its file imports on a worker instead of the leader ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ It assumes all local and cloud files are accessible, so make sure they actually are, bestie ๐Ÿ˜ญ

For the CWL/WDL runners, this class is only used when runImportsOnWorkers is enabled. So if that's off, this one is just chilling ๐ŸงŠ

Parameters

  • filenames (List[str])
  • local (bool)
  • kwargs (Any)

Attribute: filenames

static import_files(files, file_source)

this method imports a list of files into the jobstore and gives you back a mapping of each filename to its associated FileIDs ๐Ÿ—‚๏ธโœจ

When stream is true but the import is not streamable, the worker will run out of disk space and run a new import job with enough disk space instead. That's a whole plot twist, so watch out ๐Ÿ™ˆ

:param files: the list of files to import :param file_source: AbstractJobStore :return: a dictionary mapping filenames to the associated jobstore FileID

Parameters

  • files (List[str]) ๐Ÿ“„
  • file_source (toil.jobStores.abstractJobStore.AbstractJobStore)

Return type

Dict[str, toil.fileStores.FileID]

run(file_store) imports the workflow inputs, then creates and runs the workflow. It returns a promise of the workflow outputs ๐ŸŽ€

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type

Promised[Dict[str, toil.fileStores.FileID]]


๐ŸŒธ toil.job.ImportsJob ๐ŸŒธ

class toil.job.ImportsJob(file_to_data, max_batch_size, import_worker_disk, **kwargs)

Bases: Job

this job is the organizer ๐Ÿ—‚๏ธ๐Ÿ’œ It sorts out files and hands them off to individual WorkerImportJobs

For the CWL/WDL runners, this is only used when runImportsOnWorkers is enabled. Same energy as before, bestie ๐Ÿ’…

Parameters

  • file_to_data (Dict[str, FileMetadata])
  • max_batch_size (ParseableIndivisibleResource)
  • import_worker_disk (ParseableIndivisibleResource)
  • kwargs (Any)

run(file_store) imports the workflow inputs, then creates and runs the workflow ๐ŸŒˆ

Return: a tuple. The first part is a mapping from the candidate URI to the file ID. The second part is a mapping of the source filenames to their metadata. The candidate URI is a field in the file metadata ๐Ÿงพ

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type

Tuple[Promised[Dict[str, toil.fileStores.FileID]], Dict[str, FileMetadata]]


๐Ÿ”ฎ toil.job.Promise ๐Ÿ”ฎ

class toil.job.Promise(job, path)

this is a placeholder with main character energy โœจ It references a return value from a method as a promise before that method has actually run ๐Ÿ•ฐ๏ธ

It references a return value from a toil.job.Job.run() or toil.job.Job.Service.start() method as a promise before the method itself is run.

Here's the tea โ˜• Let T be a job. Instances of Promise (termed a promise) are returned by T.rv(), which is how you reference the return value of T's run function. When the promise gets passed to the constructor (or as an argument to a wrapped function) of a different, successor job, the promise gets swapped out for the actual referenced return value. This is how one job's return values can become input arguments for another job before the first job's run function has even executed ๐Ÿคฏ

Parameters

  • job (Job)
  • path (Any)

Attribute: filesToDelete

a set of IDs of files containing promised values, for when we know we won't need them anymore ๐Ÿ—‘๏ธ

Attributes: job, path ๐Ÿ’–

__reduce__()

returns the Promise class and its construction arguments. This gets called during pickling, when a promise (an instance of this class) is about to be pickled ๐Ÿฅ’

The construction arguments are evaluated during unpickling. They're the job store coordinates of a file that will hold the promised return value. By the time the promise is about to be unpickled, that file should already be populated, so make sure it is ๐Ÿซถ


๐Ÿง toil.job.T ๐Ÿง

๐Ÿง toil.job.Promised ๐Ÿง


๐ŸŒท toil.job.unwrap(p) ๐ŸŒท

toil.job.unwrap(p)

this function makes sure you actually have a promised value and not just a promise ๐Ÿ’… It's mostly useful for keeping the type-checker happy ๐Ÿ™ˆ

The "unwrap" terminology is borrowed from Rust, so if you're a Rustacean, this one's for you ๐Ÿฆ€

Parameters

  • p (Promised[T])

Return type

T


๐ŸŒท toil.job.unwrap_all(p) ๐ŸŒท

toil.job.unwrap_all(p)

same vibe as unwrap, but for a whole collection of promised values. It makes sure none of the promises are left hanging around ๐Ÿงบ It's mostly useful for type-checking too ๐Ÿ’–

Same deal with the name: the "unwrap" terminology is borrowed from Rust ๐Ÿฆ€

Parameters

  • p (Sequence[Promised[T]])

Return type

Sequence[T]


๐ŸŒŸ toil.job.PromisedRequirement ๐ŸŒŸ

class toil.job.PromisedRequirement(valueOrCallable, *args)

this class lets you dynamically allocate job function resource requirements ๐Ÿ’ช Use it when your resource requirements depend on the return value of a parent function ๐Ÿง 

(It involves toil.job.Promise instances, bestie.)

You can modify a PromisedRequirement by passing in a function that takes the promise as input, which is very galaxy-brain of you ๐ŸŒŒ

For example, let f, g, and h be functions. Then a Toil workflow can be defined like this:

A = Job.wrapFn(f)
B = A.addChildFn(g, cores=PromisedRequirement(A.rv())
C = B.addChildFn(h, cores=PromisedRequirement(lambda x: 2*x, B.rv()))

Parameters

  • valueOrCallable (Any)
  • args (Any)

getValue()

returns the PromisedRequirement value ๐Ÿ’–

Return type

Any

static convertPromises(kwargs)

returns True if a reserved resource keyword is a Promise or PromisedRequirement instance โœจ It also converts a Promise instance into a PromisedRequirement, so it's a whole glow-up ๐Ÿฆ‹

Parameters

  • kwargs (dict[str, Any]) โ€” the function keyword arguments ๐ŸŽ€

Return type

bool


๐Ÿ’€ toil.job.UnfulfilledPromiseSentinel ๐Ÿ’€

class toil.job.UnfulfilledPromiseSentinel(fulfillingJobName, file_id, unpickled)

this is a placeholder that's supposed to get overwritten by a proper promised value ๐Ÿ™…โ€โ™€๏ธ If it ever gets unpickled, it throws an exception, so don't let that happen, bestie ๐Ÿ˜ญ

Parameters

  • fulfillingJobName (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’–
  • file_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€
  • unpickled (Any) โœจ

fulfillingJobName ๐Ÿฆ‹

file_id ๐ŸŒธ

๐ŸŒ™ static __setstate__(stateDict)

Okay so this one only runs when you're unpickling, bestie ๐Ÿฅน

๐Ÿšซ It won't get unpickled unless the promise is still unresolved, so we throw an exception. Not cute, but that's the rule ๐Ÿ˜ญ

Parameters

  • stateDict (dict[str, Any]) (see /usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

  • None

๐Ÿ—‚๏ธ toil.jobStores

Submodules ๐Ÿงš

  • toil.jobStores.abstractJobStore

๐Ÿ—‚๏ธ toil.jobStores.abstractJobStore

โœจ Attributes โœจ

  • logger

๐Ÿšจ Exceptions ๐Ÿšจ

  • ProxyConnectionError โ€” Dummy class. ๐Ÿซถ
  • LocatorException โ€” Base exception class for all locator exceptions. ๐Ÿ’œ
  • InvalidImportExportUrlException โ€” Common base class for all non-exit exceptions. ๐ŸŒˆ
  • NoSuchJobException โ€” Indicates that the specified job does not exist. ๐Ÿ’€
  • ConcurrentFileModificationException โ€” Indicates that the file was attempted to be modified by multiple processes at once. ๐Ÿ˜ญ
  • NoSuchFileException โ€” Indicates that the specified file does not exist. ๐Ÿ™ˆ
  • NoSuchJobStoreException โ€” Indicates that the specified job store does not exist. ๐Ÿ“
  • JobStoreExistsException โ€” Indicates that the specified job store already exists. ๐Ÿ‘‘

๐Ÿงฑ Classes ๐Ÿงฑ

  • AbstractJobStore โ€” Represents the physical storage for the jobs and files in a Toil workflow. ๐Ÿ”ฅ
  • JobStoreSupport โ€” A mostly fake JobStore to access URLs not really associated with real job ๐Ÿงš

๐Ÿ“ฆ Module Contents ๐Ÿ“ฆ

  • toil.jobStores.abstractJobStore.logger

exception toil.jobStores.abstractJobStore.ProxyConnectionError ๐Ÿ’…

Bases: BaseException (see /usr/share/doc/python3/html/library/exceptions.html#BaseException)

Dummy class.

exception toil.jobStores.abstractJobStore.LocatorException(error_msg, locator, prefix=None) ๐Ÿ’–

Bases: Exception (see /usr/share/doc/python3/html/library/exceptions.html#Exception)

Base exception class for all locator exceptions. For example, job store/aws bucket exceptions where they already exist. It's giving organized chaos ๐ŸŒธ

Parameters

  • error_msg (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • locator (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • prefix (Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str)

exception toil.jobStores.abstractJobStore.InvalidImportExportUrlException(url) ๐Ÿฆ‹

Bases: Exception (see /usr/share/doc/python3/html/library/exceptions.html#Exception)

Common base class for all non-exit exceptions.

Parameters

  • url (urllib.parse.ParseResult, see /usr/share/doc/python3/html/library/urllib.parse.html#urllib.parse.ParseResult)

exception toil.jobStores.abstractJobStore.NoSuchJobException(jobStoreID) ๐Ÿงš

Bases: Exception (see /usr/share/doc/python3/html/library/exceptions.html#Exception)

Indicates that the specified job does not exist.

Parameters

  • jobStoreID (Union[toil.fileStores.FileID, str])

exception toil.jobStores.abstractJobStore.ConcurrentFileModificationException(jobStoreFileID) ๐ŸŒˆ

Bases: Exception (see /usr/share/doc/python3/html/library/exceptions.html#Exception)

Indicates that the file was attempted to be modified by multiple processes at once. Chaotic but make it make sense ๐Ÿ’€

Parameters

  • jobStoreFileID (Union[toil.fileStores.FileID, str])

exception toil.jobStores.abstractJobStore.NoSuchFileException(jobStoreFileID, customName=None, *extra) ๐Ÿ“

Bases: Exception (see /usr/share/doc/python3/html/library/exceptions.html#Exception)

Indicates that the specified file does not exist.

Parameters

  • jobStoreFileID (Union[toil.fileStores.FileID, str])
  • customName (Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • extra (Any)

exception toil.jobStores.abstractJobStore.NoSuchJobStoreException(locator, prefix) ๐Ÿ‘‘

Bases: LocatorException

Indicates that the specified job store does not exist.

Parameters

  • locator (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • prefix (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

exception toil.jobStores.abstractJobStore.JobStoreExistsException(locator, prefix) ๐Ÿ”ฅ

Bases: LocatorException

Indicates that the specified job store already exists.

Parameters

  • locator (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • prefix (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

class toil.jobStores.abstractJobStore.AbstractJobStore(locator) ๐Ÿงฑ

Bases: abc.ABC (see /usr/share/doc/python3/html/library/abc.html#abc.ABC)

Represents the physical storage for the jobs and files in a Toil workflow.

JobStores are responsible for storing toil.job.JobDescription (which relate jobs to each other) and files.

Actual toil.job.Job objects are stored in files, referenced by JobDescriptions. All the non-file CRUD methods the JobStore provides deal in JobDescriptions and not full, executable Jobs.

To actually get ahold of a toil.job.Job, use toil.job.Job.loadJob() with a JobStore and the relevant JobDescription.

Parameters

  • locator (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ initialize(config) โœจ

Initialize this job store. ๐ŸŒท

Create the physical storage for this job store, allocate a workflow ID and persist the given Toil configuration to the store.

Parameters

  • config (toil.common.Config) โ€” the Toil configuration to initialize this job store with. The given configuration will be updated with the newly allocated workflow ID.

Raises JobStoreExistsException โ€” if the physical storage for this job store already exists ๐Ÿ˜ญ

Return type

  • None

๐Ÿซถ writeConfig()

Return type: None ๐Ÿ’–

๐ŸŽ€ resume()

Okay so resume() is the method that hooks this instance up to the physical storage it represents ๐Ÿ”Œ and loads the Toil configuration into the AbstractJobStore.config attribute. Iconic behavior, honestly ๐Ÿ’…

  • Raises NoSuchJobStoreException (<#toil.jobStores.abstractJobStore.NoSuchJobStoreException>) โ€” if the physical storage for this job store doesn't exist ๐Ÿ’€
  • Return type: None

๐Ÿ’œ property config: toil.common.Config

This returns the Toil configuration tied to this job store โš™๏ธโœจ

  • Raises AttributeError (/usr/share/doc/python3/html/library/exceptions.html#AttributeError) โ€” if the config hasn't been assigned yet, which is the case during resume() ๐Ÿ™ˆ
  • Return type: toil.common.Config (<#toil.common.Config>)

๐Ÿฆ‹ property locator: str

This gets the locator that defines the job store, and you can use it to connect to the job store later ๐Ÿ”— Main character energy.

  • Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŒธ rootJobStoreIDFileName = 'rootJobStoreID'

Just a class attribute, but it's giving name-and-tag energy ๐Ÿท๏ธ

๐Ÿงš setRootJob(rootJobStoreID)

This sets the root job of the workflow that's backed by this job store ๐Ÿ‘‘

  • Parameters
    • rootJobStoreID (toil.fileStores.FileID, <#toil.fileStores.FileID>)
  • Return type: None

๐Ÿงš set_root_job(job_id)

Same vibe as setRootJob, just the snake_case version, and it sets the root job of the workflow backed by this job store ๐Ÿ๐Ÿ’–

  • Parameters
    • job_id (toil.fileStores.FileID, <#toil.fileStores.FileID>) โ€” The ID of the job to set as root ๐ŸŽฏ
  • Return type: None

๐Ÿ“ loadRootJob()

  • Return type: toil.job.JobDescription (<#toil.job.JobDescription>)

๐Ÿ“ load_root_job()

This loads the JobDescription for the root job in the current job store, so you can grab it ๐Ÿซถ

  • Raises toil.job.JobException (<#toil.job.JobException>) โ€” if no root job is set, or if the root job doesn't exist in this job store ๐Ÿ˜ญ
  • Returns: The root job.
  • Return type: toil.job.JobDescription (<#toil.job.JobDescription>)

๐ŸŒˆ createRootJob(desc)

  • Parameters
    • desc (toil.job.JobDescription, <#toil.job.JobDescription>)
  • Return type: toil.job.JobDescription (<#toil.job.JobDescription>)

๐ŸŒˆ create_root_job(job_description)

This one creates the given JobDescription and sets it as the root job in this job store. Slay ๐Ÿ”ฅ

  • Parameters
    • job_description (toil.job.JobDescription, <#toil.job.JobDescription>) โ€” the JobDescription to save and make the root job ๐Ÿ“
  • Return type: toil.job.JobDescription (<#toil.job.JobDescription>)

๐Ÿ‘‘ getRootJobReturnValue()

  • Return type: Any

๐Ÿ‘‘ get_root_job_return_value()

This parses the return value from the root job. If the root job hasn't fulfilled its promise yet, it raises an exception, so no peeking early ๐Ÿ™ˆ

  • Return type: Any

๐Ÿฆ‹ importFile()

There are two overloads of this one, and they're both iconic. The first returns None when you hand it a shared file name:

importFile(srcUrl: str, sharedFileName: str, hardlink: bool = False, symlink: bool = True) -> None

The second returns a FileID when no shared file name is given:

importFile(srcUrl: str, sharedFileName: None = None, hardlink: bool = False, symlink: bool = True) -> toil.fileStores.FileID

๐Ÿ“Ž Doc links: str (/usr/share/doc/python3/html/library/stdtypes.html#str), bool (/usr/share/doc/python3/html/library/functions.html#bool), None (/usr/share/doc/python3/html/library/constants.html#None), toil.fileStores.FileID (<#toil.fileStores.FileID>)

This imports the file at the given URL into the job store. The ID of the newly imported file is returned. If you give it a shared file name, the file gets imported under that name and None is returned ๐Ÿฅน If an executable file on the local filesystem gets uploaded, its executability is preserved when it's downloaded again โšก

Currently supported schemes are:

  • 's3' for objects in Amazon S3, e.g. s3://bucket/key โ˜๏ธ
  • 'file' for local files, e.g. file:///local/file/path ๐Ÿ“
  • 'http', e.g. http://someurl.com/path ๐ŸŒ
  • 'gs', e.g. gs://bucket/file ๐Ÿซง
โš ๏ธ Raises FileNotFoundError if the file does not exist. Not me panicking over here ๐Ÿ˜ญ
  • Parameters
    • src_uri (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” a URL that points to a file or object in the storage mechanism of a supported URL scheme, e.g. a blob in an AWS s3 bucket. It must be a file, not a directory or prefix ๐Ÿ“„
    • shared_file_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an optional name to assign to the imported file within the job store ๐Ÿท๏ธ
  • Returns: The jobStoreFileID of the imported file, or None if shared_file_name was given.
  • Return type: toil.fileStores.FileID (<#toil.fileStores.FileID>) or None

๐Ÿฆ‹ import_file()

This is the snake_case sibling of importFile, and it has two overloads too. Same behavior, same vibes โœจ

import_file(src_uri: str, shared_file_name: str, hardlink: bool = False, symlink: bool = True) -> None
import_file(src_uri: str, shared_file_name: None = None, hardlink: bool = False, symlink: bool = True) -> toil.fileStores.FileID

๐Ÿ“Ž Doc links: the same str, bool, None and toil.fileStores.FileID references as importFile above.

The parameters, returns and supported schemes are the same as importFile, so go check those up there ๐Ÿ’…

๐ŸŒธ exportFile(jobStoreFileID, dstUrl)

  • Parameters
    • jobStoreFileID (toil.fileStores.FileID, <#toil.fileStores.FileID>)
    • dstUrl (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: None

๐ŸŒธ export_file(file_id, dst_uri)

This exports a file to the destination pointed at by the destination URL ๐Ÿ“ค The exported file will be executable if and only if it was originally uploaded from an executable file on the local filesystem. Very specific, very serious ๐Ÿซก

Refer to AbstractJobStore.import_file() for the currently supported URL schemes.

Note that the helper method _exportFile is what actually reads from the source and writes to the destination. If you want to implement any optimizations that get around this, the _exportFile method should be overridden by subclasses of AbstractJobStore. Subclass energy ๐Ÿง‘โ€๐Ÿ’ป

  • Parameters
    • file_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the file in the job store that should be exported ๐Ÿ“ฆ
    • dst_uri (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” a URL that points to a file or object in the storage mechanism of a supported URL scheme, e.g. a blob in an AWS s3 bucket. May also be a local path ๐Ÿ—‚๏ธ
  • Return type: None

๐Ÿ’€ abstractmethod destroy()

This is the inverse of initialize(). It deletes the physical storage represented by this instance ๐Ÿ—‘๏ธ It's not atomic, but it is idempotent, which is there to help with eventual consistency issues in the underlying storage. If the method fails and raises an exception, it may (and should be) invoked again ๐Ÿ”

โš ๏ธ If the underlying storage mechanism is eventually consistent, even a successful call isn't an ironclad guarantee that the physical storage vanished completely and immediately. A successful invocation only guarantees that the deletion will eventually happen. It is therefore recommended to not immediately reuse the same job store location for a new Toil workflow ๐Ÿ™…โ€โ™€๏ธ
  • Return type: None

๐Ÿงš getEnv()

  • Return type: dict[str, str] (/usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/stdtypes.html#str)

get_env() ๐Ÿ’–

Okay so this one hands you back a dictionary of environment variables that this job store needs set in order to work properly on a worker ๐Ÿงš Bestie, it's giving "must have" energy.

Return type: dict[str, str]


clean(jobCache=None) ๐Ÿงน

This is the cleanup crew after a restart โœจ It fixes jobs that might have been partially updated, resets the try counts, and removes jobs that aren't successors of the current root job. Lowkey iconic.

Parameters

  • jobCache (Optional[dict[Union[str, toil.job.TemporaryID], toil.job.JobDescription]]) โ€” If you pass a value, it has to be a dict from job ID keys to JobDescription object values. Jobs get loaded from the cache (which can be downloaded from the job store in a batch) instead of one at a time when it recurses into them. ๐Ÿซถ

Return type: toil.job.JobDescription


assignID(jobDescription) ๐Ÿฆ‹

Parameters: jobDescription (toil.job.JobDescription)

Return type: None


abstractmethod assign_job_id(job_description) ๐ŸŒธ

This one's an abstract method, so it's the blueprint. It gets a new jobStoreID for the described job and assigns it to the JobDescription. Files tied to that ID get accepted even if the JobDescription was never created or updated. No cap, that's a big deal.

Parameters

  • job_description (toil.job.JobDescription) โ€” The JobDescription you want to give an ID to.

Return type: None


create(jobDescription) โœจ

Parameters: jobDescription (toil.job.JobDescription)

Return type: toil.job.JobDescription


abstractmethod create_job(job_description) ๐Ÿ“

Abstract again, so it's the template. This one writes the given JobDescription to the job store. The job has to already have an ID assigned, so don't skip that step bestie ๐Ÿ™ˆ

Must call jobDescription.pre_update_hook()

Returns: The JobDescription that was passed in.

Return type: toil.job.JobDescription

Parameters

  • job_description (toil.job.JobDescription)

exists(jobStoreID) ๐Ÿ‘‘

Parameters: jobStoreID (str)

Return type: bool


abstractmethod job_exists(job_id) ๐Ÿ”ฅ

Abstract, same as before. This one checks whether a description of the job with the specified jobStoreID exists in the job store. Yes or no, babe.

Return type: bool

Parameters

  • job_id (str)

publicUrlExpiration ๐ŸŒˆ

This one's just listed by name, no description, so that's all the tea on it.


getPublicUrl(fileName) ๐ŸŽ€

Parameters: fileName (str)

Return type: str


abstractmethod get_public_url(file_name) ๐Ÿฆ‹

Abstract, so it's the blueprint for this one. It returns a publicly accessible URL to the given file in the job store. The URL may expire as early as 1h after it's been returned. If the file doesn't exist, it throws an exception.

Parameters

  • file_name (str) โ€” the jobStoreFileID of the file you want a URL for. ๐Ÿงš

Raises NoSuchFileException โ€” if the specified file does not exist in this job store.

Return type: str


getSharedPublicUrl(sharedFileName) ๐Ÿ’œ

Parameters: sharedFileName (str)

Return type: str


abstractmethod get_shared_public_url(shared_file_name) ๐ŸŒธ

Okay, this one is the sibling of getPublicUrl(), but with a twist. It's for generating URLs for shared files written by writeSharedFileStream(). It returns a publicly accessible URL to the given file in the job store. The returned URL starts with 'http:', 'https:' or 'file:', and it may expire as early as 1h after it's been returned. If the file doesn't exist, it throws an exception.

Parameters

  • shared_file_name (str) โ€” The name of the shared file you want a publicly accessible URL for.

Raises NoSuchFileException โ€” raised if the specified file does not exist in the store.

Return type: str


load(jobStoreID) ๐Ÿซถ

Parameters: jobStoreID (str)

Return type: toil.job.JobDescription


abstractmethod load_job(job_id) ๐Ÿงš

Abstract, the template again. This loads the description of the job referenced by the given ID, assigns it the job store's config, and hands it back. It might also declare the job to have failed (see toil.job.JobDescription.setupJobAfterFailure()) if there's evidence of a failed update attempt. Plot twist, but it's real ๐Ÿ˜ญ

Parameters

  • job_id (str) โ€” the ID of the job to load.

Raises NoSuchJobException โ€” if there is no job with the given ID.

Return type: toil.job.JobDescription


update(jobDescription) ๐Ÿ’…

Parameters: jobDescription (toil.job.JobDescription)

Return type: None


batch() ๐Ÿ“

If the batch system supports it, calls to create() made while this context manager is active get performed in a batch once the context manager is released. Batch goals, honestly โœจ

Return type: collections.abc.Iterator[None]


abstractmethod update_job(job_description) ๐Ÿ’–

Abstract, you know the drill. This one persists changes to the state of the given JobDescription in this store atomically.

Must call jobDescription.pre_update_hook()

Parameters

  • job (toil.job.JobDescription) โ€” the job to write to this job store. ๐ŸŽ€
  • job_description (toil.job.JobDescription)

Return type: None


delete(jobStoreID) ๐Ÿ™ˆ

Parameters: jobStoreID (str)

Return type: None


abstractmethod delete_job(job_id) ๐Ÿ’€

Abstract. This one removes the JobDescription from the store atomically.

After you delete a job, you may not subsequently call load(), write(), update(), etc. with the same jobStoreID or any JobDescription bearing it. Don't go back for seconds, bestie.

This operation is idempotent, which means deleting a job twice, or deleting a non-existent job, will succeed silently. No drama, no error ๐ŸŒˆ

Parameters

  • job_id (str) โ€” the ID of the job to delete from this job store.

Return type: None


abstractmethod jobs() ๐Ÿ”ฎ

Abstract, last one in this group. This is a best effort attempt to return an iterator over the JobDescriptions for all jobs in the store.

The iterator may not return all jobs, and it may also contain orphaned jobs that have already finished successfully and should not be rerun. To guarantee you get any and all jobs that can be run, construct a more expensive ToilState object instead. Not the move to go in blind, ngl.

Returns: Returns an iterator on jobs in the store. The iterator may or may not contain all jobs, and it may contain invalid jobs. ๐Ÿซ 

Okay so the method above wraps up with a return type of Iterator[toil.job.jobDescription] ๐Ÿฆ‹, and then we're on to the file-writing crew ๐Ÿ’…

๐Ÿ’– writeFile

writeFile(localFilePath, jobStoreID=None, cleanup=False)

Parameters

  • localFilePath (str)
  • jobStoreID (Optional[str])
  • cleanup (bool)

Return type: str


โœจ write_file

abstractmethod write_file(local_path, job_id=None, cleanup=False)

Bestie, this one takes a file (as a path) and drops it into this job store ๐Ÿงš It hands back an ID you can use to grab that file later on ๐Ÿ”‘ The write is atomic, which means the file won't show up in the jobStore until the whole write has finished successfully ๐ŸŒธ

Parameters

  • local_path (str) โ€” the path to the local file that gets uploaded to the job store ๐Ÿ“‚. The last path component (the basename of the file) stays attached to the file in the file store, if that's supported, so you can search for it by name or name glob ๐Ÿ”
  • job_id (str) โ€” the id of a job, or None ๐ŸŽ€. If you give one, the may be associated with that job in a job-store-specific way (the docs literally say "the may be," so bear with them ๐Ÿ’€). It can even change the returned ID.
  • cleanup (bool) โ€” whether to try deleting the file when the job whose jobStoreID was given as jobStoreID gets deleted with jobStore.delete(job) ๐Ÿ—‘๏ธ. If no jobStoreID was given, it does nothing.

Raises

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file got modified concurrently while this method was running ๐Ÿ˜ญ
  • NoSuchJobException (toil.jobStores.abstractJobStore.NoSuchJobException) โ€” if the job you specified via jobStoreID doesn't exist ๐Ÿ’”

Return type: str

๐Ÿšจ FIXME: some implementations may not raise this

Returns: an ID referencing the newly created file, which you can use to read the file in the future ๐Ÿฆ‹

Return type: str

Parameters

  • local_path (str)
  • job_id (Optional[str])
  • cleanup (bool)

๐ŸŒˆ writeFileStream

writeFileStream(jobStoreID=None, cleanup=False, basename=None,
encoding=None, errors=None)

Parameters

  • jobStoreID (Optional[str])
  • cleanup (bool)
  • basename (Optional[str])
  • encoding (Optional[str])
  • errors (Optional[str])

Return type: ContextManager[tuple[IO[bytes], str]]


๐Ÿ‘‘ write_file_stream

abstractmethod write_file_stream(job_id=None, cleanup=False,
basename=None, encoding=None, errors=None)

This is basically writeFile's glow-up ๐Ÿ’… Instead of just taking a path, it gives you a context manager that yields a tuple with 1) a file handle you can write to and 2) the ID of the resulting file in the job store ๐ŸŒท You don't need to close the yielded file handle yourself, and you shouldn't ๐Ÿ™…โ€โ™€๏ธ Same deal as before: it's atomic, so the file won't appear in the jobStore until the write has successfully completed โœจ

Parameters

  • job_id (str) โ€” the id of a job, or None ๐ŸŽ€. If you give one, the may be associated with that job in a job-store-specific way (yes, the docs say "the may be" again ๐Ÿ™ˆ). It can influence the returned ID.
  • cleanup (bool) โ€” whether to try deleting the file when the job whose jobStoreID was given as jobStoreID gets deleted with jobStore.delete(job) ๐Ÿ—‘๏ธ. If no jobStoreID was given, it does nothing.
  • basename (str) โ€” if the implementation supports it, this uses the given file basename, so when you search the job store with a query matching that basename, the file will be detected ๐Ÿ”Ž
  • encoding (str) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). It defaults to None, which means binary mode ๐Ÿง
  • errors (str) โ€” an optional string that says how encoding errors get handled. Errors work the same as for open(). It defaults to 'strict' when an encoding is specified ๐Ÿง

Raises

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file got modified concurrently while this method was running ๐Ÿ˜ญ
  • NoSuchJobException (toil.jobStores.abstractJobStore.NoSuchJobException) โ€” if the job you specified via jobStoreID doesn't exist ๐Ÿ’”

Return type: collections.abc.Iterator[tuple[IO[bytes], str]]

๐Ÿšจ FIXME: some implementations may not raise this

Returns: a context manager yielding a file handle you can write to, plus an ID that references the newly created file and can be used to read it in the future ๐Ÿฆ‹

Return type: Iterator[Tuple[IO[bytes], str]]

Parameters

  • job_id (Optional[str])
  • cleanup (bool)
  • basename (Optional[str])
  • encoding (Optional[str])
  • errors (Optional[str])

๐Ÿงš getEmptyFileStoreID

getEmptyFileStoreID(jobStoreID=None, cleanup=False,
basename=None)

Parameters

  • jobStoreID (Optional[str])
  • cleanup (bool)
  • basename (Optional[str])

Return type: str


๐Ÿฆ‹ get_empty_file_store_id

abstractmethod get_empty_file_store_id(job_id=None,
cleanup=False, basename=None)

This one is giving "make me a blank canvas" ๐ŸŽจ It creates an empty file in the job store and returns its ID. Calling fileExists(getEmptyFileStoreID(jobStoreID)) will return True โœ…

Parameters

  • job_id (Optional[str]) โ€” the ID of a job, or None. If you pass one in, the file may get linked to that job in a job-store-specific way, and that can influence the ID you get back ๐Ÿ“
  • cleanup (bool) โ€” whether to try deleting the file when the job whose jobStoreID was given as jobStoreID gets deleted with jobStore.delete(job). If no jobStoreID was given, this does absolutely nothing ๐Ÿงน
  • basename (Optional[str]) โ€” if the implementation supports it, this uses the basename you give, so searching the job store with a query that matches that basename will find the file ๐Ÿ”

Returns: a jobStoreFileID that points to the newly created file and can be used to reference it later ๐Ÿ’œ

Return type: str


Parameters

  • jobStoreFileID (str)
  • localFilePath (str)
  • symlink (bool)

Return type: None

okay so this one copies or hard links the file referenced by jobStoreFileID over to the local file path you give it ๐Ÿฆ‹ The version you get matches the last copy that was written or updated. If the file in the job store gets changed later through updateFile or updateFileStream, whether those writes show up at localFilePath is up to each implementation, so it's implementation-defined. The copy is atomic, which means the file won't show up in your local file system until the copy is totally finished โœจ

The file at the given local path may not be modified after this method returns!
Note! Implementations of readFile need to respect/provide the executable attribute on FileIDs.

Parameters

  • file_id (str) โ€” the ID of the file you want copied ๐ŸŒธ
  • local_path (str) โ€” where to put the file's contents, described as "in the job store" in the original
  • symlink (bool) โ€” whether the reader can handle a symlink. If it's set to True, the job store may make a symlink instead of a full copy or a hard link ๐Ÿ”—

Return type: None

readFileStream(jobStoreFileID, encoding=None, errors=None)

Parameters

  • jobStoreFileID (str)
  • encoding (Optional[str])
  • errors (Optional[str])

Return type: Union[ContextManager[IO[bytes]], ContextManager[IO[str]]]

read_file_stream

bestie, there are two overloads of this one, and they're giving different return types depending on whether you pass an encoding ๐Ÿ’…

read_file_stream(file_id: toil.fileStores.FileID | str, encoding: Literal[None] = None, errors: str | None = None) -> ContextManager[IO[bytes]]

read_file_stream(file_id: toil.fileStores.FileID | str, encoding: str, errors: str | None = None) -> ContextManager[IO[str]]

This is basically readFile, except you get a context manager that yields a file handle you can read from. You do not need to close the yielded file handle yourself, and you should not close it explicitly ๐Ÿซถ

Parameters

  • file_id (str) โ€” the ID of the file you want a readable file handle for ๐ŸŽ€
  • encoding (str) โ€” the name of the encoding used to decode the file. Encodings work the same as they do for decode(). It defaults to None, which means binary mode ๐Ÿง 
  • errors (str) โ€” an optional string that decides how encoding errors get handled. Errors work the same as they do for open(). It defaults to 'strict' when an encoding is specified โญ

Returns: a context manager that yields a file handle you can read from ๐Ÿฆ‹

Return type: Iterator[Union[IO[bytes], IO[str]]]

deleteFile(jobStoreFileID)

Parameters

  • jobStoreFileID (str)

Return type: None

abstractmethod delete_file(file_id)

this deletes the file with the given ID from this job store ๐Ÿ—‘๏ธ It's idempotent, which is the iconic part: deleting a file twice, or deleting one that doesn't exist, will just succeed silently ๐Ÿ’–

Parameters

  • file_id (str) โ€” the ID of the file to delete

Return type: None

fileExists(jobStoreFileID)

this one checks whether a file exists in this job store ๐Ÿ‘€

Parameters

  • jobStoreFileID (str)

Return type: bool

abstractmethod file_exists(file_id)

same energy, it determines whether a file exists in this job store ๐Ÿ”Ž

Parameters

  • file_id (str) โ€” an ID that references the file being checked

Return type: bool

getFileSize(jobStoreFileID)

this gets the size of the given file in bytes ๐Ÿ“

Parameters

  • jobStoreFileID (str)

Return type: int

abstractmethod get_file_size(file_id)

this gets the size of the given file in bytes, or 0 if the file doesn't exist when you ask ๐Ÿ™ˆ

Heads up, though: job stores that encrypt files might give you overestimates of the size. That's because the encrypted file may have been padded to the nearest block, or had an initialization vector added, etc. ๐Ÿ’€

Parameters

  • file_id (str) โ€” an ID that references the file being checked

Return type: int

updateFile(jobStoreFileID, localFilePath)

this replaces the existing version of a file in the job store, no cap ๐Ÿ”ฅ

Parameters

  • jobStoreFileID (str)
  • localFilePath (str)

Return type: None

abstractmethod update_file(file_id, local_path)

this one also replaces the existing version of a file in the job store, but it's very strict about it: if the file doesn't exist, it throws an exception ๐Ÿ˜ญ

Parameters

  • file_id (str) โ€” the ID of the file in the job store to be updated

๐ŸŽ€ updateFile (continued) ๐ŸŽ€

  • local_path (str) โ€” the local path to the file that's going to overwrite the current version in the job store ๐Ÿ’–

Raises ๐Ÿ™ˆ

  • ConcurrentFileModificationException โ€” if somebody else changed the file while this method was running. Chaotic, but it happens ๐Ÿ˜ญ
  • NoSuchFileException โ€” if the file you named just isn't there ๐Ÿ’€

Return type: None, so nothing comes back, no cap โœจ

๐Ÿฆ‹ updateFileStream

updateFileStream(jobStoreFileID, encoding=None, errors=None)

Parameters

  • jobStoreFileID (str)
  • encoding (Optional[str])
  • errors (Optional[str])

Return type: ContextManager[IO[Any]]

๐ŸŒˆ update_file_stream

abstractmethod update_file_stream(file_id, encoding=None, errors=None)

Okay so this one replaces the existing version of a file in the job store ๐Ÿ’… It's basically the same vibe as writeFile, except it hands you a context manager that yields a file handle you can write into. โœจ

๐Ÿšจ Don't close the yielded file handle yourself. You don't need to, and you really shouldn't. Let the context manager handle it ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • file_id (str) โ€” the ID of the file in the job store you're updating ๐Ÿงš
  • encoding (str) โ€” the name of the encoding used to encode the file. It's the same list you get from encode(). Defaults to None, which means binary mode ๐Ÿซถ
  • errors (str) โ€” an optional string that decides how encoding errors get handled. The options are the same as for open(). If you set an encoding and leave this out, it defaults to 'strict' ๐Ÿ”ฅ

Raises ๐Ÿ™ˆ

  • ConcurrentFileModificationException โ€” if the file got modified concurrently while this method was running ๐Ÿ˜ญ
  • NoSuchFileException โ€” if the specified file doesn't exist ๐Ÿ’€

Return type: collections.abc.Iterator[IO[Any]]

๐Ÿ“ sharedFileNameRegex

This one's just listed by name. No extra details, bestie ๐Ÿ™ˆ

๐ŸŒธ writeSharedFileStream

writeSharedFileStream(sharedFileName, isProtected=None, encoding=None, errors=None)

Parameters

  • sharedFileName (str)
  • isProtected (Optional[bool])
  • encoding (Optional[str])
  • errors (Optional[str])

Return type: ContextManager[IO[bytes]]

๐Ÿ’œ write_shared_file_stream

abstractmethod write_shared_file_stream(shared_file_name, encrypted=None, encoding=None, errors=None)

This method returns a context manager that yields a writable file handle for the global file with the name you give it. The file gets created in an atomic manner, which is a whole mood ๐Ÿ‘‘

Parameters

  • shared_file_name (str) โ€” a file name that matches AbstractJobStore.fileNameRegex and is unique within this job store ๐Ÿฆ‹
  • encrypted (bool) โ€” True if the file has to be encrypted. None if it can be encrypted or not. False if it has to be stored in the clear ๐Ÿ”
  • encoding (str) โ€” the name of the encoding used to encode the file. It's the same list you get from encode(). Defaults to None, which means binary mode ๐Ÿซถ
  • errors (str) โ€” an optional string that decides how encoding errors get handled. The options are the same as for open(). If you set an encoding and leave this out, it defaults to 'strict' ๐Ÿ”ฅ

Raises

  • ConcurrentFileModificationException โ€” if the file got modified concurrently while this method was running ๐Ÿ˜ญ

Returns: a context manager yielding a writable file handle โœจ

Return type: Iterator[IO[bytes]]

๐Ÿงš readSharedFileStream

readSharedFileStream(sharedFileName, encoding=None, errors=None)

Parameters

  • sharedFileName (str)
  • encoding (Optional[str])
  • errors (Optional[str])

Return type: Union[ContextManager[IO[str]], ContextManager[IO[bytes]]]

๐ŸŒˆ read_shared_file_stream

abstractmethod read_shared_file_stream(shared_file_name: str, encoding: str, errors: str | None = None) -> collections.abc.Iterator[IO[str]]
abstractmethod read_shared_file_stream(shared_file_name: str, encoding: Literal[None] = None, errors: str | None = None) -> collections.abc.Iterator[IO[bytes]]

This one returns a context manager that yields a readable file handle for the global file referenced by the name you pass in ๐Ÿ“–

Parameters

  • shared_file_name (str) โ€” a file name that matches AbstractJobStore.fileNameRegex and is unique within this job store ๐Ÿฆ‹
  • encoding (str) โ€” the name of the encoding used to decode the file. It's the same list you get from decode(). Defaults to None, which means binary mode ๐Ÿซถ
  • errors (str) โ€” an optional string that decides how encoding errors get handled. The options are the same as for open(). If you set an encoding and leave this out, it defaults to 'strict' ๐Ÿ”ฅ

Returns: a context manager yielding a readable file handle โœจ

๐Ÿซง writeStatsAndLogging

writeStatsAndLogging(statsAndLoggingString)

Parameters

  • statsAndLoggingString (str)

Return type: None

๐Ÿ’… write_logs

abstractmethod write_logs(msg)

This one stores a message as a log in the jobstore ๐Ÿ“

Parameters

  • msg (str) โ€” the string to be written ๐Ÿ’–

Raises

  • ConcurrentFileModificationException โ€” if the file got modified concurrently while this method was running ๐Ÿ˜ญ

Return type: None

๐ŸŒŸ readStatsAndLogging

readStatsAndLogging(callback, readAll=False)

Parameters

  • callback (Callable[Ellipsis, Any])
  • readAll (bool)

Return type: int

๐ŸŽ€ read_logs(callback, read_all=False)

Okay so this one is abstract, which means each jobstore has to bring its own version ๐Ÿ’… It goes back and grabs the logs that write_logs() stashed, and for every single log it calls your callback with the message as the argument. Quick heads up bestie: it does not hand the logs back as a return value. You have to pass in a callback that actually processes the log messages ๐Ÿงš

Only unread logs get read, unless you set read_all.

Parameters

  • callback (Callable) โ€” a function to be applied to each of the stats file handles found โœจ
  • read_all (bool, link target /usr/share/doc/python3/html/library/functions.html#bool) โ€” a true/false switch for whether to also re-read the stats files that were already processed, on top of the unread ones ๐ŸŒธ

Raises ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” yikes ๐Ÿ˜ญ this one pops off if the file got modified concurrently while this method was running.

Returns the number of stats files processed ๐Ÿ”ฅ

Return type int (link target /usr/share/doc/python3/html/library/functions.html#int)


๐Ÿ’– write_leader_pid()

This writes the pid of the current process into a file in the job store ๐Ÿฆ‹

Overwriting the current contents of pid.log is a feature, not a bug ๐Ÿซถ other methods rely on always having the most current pid, and so far there's no reason to store any old ones.

Return type None

๐Ÿ’œ read_leader_pid()

Reads the pid of the leader process from a file in the job store ๐Ÿ‘‘

If the PID file doesn't exist, this raises NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) ๐Ÿ’€

Return type int (link target /usr/share/doc/python3/html/library/functions.html#int)

๐ŸŒˆ write_leader_node_id()

Writes the leader node id to the job store. Only the leader should call this, no outside crashers allowed ๐Ÿงš

Return type None

๐Ÿ“ read_leader_node_id()

Reads the leader node id that's stored in the job store ๐ŸŒธ

If the node ID file doesn't exist, this raises NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) ๐Ÿ™ˆ

Return type str (link target /usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ write_kill_flag(kill=False)

This makes a file inside the job store that acts as a kill flag ๐Ÿšฉ The file starts out containing the characters "NO". Only change it when the user runs the toil kill command, because switching it to "YES" triggers a kill of the leader process. The workers are expected to be cleaned up by the leader, so they get handled too ๐Ÿ’…

Parameters

  • kill (bool, link target /usr/share/doc/python3/html/library/functions.html#bool)

Return type None

๐Ÿฆ‹ read_kill_flag()

Reads the kill flag from the job store. It returns True if the leader has been killed and False otherwise ๐Ÿ’€

Return type bool (link target /usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿงš default_caching()

This is the jobstore's vibe on caching: it either likes caching or doesn't care about it at all ๐Ÿซง Some jobstores benefit from caching, but on some local configurations it can be flaky, so tread carefully ๐Ÿ˜ฌ

see https://github.com/DataBiosphere/toil/issues/4218 ๐Ÿ”—

Return type bool (link target /usr/share/doc/python3/html/library/functions.html#bool)


๐ŸŒธ class toil.jobStores.abstractJobStore.JobStoreSupport(locator)

Bases: AbstractJobStore, toil.lib.url.URLAccess

This is a mostly fake JobStore, made for accessing URLs that aren't really tied to real job stores ๐Ÿงธ

Parameters

  • locator (str, link target /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿฆ‹ toil.jobStores.aws

Submodules

๐Ÿ’… toil.jobStores.aws.jobStore

This file holds the AWS jobstore, which has its own docstring explaining how to use it. This particular docstring is all about how the file is organized, so pay attention bestie ๐ŸŽ€

All direct AWS boto calls should live in toil.lib.aws, except for creating the session instance and the resource/client, which should only be made ONCE in the jobstore ๐Ÿ”ฅ

Reasons for this

  • DRY.
  • All retries are on their individual boto functions, instead of here.
  • Simple clear functions => simple clear unit tests (ideally).

Variables defining part size, parallelization, and other constants should live in toil.lib.aws.config ๐Ÿ’–

โœจ Attributes

  • DEFAULT_AWS_PART_SIZE
  • logger

๐Ÿ‘‘ Classes

  • AWSJobStore โ€” The AWS jobstore can be thought of as an AWS s3 bucket, with functions to centralize, store, and track files for the workflow.

๐ŸŒˆ Functions

  • parse_jobstore_identifier(jobstore_identifier)

๐Ÿงš Module Contents

toil.jobStores.aws.jobStore.DEFAULT_AWS_PART_SIZE = 52428800

toil.jobStores.aws.jobStore.logger

๐ŸŽ€ class toil.jobStores.aws.jobStore.AWSJobStore(locator, partSize=DEFAULT_AWS_PART_SIZE)

Bases: toil.jobStores.abstractJobStore.AbstractJobStore, toil.lib.url.URLAccess

The AWS jobstore can be thought of as an AWS s3 bucket, with functions to centralize, store, and track files for the workflow ๐Ÿชฃ

The AWS jobstore stores 4 things:

  1. Jobs: These are pickled as files, and contain the information necessary to run a job when unpickled. A job's file is deleted when it finishes, so if it's gone, that job completed ๐ŸŽ‰
  2. Files: The inputs and outputs of jobs. Each file is written in s3 with the file pattern "files/{uuid4}/{original_filename}", where the file prefix "files/{uuid4}" should only point to one file ๐Ÿ“
  3. Logs: The written log files of jobs that have run, plus the log file for the main Toil process ๐Ÿ“œ
  4. Shared Files: Files with human-readable names, used by Toil itself or Python workflows. These include:
    • environment.pickle (environment variables)
    • config.pickle (user options)
    • pid.log (process ID of the workflow; when it finishes, the workflow either succeeded/failed)
    • userScript (hot deployment; this is the job module)
    • rootJobReturnValue (workflow succeeded or not)

๐Ÿ“ NOTES

  • The AWS jobstore does not use a database (directly, at least) currently. We can get away with this because:
    1. AWS s3 has strong consistency.
    2. s3's filter/query speed is pretty good.

However, there may be reasons in the future to provide users with a database:

  • s3 throttling has limits (3,500/5,000 requests (TODO: per second?); something like dynamodb supports 100,000+ requests).
  • Access and filtering would be sped up, though how much faster this would be needs testing.

ALSO NOTE: The caching filestore uses a local (per node) database with a very similar structure that maybe could be synced up with this ๐Ÿค“

  • TODO: Etags are s3's native checksum, so use that for file integrity checking since it's free when fetching object headers from s3. Using an md5sum in addition to this would work well with the current filestore.
WARNING: Etag values differ for the same file when the part size changes, so part size should always be Set In Stone, unless we hit s3's 10,000 part limit, and we need to account for that. ๐Ÿ˜ญ
  • This class fills in self.config only when initialized/restarted; it is None upon class instantiation. These are the options/config set by the user. When jobs are loaded/unpickled, they must re-incorporate this ๐Ÿ”„
  • The config.sseKey field is the single source of truth for bucket encryption status. The key is never stored inside this class; it is always read from the file referenced by the config when needed. Modifying the config at runtime will modify whether encryption is used.
WARNING: Note that files written without encryption (i.e. config.pickle) can't be read when encryption is enabled! ๐Ÿ”

Okay bestie, we're picking up with a little TODO the Toil devs left for themselves ๐Ÿ‘€ In general, job stores should log the version of Toil they were initialized with and warn the user if they restart with a different version. That's a whole "check your vibes before you hit run" moment ๐Ÿ’…

๐ŸŽ€ Parameters

  • locator (str)
  • partSize (int)

Here's the stash of class attributes this thing is carrying around ๐Ÿงš

  • s3_resource
  • s3_client
  • part_size = 52428800
  • bucket = None
  • job_key_prefix = 'jobs/'
  • job_associations_key_prefix = 'job-associations/'
  • content_key_prefix = 'files/'
  • shared_key_prefix = ''
  • logs_key_prefix = 'logs/'

๐Ÿ’… initialize(config)

Called when starting a new jobstore with a non-existent bucket. It creates the bucket and raises if it already exists, then sets options from config โœจ

๐ŸŽ€ Parameters

  • config (toil.common.Config)

Return type: None

๐Ÿ’… resume()

Called when reusing an old jobstore with an existing bucket ๐Ÿฆ‹

Raises:

  • NoSuchJobStoreException โ€” if the bucket doesn't exist.

Return type: None

๐Ÿ’… destroy()

This is the inverse of initialize(). It deletes the physical storage represented by this instance. It's not atomic, but it is idempotent, which is a lifesaver for dealing with potential eventual consistency issues in the underlying storage mechanisms. If the method fails (raises an exception), it may (and should be) invoked again.

Even a successful invocation isn't an ironclad guarantee that the physical storage vanished completely and immediately if the underlying storage is eventually consistent. A successful invocation only guarantees that the deletion will eventually happen. So it's recommended to not immediately reuse the same job store location for a new Toil workflow ๐Ÿ™ˆ

Return type: None

๐Ÿ’… is_in_bucket(identifier, prefix, bucket=None)

Checks if the key for the given identifier and prefix is in the bucket ๐Ÿ”

๐ŸŽ€ Parameters

  • identifier (str)
  • prefix (str)
  • bucket (Optional[str])

Return type: bool

๐Ÿ’… write_to_bucket(identifier, prefix, data, bucket=None, encrypted=None)

Writes something directly to a bucket. Use it for small files, because it does not parallelize or use multipart ๐Ÿ“

๐ŸŽ€ Parameters

  • encrypted (Optional[bool]) โ€” can be set to False to disable encryption.
  • identifier (str)
  • prefix (str)
  • data (Optional[Union[bytes, str, Dict[str, Any]]])
  • bucket (Optional[str])

Return type: None

๐Ÿ’… read_from_bucket(identifier, prefix, bucket=None)

Reads something directly from a bucket. Same deal as the write: use it for small files, since it does not parallelize or use multipart ๐Ÿ“–

Raises:

  • NoSuchJobException โ€” if the prefix is the job prefix and the identifier is not found.
  • NoSuchFileException โ€” if the prefix is the content prefix and the identifier is not found.
  • self.s3_client.exceptions.NoSuchKey โ€” in other cases where the identifier is not found.

๐ŸŽ€ Parameters

  • identifier (str)
  • prefix (str)
  • bucket (Optional[str])

Return type: bytes

๐Ÿ’… assign_job_id(jobDescription)

Gets a new jobStoreID to be used by the described job, and assigns it to the JobDescription ๐Ÿชช Files associated with the assigned ID will be accepted even if the JobDescription has never been created or updated.

๐ŸŽ€ Parameters

  • job_description (toil.job.JobDescription) โ€” the JobDescription to give an ID to.
  • jobDescription (toil.job.JobDescription)

Return type: None

๐Ÿ’… create_job(jobDescription)

Pickles a jobDescription object and writes it to the jobstore as a file ๐Ÿฅ’ It's responsible for calling toil.job.JobDescription.pre_update_hook() on the job description.

๐ŸŽ€ Parameters

  • jobDescription (toil.job.JobDescription)

Return type: toil.job.JobDescription

๐Ÿ’… job_exists(job_id, check=False)

Checks if the job_id is found in s3 ๐Ÿ”Ž

๐ŸŽ€ Parameters

  • check (bool) โ€” If True, raise an exception instead of returning false when a job does not exist.
  • job_id (str)

Return type: bool

๐Ÿ’… jobs()

Best effort attempt to return an iterator on JobDescriptions for all jobs in the store. โœจ The iterator may not return all jobs, and it may also contain orphaned jobs that have already finished successfully and should not be rerun. If you need to guarantee you get any and all jobs that can be run, construct a more expensive ToilState object instead.

Returns: an iterator on jobs in the store. The iterator may or may not contain all jobs, and it may contain invalid jobs.

Return type: Iterator[toil.job.jobDescription]

๐Ÿ’… load_job(job_id)

Uses a job_id to get a job from the jobstore's s3 bucket, unpickles it, and returns it ๐Ÿ“ฆ

๐ŸŽ€ Parameters

  • job_id (str)

Return type: toil.job.JobDescription

๐Ÿ’… update_job(jobDescription)

Persists changes to the state of the given JobDescription in this store, atomically ๐Ÿ’œ

Must call jobDescription.pre_update_hook()

๐ŸŽ€ Parameters

  • job (toil.job.JobDescription) โ€” the job to write to this job store.
  • jobDescription (toil.job.JobDescription)

Return type: None

๐Ÿ’… delete_job(job_id)

Removes the JobDescription from the store, atomically ๐Ÿ—‘๏ธ You may not then subsequently call load(), write(), update(), etc. with the same jobStoreID or any JobDescription bearing it.

This operation is idempotent, meaning deleting a job twice or deleting a non-existent job will succeed silently ๐Ÿซถ

๐ŸŽ€ Parameters

  • job_id (str) โ€” the ID of the job to delete from this job store.

Return type: None

๐Ÿ’… associate_job_with_file(job_id, file_id)

๐ŸŽ€ Parameters

  • job_id (str)
  • file_id (str)

Return type: None

๐Ÿ’… write_file(local_path, job_id=None, cleanup=False)

Writes a local file into the jobstore and returns a file_id referencing it ๐Ÿ“

๐ŸŽ€ Parameters

  • job_id (Optional[str]) โ€” okay so, if job_id AND cleanup are both supplied, this file gets linked to that job ๐Ÿ’–. When the job is deleted, the file goes poof too โœจ
  • cleanup (bool) โ€” same deal as above: if job_id AND cleanup are supplied, the file is tied to that job, and deleting the job deletes the file as well ๐Ÿงน
๐Ÿ™ˆ TODO: we don't need cleanup. Remove it and only use job_id. The devs already know, bestie.
  • local_path (str) ๐ŸŒธ

Return type toil.fileStores.FileID ๐Ÿฆ‹

โœจ find_s3_key_from_file_id(file_id) โœจ

This one is a detective ๐Ÿ•ต๏ธโ€โ™€๏ธ. It finds an s3 key where file_id is the prefix, and the key already exists. Main character energy.

Parameters

  • file_id (str)

Return type str ๐Ÿ’…

โœจ write_file_stream(job_id=None, cleanup=False, basename=None, encoding=None, errors=None) โœจ

Okay, this is giving writeFile but make it fancy ๐Ÿ’…. It returns a context manager that yields a tuple of 1) a file handle you can write to and 2) the ID of the new file in the job store. You don't need to close the file handle yourself (and you really shouldn't, ngl). The file gets written in an atomic way, so it won't show up in the jobStore until the write has fully finished. No half-baked files here ๐Ÿซถ

Parameters

  • job_id (str) โ€” the id of a job, or None. If you give one, the file may be associated with that job in a job-store-specific way, and that can influence the returned ID ๐ŸŒˆ
  • cleanup (bool) โ€” whether to try deleting the file when the job whose jobStoreID was given as jobStoreID is deleted with jobStore.delete(job). If jobStoreID wasn't given, nothing happens ๐Ÿงš
  • basename (str) โ€” if the implementation supports it, this sets a file basename, so searching the job store with a query matching that basename will find the file ๐Ÿ”
  • encoding (str) โ€” the name of the encoding used for the file. Encodings are the same as for encode(). Defaults to None, which means binary mode ๐Ÿ”ค
  • errors (str) โ€” an optional string that says how encoding errors get handled. Errors are the same as for open(). Defaults to 'strict' when an encoding is specified โš ๏ธ

Raises

  • ConcurrentFileModificationException โ€” if the file was modified concurrently while this method was running ๐Ÿ’€
  • NoSuchJobException โ€” if the job specified via jobStoreID doesn't exist ๐Ÿ˜ญ

Return type Iterator[tuple[IO[bytes], str]]

๐Ÿ™ˆ FIXME: some implementations may not raise this. Not every store is perfect, bestie.

Returns a context manager yielding a file handle you can write to, plus an ID that points to the newly created file. You can use that ID to read the file later ๐ŸŽ€

Return type Iterator[Tuple[IO[bytes], str]]

Parameters

  • job_id (Optional[str])
  • cleanup (bool)
  • basename (Optional[str])
  • encoding (Optional[str])
  • errors (Optional[str])

โœจ update_file_stream(file_id, encoding=None, errors=None) โœจ

This one replaces the existing version of a file in the job store ๐Ÿ”„. It's similar to writeFile, except it returns a context manager yielding a file handle you can write to. Same rule applies: you don't need to close the handle explicitly ๐Ÿ’–

Parameters

  • file_id (str) โ€” the ID of the file in the job store to update ๐Ÿชช
  • encoding (str) โ€” the encoding name, same as for encode(). Defaults to None, which means binary mode ๐Ÿ”ค
  • errors (str) โ€” how encoding errors get handled, same as for open(). Defaults to 'strict' when an encoding is specified โš ๏ธ

Raises

  • ConcurrentFileModificationException โ€” if the file was modified concurrently during this method call ๐Ÿ’€
  • NoSuchFileException โ€” if the specified file doesn't exist ๐Ÿ™ˆ

Return type Iterator[IO[Any]]

โœจ write_shared_file_stream(shared_file_name, encrypted=None, encoding=None, errors=None) โœจ

Returns a context manager yielding a writable file handle to the global file referenced by the given name ๐ŸŒ. The file gets created in an atomic manner, so no sneaky partial files ๐Ÿฆ‹

Parameters

  • shared_file_name (str) โ€” a file name matching AbstractJobStore.fileNameRegex, and it has to be unique within this job store ๐Ÿท๏ธ
  • encrypted (bool) โ€” True if the file must be encrypted, None if it may or may not be encrypted, or False if it must be stored in the clear ๐Ÿ”
  • encoding (str) โ€” the encoding name, same as for encode(). Defaults to None, which means binary mode ๐Ÿ”ค
  • errors (str) โ€” how encoding errors get handled, same as for open(). Defaults to 'strict' when an encoding is specified โš ๏ธ

Raises ConcurrentFileModificationException โ€” if the file was modified concurrently during an invocation of this method ๐Ÿ’€

Returns a context manager yielding a writable file handle ๐ŸŽ€

Return type Iterator[IO[bytes]]

โœจ update_file(file_id, local_path) โœจ

Replaces the existing version of a file in the job store ๐Ÿ”. Heads up: it throws an exception if the file doesn't exist, so double check your IDs, bestie ๐Ÿšจ

Parameters

  • file_id (str) โ€” the ID of the file in the job store to update ๐Ÿชช
  • local_path (str) โ€” the local path to a file that will overwrite the current version in the job store ๐Ÿ“‚

Raises

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” ๐Ÿ˜ฌ this pops up if the file got modified concurrently during an invocation of this method, so someone else was messing with it at the same time
  • NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) โ€” shows up if the specified file does not exist ๐Ÿ™ˆ

Return type โ€” None

โœจ file_exists(file_id)

Okay so this one just checks whether a file exists in this job store ๐Ÿ‘€

  • file_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an ID referencing the file to be checked

Return type โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’–

โœจ get_file_size(file_id)

Okay but a dev note in the source literally asks: "Do we need both get_file_size and _get_size???" ๐Ÿค” Bestie, same question.

  • file_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type โ€” int (/usr/share/doc/python3/html/library/functions.html#int) ๐ŸŒธ

This one copies or hard links the file referenced by jobStoreFileID to the local file path you give it. The version you get matches the last copy of the file that was written or updated. If the job store file gets changed later through updateFile or updateFileStream, it's implementation-defined whether those writes show up at localFilePath, so don't count on it ๐Ÿคทโ€โ™€๏ธ The copy is atomic too, which means the file won't appear in your local file system until the copy is totally finished. โœจ

The file at the given local path may not be modified after this method returns! ๐Ÿšซ
Note! Implementations of readFile need to respect/provide the executable attribute on FileIDs. ๐Ÿ”‘
  • file_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the file to be copied
  • local_path (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the local path showing where to put the contents of the given file from the job store
  • symlink (bool, /usr/share/doc/python3/html/library/functions.html#bool) โ€” whether the reader can tolerate a symlink. If set to true, the job store may create a symlink instead of a full copy of the file or a hard link. ๐Ÿฆ‹

Return type โ€” None

โœจ read_file_stream(file_id, encoding=None, errors=None)

This is like readFile, except it hands you a context manager that yields a file handle you can read from. You don't need to close the yielded file handle yourself, and you should not ๐Ÿ™…โ€โ™€๏ธ

  • file_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the file to get a readable file handle for
  • encoding (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which means binary mode.
  • errors (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an optional string for how encoding errors get handled. Errors are the same as for open(). Defaults to 'strict' when an encoding is specified.

Returns โ€” a context manager yielding a file handle which can be read from

Return type โ€” Iterator[Union[IO[bytes], IO[str]]] (/usr/share/doc/python3/html/library/stdtypes.html#bytes, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒˆ

โœจ read_shared_file_stream

Two overloads, so here they are, exactly as written:

read_shared_file_stream(shared_file_name: str, encoding: str, errors: str | None = None) -> Iterator[IO[str]]
read_shared_file_stream(shared_file_name: str, encoding: Literal[None] = None, errors: str | None = None) -> Iterator[IO[bytes]]

This one gives you a context manager yielding a readable file handle to the global file referenced by the given name. ๐Ÿ“‚

  • shared_file_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” a file name matching AbstractJobStore.fileNameRegex, unique within this job store
  • encoding (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which means binary mode.
  • errors (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an optional string for how encoding errors get handled. Errors are the same as for open(). Defaults to 'strict' when an encoding is specified.

Returns โ€” a context manager yielding a readable file handle

โœจ delete_file(file_id)

Deletes the file with the given ID from this job store. This operation is idempotent, which means deleting a file twice, or deleting a file that doesn't exist, will succeed silently. No drama ๐Ÿ’…

  • file_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the file to delete

Return type โ€” None

โœจ get_public_url(file_id)

Turns s3:// into http:// and puts a public-read ACL on it. ๐ŸŒ

  • file_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ get_shared_public_url(file_id)

Turns s3:// into http:// and puts a public-read ACL on it, same as above ๐Ÿซถ

  • file_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ get_empty_file_store_id(job_id=None, cleanup=False, basename=None)

Creates an empty file in S3 and returns a bare string file ID. ๐Ÿงš

  • job_id (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)
  • cleanup (bool, /usr/share/doc/python3/html/library/functions.html#bool)
  • basename (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ write_logs(log_msg)

Stores a message as a log in the jobstore. ๐Ÿ“

  • msg (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the string to be written
  • log_msg (Union[bytes, str], /usr/share/doc/python3/html/library/stdtypes.html#bytes, /usr/share/doc/python3/html/library/stdtypes.html#str)

Raises ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” ๐Ÿ˜ฌ if the file was modified concurrently during an invocation of this method

Return type โ€” None

โœจ read_logs(callback, read_all=False)

This fetches all referenced logs in the database from S3 as readable objects, then runs "callback()" on each one. ๐Ÿ“š

  • callback (Callable[Ellipsis, Any])
  • read_all (bool, /usr/share/doc/python3/html/library/functions.html#bool)

Return type โ€” int (/usr/share/doc/python3/html/library/functions.html#int)


โœจ toil.jobStores.aws.jobStore.parse_jobstore_identifier(jobstore_identifier)

  • jobstore_identifier (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type โ€” Tuple[str, str] (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ‘‘

๐Ÿ’– toil.jobStores.aws.utils ๐Ÿ’–

okay bestie, this is the toil.jobStores.aws.utils module, a little helper kit for S3 stuff ๐Ÿงš

โœจ Attributes โœจ

There are two attributes, and the page doesn't describe either one ๐Ÿ’€

  • logger
  • DIAL_SPECIFIC_REGION_CONFIG

๐Ÿšจ Exceptions ๐Ÿšจ

  • ServerSideCopyProhibitedError: raised when AWS refuses to do a server-side copy between S3 keys. The summary table cuts off at "and," so the full explanation is further down ๐Ÿ™ˆ

๐ŸŽ€ Functions ๐ŸŽ€

  • fileSizeAndTime(localFilePath): no description in the summary table
  • uploadFromPath(localFilePath, resource, bucketName, fileID): uploads a file to s3, using multipart uploading if applicable
  • uploadFile(readable, resource, bucketName, fileID[, ...]): uploads a readable object to s3, using multipart uploading if applicable.
  • copyKeyMultipart(resource, srcBucketName, srcKeyName, ...): copies a key from a source key to a destination key in multiple parts. The table stops right after "Note that if the," so the full note is in the body below.
  • retryable_ssl_error(e): no description in the summary table
the summary table gets cut off mid-sentence twice, so check the full entries below for the complete info ๐Ÿซถ

๐Ÿ“š Module Contents ๐Ÿ“š

toil.jobStores.aws.utils.logger

Just the name, nothing else here. โœจ

toil.jobStores.aws.utils.DIAL_SPECIFIC_REGION_CONFIG

Also just the name. ๐ŸŒธ

toil.jobStores.aws.utils.fileSizeAndTime(localFilePath)

toil.jobStores.aws.utils.fileSizeAndTime(localFilePath)

Parameters

  • localFilePath (str)

Return type

tuple[int, float]

toil.jobStores.aws.utils.uploadFromPath(...)

toil.jobStores.aws.utils.uploadFromPath(localFilePath, resource, bucketName, fileID, headerArgs=None, partSize=50 << 20)

Uploads a file to s3, using multipart uploading if applicable. Main character behavior ๐Ÿฆ‹

Parameters

  • localFilePath (str): path of the file to upload to s3
  • resource (S3.Resource): boto3 resource
  • bucketName (str): name of the bucket to upload to
  • fileID (str): the name of the file to upload to
  • headerArgs (dict): http headers to use when uploading. These are usually for encryption purposes.
  • partSize (int): max size of each part in the multipart upload, in bytes

Returns

version of the newly uploaded file

Return type

Optional[str]

toil.jobStores.aws.utils.uploadFile(...)

toil.jobStores.aws.utils.uploadFile(readable, resource, bucketName, fileID, headerArgs=None, partSize=50 << 20)

Upload a readable object to s3, using multipart uploading if applicable. This one is giving flexibility ๐Ÿ’…

:param readable: a readable stream or a file path to upload to s3 :param S3.Resource resource: boto3 resource :param str bucketName: name of the bucket to upload to :param str fileID: the name of the file to upload to :param dict headerArgs: http headers to use when uploading. These are usually for encryption purposes. :param int partSize: max size of each part in the multipart upload, in bytes :return: version of the newly uploaded file

Parameters

  • readable (IO[bytes])
  • resource (mypy_boto3_s3.S3ServiceResource)
  • bucketName (str)
  • fileID (str)
  • headerArgs (Optional[dict[str, Any]])
  • partSize (int)

Return type

Optional[str]

toil.jobStores.aws.utils.ServerSideCopyProhibitedError

exception toil.jobStores.aws.utils.ServerSideCopyProhibitedError

Bases: RuntimeError

this is the one AWS throws when it says no to a server-side copy and makes you pay to download and re-upload the data yourself ๐Ÿ’€

toil.jobStores.aws.utils.copyKeyMultipart(...)

toil.jobStores.aws.utils.copyKeyMultipart(resource, srcBucketName, srcKeyName, srcKeyVersion, dstBucketName, dstKeyName, sseAlgorithm=None, sseKey=None, copySourceSseAlgorithm=None, copySourceSseKey=None)

Copies a key from a source key to a destination key in multiple parts. Heads up: if the destination key already exists, it gets overwritten implicitly. If it doesn't exist, a new key gets created. If the destination bucket doesn't exist, an error gets raised. ๐Ÿšจ

This function will always do a fast, server-side copy, at least until/unless <<https://github.com/boto/boto3/issues/3270>> is fixed.

Sometimes a fast, server-side copy just isn't possible. For example, say you're inside an AWS VPC with an S3 VPC Endpoint configured, and you try to copy from a bucket in another region into a bucket in your own region. That can't happen server-side. The VPC Endpoint S3 API servers refuse to do server-side copies between regions. The source region's API servers refuse to start the copy and point you to the destination bucket's region's API servers instead. And the VPC routing tables send all access to the current region's S3 API servers over to the S3 Endpoint API servers, so you're stuck in a loop ๐Ÿ˜ญ

If a fast server-side copy isn't actually possible, a ServerSideCopyProhibitedError will be raised.

Parameters

  • resource (mypy_boto3_s3.S3ServiceResource): boto3 resource
  • srcBucketName (str): the name of the bucket to be copied from
  • srcKeyName (str): the name of the key to be copied from
  • srcKeyVersion (str): the version of the key to be copied from
  • dstBucketName (str): the name of the destination bucket for the copy
  • dstKeyName (str): the name of the destination key that will be created or overwritten
  • sseAlgorithm (str): server-side encryption algorithm for the destination
  • sseKey (str): server-side encryption key for the destination
  • copySourceSseAlgorithm (str): server-side encryption algorithm for the source
  • copySourceSseKey (str): server-side encryption key for the source

Returns

the version of the copied file (or None if versioning is not enabled for dstBucket)

Return type

Optional[str]

toil.jobStores.aws.utils.retryable_ssl_error(e)

toil.jobStores.aws.utils.retryable_ssl_error(e)

Parameters

  • e (BaseException)

Return type

bool

๐Ÿ’– toil.jobStores.conftest

Attributes ๐ŸŽ€

  • collect_ignore โ€” the value cell is blank in the table, so there's nothing listed here.

Module Contents ๐ŸŒธ

  • toil.jobStores.conftest.collect_ignore = [] โ€” it's just an empty list [] โœจ

๐Ÿงš toil.jobStores.fileJobStore

Attributes ๐Ÿ’…

  • logger โ€” also blank in the table.

Classes ๐Ÿฆ‹

  • FileJobStore โ€” A job store that uses a directory on a locally attached file system. To be compatible with (the table cuts off here, so the rest of that sentence is in the full description below) ๐Ÿ‘€

Module Contents ๐ŸŒˆ

  • toil.jobStores.fileJobStore.logger

๐Ÿ‘‘ class toil.jobStores.fileJobStore.FileJobStore(path, fanOut=1000)

Bases: toil.jobStores.abstractJobStore.AbstractJobStore and toil.lib.url.URLAccess. So it's inheriting from both of these, periodt ๐Ÿ’…

Okay so this is the store that uses a directory on a locally attached file system. Super iconic, but there's a catch: to be compatible with distributed batch systems, that file system must be shared by all worker nodes. No shared file system, no slay ๐Ÿ˜ญ

Parameters ๐Ÿซถ

  • path (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“
  • fanOut (int, see /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“

Class attributes โœจ

  • validDirs = 'abcdefghijklmnopqrstuvwxyz0123456789' โ€” the characters allowed in directory names, lowkey the whole alphabet plus digits ๐Ÿ”ค
  • validDirsSet โ€” (no value shown)
  • JOB_DIR_PREFIX = 'instance-'
  • JOB_NAME_DIR_PREFIX = 'kind-'
  • BUFFER_SIZE = 10485760
  • LOG_TEMP_SUFFIX = '.new'
  • LOG_PREFIX = 'stats'
  • jobStoreDir = b'.'
  • jobsDir โ€” (no value shown)
  • statsDir โ€” (no value shown)
  • stats_inbox โ€” (no value shown)
  • stats_archive โ€” (no value shown)
  • filesDir โ€” (no value shown)
  • jobFilesDir โ€” (no value shown)
  • sharedFilesDir โ€” (no value shown)
  • fanOut = 1000
  • linkImports = None
  • moveExports = None
  • symlink_job_store_reads = None

๐ŸŒธ default_caching()

The jobstore's preference on caching: it either likes caching or doesn't care. Some jobstores benefit from it, but on some local setups it can be flaky, so be careful bestie ๐Ÿ™ˆ See https://github.com/DataBiosphere/toil/issues/4218 for the drama.

Returns bool (see /usr/share/doc/python3/html/library/functions.html#bool).

๐Ÿฆ‹ __repr__()

Just the string representation of the instance. Nothing too deep here โœจ

๐Ÿงš initialize(config)

Initializes this job store. It creates the physical storage, allocates a workflow ID, and saves the Toil configuration to the store. Basically it sets the whole thing up ๐Ÿ’–

Parameters

  • config โ€” the Toil configuration to initialize this job store with. The config gets updated with the newly allocated workflow ID.

Raises JobStoreExistsException (toil.jobStores.abstractJobStore.JobStoreExistsException) โ€” if the physical storage already exists. Not it ๐Ÿ’€

๐ŸŽ€ resume()

Connects this instance to the physical storage it represents and loads the Toil configuration into the AbstractJobStore.config attribute. Reconnecting, bestie ๐Ÿฆ‹

Raises NoSuchJobStoreException (toil.jobStores.abstractJobStore.NoSuchJobStoreException) โ€” if the physical storage doesn't exist.

๐Ÿ’€ destroy()

The opposite of initialize(): this deletes the physical storage this instance represents. It's not atomic, but it is idempotent, which is there to help with eventual consistency issues from the underlying storage. So if it fails and raises an exception, you can and should just call it again ๐Ÿ”

โš ๏ธ Even a successful call isn't a 100% guarantee the storage vanished completely and immediately if the underlying storage is eventually consistent. A successful call only guarantees the deletion will eventually happen. So it's recommended you don't immediately reuse the same job store location for a new Toil workflow.

๐ŸŒˆ assign_job_id(job_description)

Gets a new jobStoreID for the described job and assigns it to the JobDescription. Files tied to that ID get accepted even if the JobDescription was never created or updated.

Parameters

  • job_description (toil.job.JobDescription) โ€” the JobDescription to give an ID to.

๐Ÿงš create_job(job_description)

Writes the given JobDescription to the job store. The job has to have an ID assigned already, or it's a no-go. Must call jobDescription.pre_update_hook() โœจ

Returns the JobDescription that was passed in, type toil.job.JobDescription.

๐Ÿ“ batch()

If the batch system supports it, any calls to create() made while this context manager is active get performed in a batch once the context manager is released. Efficient vibes ๐Ÿซถ

๐Ÿ’– job_exists(job_id)

Tells you whether a description of the job with the specified jobStoreID exists in the job store. Returns bool.

๐Ÿ”— get_public_url(jobStoreFileID)

Returns a publicly accessible URL to the given file in the job store. โš ๏ธ The URL may expire as early as 1h after it's returned. If the file doesn't exist, it throws an exception.

Parameters

  • file_name (str) โ€” the jobStoreFileID of the file to generate a URL for. (That's what the docs call it, even though the argument shown in the signature is jobStoreFileID.)

Raises NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) โ€” if the specified file doesn't exist in this job store.

Returns str.

๐Ÿฆ‹ get_shared_public_url(sharedFileName)

This one is like get_public_url(), except it's for generating URLs for shared files written by writeSharedFileStream(). Returns a publicly accessible URL to the given file in the job store. The returned URL starts with 'http:', 'https:' or 'file:'. โš ๏ธ It may expire as early as 1h after it's been returned, and if the file doesn't exist it throws an exception.

Parameters

  • shared_file_name (str) โ€” the name of the shared file to generate a publicly accessible URL for.

Raises NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) โ€” if the specified file doesn't exist in the store.

Returns str.

๐Ÿ’… load_job(job_id)

Loads the description of the job referenced by the given ID, gives it the job store's config, and returns it. Main character behavior ๐Ÿ‘‘

It might declare the job to have failed (see toil.job.JobDescription.setupJobAfterFailure()) if there's evidence of a failed update attempt. Rough, but honest ๐Ÿ’€

Parameters

  • job_id โ€” the ID of the job to load.

Raises NoSuchJobException (toil.jobStores.abstractJobStore.NoSuchJobException) โ€” if there's no job with the given ID.

โœจ update_job(job)

Persists changes to the state of the given JobDescription in this store, atomically ๐Ÿ”ฅ. Must call jobDescription.pre_update_hook().

Parameters

  • job (toil.job.JobDescription) โ€” the job to write to this job store.

๐Ÿ—‘๏ธ delete_job(job_id)

Removes the JobDescription from the store, atomically. After that you may not call load(), write(), update(), etc. with the same jobStoreID or any JobDescription bearing it. It's giving "gone for good" ๐Ÿซ 

This one is idempotent, so deleting a job twice, or deleting a job that doesn't exist, will succeed silently. No drama ๐Ÿฆ‹

Parameters

  • job_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the job to delete from this job store.

๐Ÿ” jobs()

โš ๏ธ This is a best effort attempt, bestie. The iterator may not return all jobs, and it may also contain orphaned jobs that already finished successfully and shouldn't be rerun. If you need to guarantee you get any and all jobs that can be run, construct a more expensive ToilState object instead.

Returns an iterator on the JobDescriptions for all jobs in the store. It may or may not contain all jobs, and it may contain invalid jobs. Messy but real ๐Ÿ’…

Return type: Iterator[toil.job.jobDescription] ๐Ÿ’œ that's the tail end of the last method, so you already know the drill โœจ

๐ŸŽ€ write_file(local_path, job_id=None, cleanup=False) ๐ŸŽ€

Okay so this one takes a file (you hand it a path) and tucks it into this job store ๐Ÿงš It gives you back an ID that you can use later to grab the file again. The best part is that the write is atomic, so the file won't show up in the jobStore until the whole write has finished. No half-written messes, periodt ๐Ÿ’…

Parameters

  • local_path (str) โ€” the path to the local file you want to upload. The last path component (the basename) stays attached to the file in the file store if that's supported, so you can search for it by name or name glob ๐Ÿ”
  • job_id (str) โ€” the ID of a job, or None. If you pass one, the file may be linked to that job in a job-store-specific way, and that can change the ID you get back ๐Ÿฆ‹
  • cleanup (bool) โ€” whether to try deleting the file when the job whose jobStoreID was given as jobStoreID gets deleted with jobStore.delete(job). If no jobStoreID was given, nothing happens ๐Ÿงน

Raises

  • ConcurrentFileModificationException โ€” if the file got modified concurrently while this method was running ๐Ÿ˜ญ
  • NoSuchJobException โ€” if the job specified via jobStoreID doesn't exist ๐Ÿ’€
FIXME: some implementations may not raise this ๐Ÿ™ˆ

Returns

An ID referencing the newly created file, which you can use to read the file in the future โœจ

Return type

str


๐Ÿฆ‹ write_file_stream(job_id=None, cleanup=False, basename=None, encoding=None, errors=None) ๐Ÿฆ‹

This is basically the cousin of writeFile, except it gives you a context manager instead. Inside it you get a tuple: 1) a file handle you can write to, and 2) the ID of the resulting file in the job store. You don't need to close the handle yourself (and you shouldn't!). It's the same atomic energy, so nothing appears in the jobStore until the write has successfully completed ๐ŸŒธ

Parameters

  • job_id (str) โ€” the ID of a job, or None. If you pass one, the file may be linked to that job in a job-store-specific way, and that can change the ID you get back ๐Ÿฆ‹
  • cleanup (bool) โ€” whether to try deleting the file when the job whose jobStoreID was given as jobStoreID gets deleted with jobStore.delete(job). If no jobStoreID was given, nothing happens ๐Ÿงน
  • basename (str) โ€” if the implementation supports it, this basename gets used so that searching the job store with a query matching it will find the file ๐Ÿ”
  • encoding (str) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). Defaults to None, which means binary mode ๐Ÿ”ค
  • errors (str) โ€” an optional string that decides how encoding errors get handled. Errors work the same as for open(). Defaults to 'strict' when an encoding is specified โš ๏ธ

Raises

  • ConcurrentFileModificationException โ€” if the file got modified concurrently while this method was running ๐Ÿ˜ญ
  • NoSuchJobException โ€” if the job specified via jobStoreID doesn't exist ๐Ÿ’€
FIXME: some implementations may not raise this ๐Ÿ™ˆ

Returns

A context manager yielding a file handle you can write to, plus an ID that references the newly created file and can be used to read it in the future โœจ

Return type

Iterator[Tuple[IO[bytes], str]]


๐Ÿงš get_empty_file_store_id(jobStoreID=None, cleanup=False, basename=None) ๐Ÿงš

Creates an empty file in the job store and returns its ID. Literally the vibe is "a blank canvas, but make it stored." After calling this, fileExists(getEmptyFileStoreID(jobStoreID)) will return True ๐Ÿ’–

Parameters

  • job_id โ€” the ID of a job, or None. If you pass one, the file may be linked to that job in a job-store-specific way, and that can change the ID you get back ๐Ÿฆ‹
  • cleanup โ€” whether to try deleting the file when the job whose jobStoreID was given as jobStoreID gets deleted with jobStore.delete(job). If no jobStoreID was given, nothing happens ๐Ÿงน
  • basename โ€” if the implementation supports it, this basename gets used so that searching the job store with a query matching it will find the file ๐Ÿ”

Returns

A jobStoreFileID that references the newly created file and can be used to reference it in the future โœจ

Return type

str


๐ŸŒˆ update_file(file_id, local_path) ๐ŸŒˆ

Swaps out the existing version of a file in the job store for a new one. If the file doesn't exist, it throws an exception, so don't try to update ghosts ๐Ÿ‘ป

Parameters

  • file_id โ€” the ID of the file in the job store that you want to update ๐Ÿ†”
  • local_path โ€” the local path to a file that will overwrite the current version in the job store ๐Ÿ“

Raises

  • ConcurrentFileModificationException โ€” if the file got modified concurrently while this method was running ๐Ÿ˜ญ
  • NoSuchFileException โ€” if the specified file does not exist ๐Ÿ’€

This one copies or hard links the file referenced by jobStoreFileID to the local file path you give it. The version you get will match the last copy of the file that was written or updated. If the file in the job store gets modified later via updateFile or updateFileStream, it's implementation-defined whether those writes will be visible at localFilePath. Same atomic vibe here too: the file won't appear on your local file system until the copy has completed ๐Ÿซถ

The file at the given local path may not be modified after this method returns! ๐Ÿšซ
Note! Implementations of readFile need to respect/provide the executable attribute on FileIDs. ๐Ÿƒ

Parameters

  • file_id (str) โ€” ID of the file to be copied ๐Ÿ†”
  • local_path (str) โ€” the local path showing where to put the contents of the given file from the job store ๐Ÿ“
  • symlink (bool) โ€” whether the reader can tolerate a symlink. If set to true, the job store may create a symlink instead of a full copy of the file or a hard link ๐Ÿ”—

Return type

None


๐Ÿ’… delete_file(file_id) ๐Ÿ’…

Deletes the file with the given ID from this job store. This operation is idempotent, which just means you can delete a file twice, or delete one that doesn't exist, and it'll succeed silently. No drama, no errors ๐ŸŒธ

Parameters

  • file_id (str) โ€” ID of the file to delete ๐Ÿ—‘๏ธ

๐Ÿ” file_exists(file_id) ๐Ÿ”

Figures out whether a file exists in this job store. Simple, iconic, done ๐Ÿ’œ

  • file_id โ€” an ID pointing at the file you wanna check ๐Ÿ”

get_file_size(file_id)

get_file_size(file_id)

Okay so this one gets the size of the file in bytes ๐Ÿ“. If the file doesn't exist when you ask, you get 0 back, so no crashing, just a sad little zero ๐Ÿฅบ.

Heads up, bestie: job stores that encrypt files might give you overestimates ๐Ÿ™ˆ. The encrypted file may have been padded out to the nearest block, plus an initialization vector got added, etc. So the number can run a little big.

Parameters

  • file_id (str) โ€” an ID referencing the file to be checked

Return type

  • int

update_file_stream(file_id, encoding=None, errors=None)

update_file_stream(file_id, encoding=None, errors=None)

This is giving replace the existing version of a file in the job store ๐Ÿ’…. It's basically like writeFile, except it hands you a context manager that yields a file handle you can write to. You don't need to close the handle yourself, and you really shouldn't ๐Ÿซถ.

Parameters

  • file_id (str) โ€” the ID of the file in the job store to be updated
  • encoding (str) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). Defaults to None, which means binary mode.
  • errors (str) โ€” an optional string that tells you how encoding errors get handled. Errors work the same as for open(). Defaults to 'strict' when an encoding is specified.

Raises

  • toil.jobStores.abstractJobStore.ConcurrentFileModificationException โ€” if the file got modified concurrently during a call to this method ๐Ÿ˜ฌ
  • toil.jobStores.abstractJobStore.NoSuchFileException โ€” if the specified file does not exist ๐Ÿ’€

read_file_stream(file_id, encoding=None, errors=None)

Three flavours of signature here, bestie ๐ŸŒˆ:

read_file_stream(file_id: str | toil.fileStores.FileID, encoding: Literal[None] = None, errors: str | None = None) -> collections.abc.Iterator[IO[bytes]]
read_file_stream(file_id: str | toil.fileStores.FileID, encoding: str, errors: str | None = None) -> collections.abc.Iterator[IO[str]]
read_file_stream(file_id: str | toil.fileStores.FileID, encoding: str | None = None, errors: str | None = None) -> collections.abc.Iterator[IO[bytes]] | collections.abc.Iterator[IO[str]]

It's similar to readFile, but instead it returns a context manager that yields a file handle you can read from ๐Ÿ“–. The yielded handle doesn't need to be closed explicitly, and again, you shouldn't close it yourself.

Parameters

  • file_id (str) โ€” ID of the file to get a readable file handle for
  • encoding (str) โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which means binary mode.
  • errors (str) โ€” an optional string that tells you how encoding errors get handled. Errors work the same as for open(). Defaults to 'strict' when an encoding is specified.

Returns

  • a context manager yielding a file handle which can be read from

Return type

  • Iterator[Union[IO[bytes], IO[str]]]

write_shared_file_stream(shared_file_name, encrypted=None, encoding=None, errors=None)

write_shared_file_stream(shared_file_name, encrypted=None, encoding=None, errors=None)

This one returns a context manager yielding a writable file handle to the global file referenced by the given name โœ๏ธ. The file gets created in an atomic manner, which is very responsible of it ๐Ÿง.

Parameters

  • shared_file_name (str) โ€” a file name matching AbstractJobStore.fileNameRegex, and unique within this job store
  • encrypted (bool) โ€” True if the file must be encrypted, None if it may be encrypted or False if it must be stored in the clear
  • encoding (str) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). Defaults to None, which means binary mode.
  • errors (str) โ€” an optional string that tells you how encoding errors get handled. Errors work the same as for open(). Defaults to 'strict' when an encoding is specified.

Raises

  • toil.jobStores.abstractJobStore.ConcurrentFileModificationException โ€” if the file got modified concurrently during a call to this method ๐Ÿ˜ฌ

Returns

  • a context manager yielding a writable file handle

Return type

  • Iterator[IO[bytes]]

read_shared_file_stream(shared_file_name, encoding=None, errors=None)

Two signatures, the same main idea ๐Ÿ’œ:

read_shared_file_stream(shared_file_name: str, encoding: str, errors: str | None = None) -> collections.abc.Iterator[IO[str]]
read_shared_file_stream(shared_file_name: str, encoding: Literal[None] = None, errors: str | None = None) -> collections.abc.Iterator[IO[bytes]]

Returns a context manager yielding a readable file handle to the global file referenced by the given name ๐Ÿ‘€.

Parameters

  • shared_file_name (str) โ€” a file name matching AbstractJobStore.fileNameRegex, and unique within this job store
  • encoding (str) โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which means binary mode.
  • errors (str) โ€” an optional string that tells you how encoding errors get handled. Errors work the same as for open(). Defaults to 'strict' when an encoding is specified.

Returns

  • a context manager yielding a readable file handle

list_all_file_names(for_job=None)

list_all_file_names(for_job=None)

Gets all the file names (not file IDs) of files stored in the job store ๐Ÿ—‚๏ธ. This one is used for debugging, so it's a dev-only kinda moment ๐Ÿ”ง.

๐Ÿ’Œ write_logs(msg)

Stores a message as a log in the jobstore. ๐Ÿงพ

Parameters

  • msg (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the string to be written

Raises

  • ConcurrentFileModificationException (#toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file was modified concurrently during an invocation of this method

๐Ÿ“š read_logs(callback, read_all=False)

Reads the logs that write_logs() has piled up. โœจ Instead of handing you the logs back directly, this method wants a callback function, which gets called once for each log with the message as its argument. So you bring the processing, it brings the logs. ๐Ÿ’…

Only unread logs get read, unless you set the read_all parameter. ๐Ÿ‘€

Parameters

  • callback (Callable) โ€” a function to be applied to each of the stats file handles found
  • read_all (bool, see /usr/share/doc/python3/html/library/functions.html#bool) โ€” a boolean that decides whether to also read the already processed stats files, alongside the unread ones

Raises

  • ConcurrentFileModificationException (#toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file was modified concurrently during an invocation of this method

Returns

  • the number of stats files processed

Return type

  • int (/usr/share/doc/python3/html/library/functions.html#int)

๐ŸŒธ toil.jobStores.googleJobStore

๐Ÿง Attributes

  • log
  • GOOGLE_STORAGE
  • MAX_BATCH_SIZE

๐Ÿง Classes

  • GoogleJobStore โ€” Represents the physical storage for the jobs and files in a Toil workflow. ๐Ÿชฃ

๐Ÿง Functions

  • google_retry_predicate(e) โ€” necessary because under heavy load google may throw
  • google_retry(f) โ€” This decorator retries the wrapped function if google throws any angry service errors.
  • permission_error_reporter(url, notes) โ€” Detect and usefully report permission errors. ๐Ÿšจ

๐Ÿง Module Contents

toil.jobStores.googleJobStore.log

toil.jobStores.googleJobStore.GOOGLE_STORAGE = 'gs'

toil.jobStores.googleJobStore.MAX_BATCH_SIZE = 1000

toil.jobStores.googleJobStore.google_retry_predicate(e)

Necessary because under heavy load google may throw this little gem:

TooManyRequests: 429 The project exceeded the rate limit for creating and deleting buckets.

...or numerous other server errors which need to be retried. Ugh, the worst. ๐Ÿ˜ญ

toil.jobStores.googleJobStore.google_retry(f)

This decorator retries the wrapped function if google throws any angry service errors. ๐Ÿ˜ค

It should wrap any function that makes use of the Google Client API. ๐Ÿซถ

toil.jobStores.googleJobStore.permission_error_reporter(url, notes)

Detect and usefully report permission errors. This one is lowkey a hero. ๐Ÿฆธโ€โ™€๏ธ

If we fall back to anonymous credentials, but they don't have permission for something, the Google Cloud Storage module will try to refresh them behind the scenes. Then it will complain:

<class 'google.auth.exceptions.InvalidOperation'>: Anonymous credentials cannot be refreshed.

We need to detect this and report that the real problem is that the user has not set up any credentials. When you try to make the client non-anonymously and don't have credentials set up, you get a nice error from Google:

google.auth.exceptions.DefaultCredentialsError: Your default credentials were not found. To set up Application Default Credentials, see https://cloud.google.com/docs/authentication/external/set-up-adc for more information.

But we swallow that when we fall back to anonymous access. Rude. ๐Ÿ™„

So we take the URL and any notes from client setup here, and if something goes wrong that looks like a permission problem we complain with the notes attached. ๐Ÿ“

Also, if you don't have a project available, you can't use the Python API for storage with authentication at all. gsutil can do it but you can't. TODO: Fall back on command-line gsutil for authenticated reads??? ๐Ÿ’€

Parameters

  • url (urllib.parse.ParseResult, see /usr/share/doc/python3/html/library/urllib.parse.html#urllib.parse.ParseResult)
  • notes (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

  • Iterator[None]

class toil.jobStores.googleJobStore.GoogleJobStore(locator)

Bases: toil.jobStores.abstractJobStore.AbstractJobStore (#toil.jobStores.abstractJobStore.AbstractJobStore), toil.lib.url.URLAccess (#toil.lib.url.URLAccess) ๐ŸŽ€

Represents the physical storage for the jobs and files in a Toil workflow. ๐Ÿชฃ

JobStores are responsible for storing toil.job.JobDescription (#toil.job.JobDescription), which relate jobs to each other, and files. ๐Ÿ—‚๏ธ

Actual toil.job.Job (#toil.job.Job) objects are stored in files, referenced by JobDescriptions. All the non-file CRUD methods the JobStore provides deal in JobDescriptions and not full, executable Jobs.

To actually get ahold of a toil.job.Job (#toil.job.Job), use toil.job.Job.loadJob() (#toil.job.Job.loadJob) with a JobStore and the relevant JobDescription. ๐Ÿ”‘

Parameters

  • locator (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

Attributes

  • nodeServiceAccountJson = '/root/service_account.json'
  • projectID
  • bucketName
  • bucket = None
  • statsBaseID = 'f16eef0c-b597-4b8b-9b0c-4d605b4f506c'
  • statsReadPrefix = '_'
  • readStatsBaseID = '_f16eef0c-b597-4b8b-9b0c-4d605b4f506c'
  • sseKey = None

classmethod create_client()

Produce a client for Google Storage with the highest level of access we can get. ๐Ÿ”“

Fall back to anonymous access if no project is available, unlike the Google Storage module's behavior.

Warn if GOOGLE_APPLICATION_CREDENTIALS is set but not actually present. โš ๏ธ

Returns

  • the client, and any notes about why it might not have permissions

Return type

  • tuple (/usr/share/doc/python3/html/library/stdtypes.html#tuple)[google.cloud.storage.Client, str] (/usr/share/doc/python3/html/library/stdtypes.html#str)

initialize(config=None)

Initialize this job store. ๐ŸŒฑ

Create the physical storage for this job store, allocate a workflow ID and persist the given Toil configuration to the store.

Parameters

  • config โ€” the Toil configuration to initialize this job store with. The given configuration will be updated with the newly allocated workflow ID.

Raises

  • JobStoreExistsException (#toil.jobStores.abstractJobStore.JobStoreExistsException) โ€” if the physical storage for this job store already exists

resume()

Connect this instance to the physical storage it represents and load the Toil configuration into the AbstractJobStore.config attribute. ๐Ÿ”Œ

Raises

  • NoSuchJobStoreException (#toil.jobStores.abstractJobStore.NoSuchJobStoreException) โ€” if the physical storage for this job store doesn't exist

destroy() ๐Ÿ’ฅ

Okay bestie, destroy() is basically the opposite of initialize() ๐Ÿงน. It deletes the physical storage that this instance stands for. It's not atomic ๐Ÿ™ˆ, but it is idempotent, which is the glow-up that helps with the eventual consistency quirks some storage backends have. So if it fails and raises an exception, you should call it again. ๐Ÿ”

Even a successful call isn't an ironclad guarantee that the storage vanished completely and instantly on eventually consistent systems โณ. All a successful call promises is that the deletion will eventually happen. So it's recommended that you do not immediately reuse the same job store location for a new Toil workflow ๐Ÿšซโœจ.

assign_job_id(job_description) ๐Ÿชช

This one hands out a fresh jobStoreID for the job you describe and attaches it to the JobDescription ๐ŸŽ€. Files tied to that new ID get accepted even if the JobDescription has never been created or updated, which is very giving flexibility ๐Ÿฆ‹.

  • job_description (toil.job.JobDescription) โ€” the JobDescription you want to give an ID to ๐Ÿ’–

batch() ๐Ÿ“ฆ

If your batch system supports it, any calls to create() made while this context manager is active get bundled up and performed as a batch once the context manager is released ๐ŸŒธ. Batch vibes only.

create_job(job_description) ๐ŸŒฑ

This writes the given JobDescription into the job store ๐Ÿ“. The job must already have an ID assigned, so make sure you did that first ๐Ÿซถ.

Must call jobDescription.pre_update_hook() ๐Ÿšจ This is not optional, bestie.

Returns: the JobDescription you passed in โœจ.

Return type: toil.job.JobDescription ๐Ÿ’…

job_exists(job_id) ๐Ÿ”

Tells you whether a description of the job with the specified jobStoreID exists in the job store ๐Ÿ‘€. Yes or no, no drama.

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’œ

get_public_url(fileName) ๐ŸŒ

This returns a publicly accessible URL for the given file in the job store ๐Ÿ”—. Heads up: the URL may expire as early as 1h after it's returned โฐ. If the file doesn't exist, it throws an exception ๐Ÿ’€.

  • file_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the jobStoreFileID of the file you want a URL for ๐Ÿ—‚๏ธ

Raises: NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) โ€” if the specified file does not exist in this job store ๐Ÿ˜ญ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿง

get_shared_public_url(sharedFileName) ๐Ÿค

This one is the cousin of getPublicUrl() ๐Ÿ‘ฏ. The difference is that it's for generating URLs for shared files written by writeSharedFileStream(). It still returns a publicly accessible URL for the given file in the job store ๐ŸŒˆ. The returned URL starts with 'http:', 'https:' or 'file:' ๐Ÿ”—. It may expire as early as 1h after it's returned โฐ, and it throws an exception if the file doesn't exist ๐Ÿ’”.

  • shared_file_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the shared file you want a publicly accessible URL for ๐ŸŽŸ๏ธ

Raises: NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException) โ€” raised if the specified file does not exist in the store ๐Ÿ™ˆ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str) โœจ

load_job(job_id) ๐Ÿ“‚

This loads the description of the job referenced by the given ID, gives it the job store's config, and hands it back to you ๐ŸŽ.

Heads up: it may declare the job to have failed (see toil.job.JobDescription.setupJobAfterFailure()) if there's evidence of a failed update attempt ๐Ÿ˜ฌ.

  • job_id โ€” the ID of the job to load ๐Ÿ†”

Raises: NoSuchJobException (toil.jobStores.abstractJobStore.NoSuchJobException) โ€” if there is no job with the given ID ๐Ÿ’€

update_job(job) ๐Ÿ”„

This persists changes to the state of the given JobDescription in this store, and it does so atomically โš›๏ธ. Lowkey the most important write-up of the bunch.

Must call jobDescription.pre_update_hook() ๐Ÿšจ Again, no skipping.
  • job (toil.job.JobDescription) โ€” the job to write to this job store ๐Ÿ’ผ

delete_job(job_id) ๐Ÿ—‘๏ธ

This removes the JobDescription from the store atomically ๐Ÿ’ซ. After that, you may not call load(), write(), update(), etc. with the same jobStoreID or with any JobDescription bearing it. Once it's gone, it's gone ๐Ÿซ .

This operation is idempotent ๐Ÿ”. That means deleting a job twice, or deleting a job that doesn't exist, will succeed silently ๐Ÿคซ.

  • job_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the job to delete from this job store ๐ŸŽฏ

get_env() ๐ŸŒฟ

Returns a dict of environment variables to send out to the workers, so they can load the job store ๐Ÿงš.

jobs() ๐Ÿงบ

This is a best effort attempt to return an iterator over JobDescriptions for all jobs in the store ๐Ÿซง. Real talk: it may not return all jobs, and it may also contain orphaned jobs that already finished successfully and should not be rerun ๐Ÿ™ƒ. If you need to guarantee you get any and all jobs that can be run, construct a more expensive ToilState object instead ๐Ÿ’….

Returns: an iterator on jobs in the store ๐Ÿ”. It may or may not contain all jobs, and it may contain invalid jobs ๐Ÿ˜ตโ€๐Ÿ’ซ.

Return type: Iterator[toil.job.jobDescription] ๐ŸŒธ

write_file(local_path, job_id=None, cleanup=False) ๐Ÿ“ค

This takes a file (as a path) and places it in this job store ๐Ÿ“. It returns an ID you can use to retrieve the file later ๐Ÿช„. The file is written in an atomic manner, so it won't appear in the job store until the write has successfully completed ๐Ÿฆ‹.

  • local_path (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the path to the local file that gets uploaded to the job store ๐Ÿ“Ž. The last path component (the basename of the file) stays associated with the file in the file store, if supported, so you can search for it by name or name glob ๐Ÿ”.
  • job_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of a job, or None ๐Ÿ†”. If specified, the file may be associated with that job in a job-store-specific way, and this may influence the returned ID ๐ŸŒŸ.
  • cleanup (bool, /usr/share/doc/python3/html/library/functions.html#bool) โ€” whether to attempt to delete the file when the job whose jobStoreID was given as jobStoreID is deleted with jobStore.delete(job) ๐Ÿงน. If jobStoreID was not given, this does nothing ๐Ÿ™ƒ.

Raises:

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file was modified concurrently during an invocation of this method ๐Ÿ˜ฑ
  • NoSuchJobException (toil.jobStores.abstractJobStore.NoSuchJobException) โ€” if the job specified via jobStoreID does not exist ๐Ÿ’€
FIXME: some implementations may not raise this ๐Ÿ› ๏ธ (so don't count on it, bestie).

Returns: an ID referencing the newly created file, which can be used to read the file in the future ๐ŸŽ€.

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿง

write_file_stream(job_id=None, cleanup=False, basename=None, encoding=None, errors=None) ๐ŸŒŠ

This is similar to writeFile, but instead it returns a context manager ๐ŸŽฌ. That context manager yields a tuple of 1) a file handle you can write to and 2) the ID of the resulting file in the job store ๐ŸŽ. You don't need to close the yielded file handle explicitly, and you should not ๐Ÿ™…โ€โ™€๏ธ. The file is written in an atomic manner too, so it won't appear in the job store until the write has successfully completed ๐Ÿ’–.

  • job_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of a job, or None ๐Ÿ†”. If specified, the file may be associated with that job in a job-store-specific way, and this may influence the returned ID ๐ŸŒŸ.
  • cleanup (bool, /usr/share/doc/python3/html/library/functions.html#bool) โ€” whether to attempt to delete the file when the job whose jobStoreID was given as jobStoreID is deleted with jobStore.delete(job) ๐Ÿงน. If jobStoreID was not given, this does nothing ๐Ÿ™ƒ.
  • basename (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” okay bestie, if the implementation supports it, the given file basename gets used so that a job store search matching that basename will find the file ๐Ÿ”โœจ
  • encoding (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). Defaults to None, which means binary mode ๐Ÿซง
  • errors (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an optional string for how encoding errors get handled. These are the same as for open(), and it defaults to 'strict' when an encoding is specified ๐Ÿ’…

Raises

  • ConcurrentFileModificationException (#toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file got modified concurrently during an invocation of this method ๐Ÿ˜ญ
  • NoSuchJobException (#toil.jobStores.abstractJobStore.NoSuchJobException) โ€” if the job specified via jobStoreID does not exist ๐Ÿ’€
FIXME: some implementations may not raise this

Returns

A context manager yielding a file handle that can be written to, plus an ID that references the newly created file and can be used to read it in the future. ๐ŸŽ€

Return type

Iterator[Tuple[IO[bytes], str]]

Doc refs: /usr/share/doc/python3/html/library/stdtypes.html#bytes and /usr/share/doc/python3/html/library/stdtypes.html#str.


get_empty_file_store_id(job_id=None, cleanup=False, basename=None)

Creates an empty file in the job store and returns its ID. Calling fileExists(getEmptyFileStoreID(jobStoreID)) will return True, so you can literally check it right away โœจ

Parameters

  • job_id โ€” the ID of a job, or None. If specified, the file may be associated with that job in a job-store-specific way. This may influence the returned ID ๐Ÿงš
  • cleanup โ€” whether to attempt deleting the file when the job whose jobStoreID was given as jobStoreID is deleted with jobStore.delete(job). If jobStoreID was not given, nothing happens ๐Ÿงน
  • basename โ€” if supported by the implementation, use the given file basename so that when searching the job store with a query matching that basename, the file will be detected ๐Ÿ”Ž

Returns

A jobStoreFileID that references the newly created file and can be used to reference the file in the future ๐Ÿฆ‹

Return type

str (see /usr/share/doc/python3/html/library/stdtypes.html#str)


Copies or hard links the file referenced by jobStoreFileID to the given local file path. The version will be consistent with the last copy of the file written or updated. If the file in the job store is later modified via updateFile or updateFileStream, it is implementation-defined whether those writes will be visible at localFilePath. The file is copied in an atomic manner, so it won't appear in the local file system until the copy has completed ๐ŸŒธ

The file at the given local path may not be modified after this method returns!
Note! Implementations of readFile need to respect and provide the executable attribute on FileIDs ๐Ÿ”ฅ

Parameters

  • file_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” ID of the file to be copied
  • local_path (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the local path showing where to place the contents of the given file in the job store
  • symlink (bool, see /usr/share/doc/python3/html/library/functions.html#bool) โ€” whether the reader can tolerate a symlink. If set to true, the job store may create a symlink instead of a full copy of the file or a hard link ๐Ÿ”—

read_file_stream(file_id, encoding=None, errors=None)

Okay so this one is basically readFile's cooler cousin ๐Ÿ˜Ž It returns a context manager yielding a file handle that you can read from. The yielded file handle does not need to be closed explicitly, and it should not be closed explicitly either ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • file_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” ID of the file to get a readable file handle for
  • encoding (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the encoding used to decode the file. Encodings are the same as for decode(). Defaults to None, which means binary mode
  • errors (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an optional string for how encoding errors get handled. These are the same as for open(), and it defaults to 'strict' when an encoding is specified

Returns

A context manager yielding a file handle that can be read from ๐Ÿ“–

Return type

Iterator[Union[IO[bytes], IO[str]]]

Doc refs: /usr/share/doc/python3/html/library/stdtypes.html#bytes and /usr/share/doc/python3/html/library/stdtypes.html#str.


delete_file(file_id)

Deletes the file with the given ID from this job store. This operation is idempotent, which means deleting a file twice, or deleting a non-existent file, will succeed silently. No drama ๐Ÿซถ

Parameters

  • file_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” ID of the file to delete ๐Ÿ—‘๏ธ

file_exists(file_id)

Determines whether a file exists in this job store ๐Ÿ‘€

Parameters

  • file_id โ€” an ID referencing the file to be checked

get_file_size(file_id)

Gets the size of the given file in bytes, or 0 if it does not exist when queried. ๐Ÿ“

Note that job stores which encrypt files might return overestimates of file sizes, since the encrypted file may have been padded to the nearest block, augmented with an initialization vector, etc.

Parameters

  • file_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an ID referencing the file to be checked

Return type

int (see /usr/share/doc/python3/html/library/functions.html#int)


update_file(file_id, local_path)

Replaces the existing version of a file in the job store. It throws an exception if the file does not exist ๐Ÿšซ

Parameters

  • file_id โ€” the ID of the file in the job store to be updated
  • local_path โ€” the local path to a file that will overwrite the current version in the job store

Raises

  • ConcurrentFileModificationException (#toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file was modified concurrently during an invocation of this method ๐Ÿ˜ฌ
  • NoSuchFileException (#toil.jobStores.abstractJobStore.NoSuchFileException) โ€” if the specified file does not exist ๐Ÿ™ˆ

update_file_stream(file_id, encoding=None, errors=None)

Replaces the existing version of a file in the job store. It's similar to writeFile, but it returns a context manager yielding a file handle which can be written to ๐Ÿช„ The yielded file handle does not need to be closed explicitly, and it should not be closed explicitly either ๐Ÿ’œ

Parameters

  • file_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the ID of the file in the job store to be updated
  • encoding (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the encoding used to encode the file. Encodings are the same as for encode(). Defaults to None, which means binary mode
  • errors (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an optional string for how encoding errors get handled. These are the same as for open(), and it defaults to 'strict' when an encoding is specified

Raises

  • ConcurrentFileModificationException (#toil.jobStores.abstractJobStore.ConcurrentFileModificationException) โ€” if the file was modified concurrently during an invocation of this method ๐Ÿ˜ญ
  • NoSuchFileException (toil.jobStores.abstractJobStore.NoSuchFileException): bestie, this one gets raised when the file you asked for straight up doesn't exist ๐Ÿ’€

โœจ write_shared_file_stream(shared_file_name, encrypted=True, encoding=None, errors=None) โœจ

okay so this one hands you a context manager that yields a writable file handle to the global file with the name you give it ๐Ÿฆ‹ the file gets created in an atomic manner, so it's giving all-or-nothing energy ๐Ÿ’…

Parameters ๐ŸŽ€

  • shared_file_name (str): a file name that matches AbstractJobStore.fileNameRegex and is unique inside this job store ๐ŸŒธ
  • encrypted (bool): True if the file has to be encrypted, None if it can be encrypted or maybe not, and False if it must be stored in the clear ๐Ÿ”
  • encoding (str): the name of the encoding used to encode the file. Encodings are the same ones you'd use with encode(). It defaults to None, which means binary mode ๐Ÿงš
  • errors (str): an optional string that tells Python how to handle encoding errors. These work the same as they do for open(). It defaults to 'strict' whenever you specify an encoding ๐Ÿซถ

Raises ๐Ÿ˜ญ

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException): if the file got modified by someone else while this method was running ๐Ÿ™ˆ

Returns โœจ

a context manager yielding a writable file handle

Return type ๐Ÿ’œ

Iterator[IO[bytes]]

โœจ read_shared_file_stream(shared_file_name, isProtected=True, encoding=None, errors=None) โœจ

this is the reading counterpart! ๐Ÿ“– it returns a context manager that yields a readable file handle to the global file that matches the name you pass in ๐ŸŒˆ

Parameters ๐ŸŽ€

  • shared_file_name (str): a file name that matches AbstractJobStore.fileNameRegex and is unique inside this job store ๐ŸŒธ
  • encoding (str): the name of the encoding used to decode the file. Decodings match what you'd get from decode(). It defaults to None, which means binary mode ๐Ÿงš
  • errors (str): an optional string that tells Python how to handle encoding errors, same as open(). It defaults to 'strict' when an encoding is specified ๐Ÿซถ

Returns โœจ

a context manager yielding a readable file handle

โœจ write_logs(msg) โœจ

this one stores a message as a log in the jobstore ๐Ÿ“ very simple, very iconic ๐Ÿ’…

Parameters ๐ŸŽ€

  • msg (str): the string you want written ๐Ÿ“

Raises ๐Ÿ˜ญ

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException): if the file was modified concurrently during an invocation of this method ๐Ÿ™ˆ

Return type ๐Ÿ’œ

None

โœจ read_logs(callback, read_all=False) โœจ

this reads the logs that write_logs() has piled up ๐Ÿ“š ngl, it doesn't hand them back to you directly. instead, it calls the callback function you give it once for each log, with the message as the argument. so your callback is the one doing the processing ๐Ÿฆ‹

by default, only the unread logs get read. set read_all if you want the already-processed ones too ๐Ÿ‘‘

Parameters ๐ŸŽ€

  • callback (Callable): a function to be applied to each of the stats file handles found ๐Ÿงš
  • read_all (bool): a boolean that decides whether to also read the stats files that were already processed, on top of the unread ones ๐ŸŒธ

Raises ๐Ÿ˜ญ

  • ConcurrentFileModificationException (toil.jobStores.abstractJobStore.ConcurrentFileModificationException): if the file was modified concurrently during an invocation of this method ๐Ÿ™ˆ

Returns โœจ

the number of stats files processed

Return type ๐Ÿ’œ

int


๐ŸŒธ toil.jobStores.utils ๐ŸŒธ

Attributes ๐ŸŽ€

  • log: the logger attribute for this module ๐Ÿ“

Exceptions ๐Ÿซถ

  • JobStoreUnavailableException: raised when a particular type of job store is requested but can't be used ๐Ÿ˜ค

Functions ๐Ÿงš

  • generate_locator(job_store_type[, local_suggestion, ...]): generates a random locator for a job store of the given type. It raises an error if the job store can't be used ๐Ÿ”ฎ

Module Contents ๐Ÿ’…

toil.jobStores.utils.log

exception toil.jobStores.utils.JobStoreUnavailableException

Bases: RuntimeError

this is raised when a particular type of job store is requested but can't be used ๐Ÿ™…โ€โ™€๏ธ

toil.jobStores.utils.generate_locator(job_store_type, local_suggestion=None, decoration=None)

generates a random locator for a job store of the given type ๐ŸŽฒ if that job store can't be used, it raises a JobStoreUnavailableException ๐Ÿšจ

Parameters ๐ŸŽ€

  • job_store_type (str): the registry name of the job store you want to use ๐Ÿ—‚๏ธ
  • local_suggestion (Optional[str]): a path to a nonexistent local directory that's suitable for use as a file job store ๐Ÿ“
  • decoration (Optional[str]): an extra string to add to the job store locator, if it's convenient ๐ŸŽ€

Return str โœจ

the job store locator for a usable job store

Return type ๐Ÿ’œ

str


๐Ÿฆ‹ toil.leader ๐Ÿฆ‹

the leader script (the leader half of the leader/worker pair) that runs your jobs ๐Ÿ‘‘

Attributes ๐ŸŽ€

  • logger: the logger for this module ๐Ÿ“

Classes ๐Ÿ’…

  • Leader: represents the Toil leader ๐Ÿ‘‘

Module Contents ๐ŸŒˆ

toil.leader.logger

class toil.leader.Leader(config, batchSystem, provisioner, jobStore, rootJob, jobCache=None)

represents the Toil leader, and it's the one responsible for figuring out which jobs are ready to be scheduled ๐Ÿง  it checks in with the job store and then issues those jobs to the batch system ๐Ÿš€

Parameters ๐ŸŽ€

  • config (toil.common.Config) โš™๏ธ
  • batchSystem (toil.batchSystems.abstractBatchSystem.AbstractBatchSystem) ๐Ÿ–ฅ๏ธ
  • provisioner (Optional[toil.provisioners.abstractProvisioner.AbstractProvisioner]) โ˜๏ธ
  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore) ๐Ÿ—ƒ๏ธ
  • rootJob (toil.job.JobDescription) ๐ŸŒณ
  • jobCache (Optional[dict[Union[str, toil.job.TemporaryID], toil.job.JobDescription]]) ๐Ÿงบ

Attributes ๐Ÿ’–

  • config
  • jobStore
  • jobStoreLocator
  • toilState
  • batchSystem

Okay so the leader is holding a whole bag of attributes, and it's giving organized ๐Ÿ’…โœจ

issued_jobs_by_batch_system_id: dict[int, str]
preemptibleJobsIssued = 0
serviceJobsIssued = 0
serviceJobsToBeIssued: list[str] = []
preemptibleServiceJobsIssued = 0
preemptibleServiceJobsToBeIssued: list[str] = []
timeSinceJobsLastRescued = None
reissueMissingJobs_missingHash: dict[int, int]
provisioner
clusterScaler = None
serviceManager
statsAndLogging
potentialDeadlockedJobs: set[str]
potentialDeadlockTime = 0
toilMetrics: toil.common.ToilMetrics | None = None
debugJobNames = ('CWLJob', 'CWLWorkflow', 'CWLScatter', 'CWLGather', 'ResolveIndirect')
deadlockThrottler
statusThrottler
kill_throttler
progress_overall = None
progress_failed = None
GOOD_COLOR = (0, 60, 108)
BAD_COLOR = (253, 199, 0)
PROGRESS_BAR_FORMAT = '{desc}{desc_pad}{percentage:3.0f}%|{bar}| {count:{len_total}d}/{total:d} ({count_1:d} failures)...
recommended_fail_exit_code = 1

The type references behind those annotations point at these docs, bestie ๐Ÿงš:

  • dict โ†’ /usr/share/doc/python3/html/library/stdtypes.html#dict
  • int โ†’ /usr/share/doc/python3/html/library/functions.html#int
  • str โ†’ /usr/share/doc/python3/html/library/stdtypes.html#str
  • list โ†’ /usr/share/doc/python3/html/library/stdtypes.html#list
  • set โ†’ /usr/share/doc/python3/html/library/stdtypes.html#set
  • None โ†’ /usr/share/doc/python3/html/library/constants.html#None
  • bool โ†’ /usr/share/doc/python3/html/library/functions.html#bool
  • float โ†’ /usr/share/doc/python3/html/library/functions.html#float

run() ๐Ÿƒโ€โ™€๏ธ

Okay this one is the main event! It runs the leader process to issue and manage jobs. ๐Ÿ‘‘

  • Raises toil.exceptions.FailedJobsException if failed jobs remain after running.
  • Returns the return value of the root job's run function.
  • Return type Any

create_status_sentinel_file(fail) ๐Ÿšฉ

Creates a file in the jobstore that says whether things failed or succeeded. ๐ŸŽ€

  • Parameters: fail (bool, see /usr/share/doc/python3/html/library/functions.html#bool)
  • Return type None

innerLoop() ๐Ÿ”

Processes jobs. This is the leader's main loop, so it's literally the heartbeat of the whole thing ๐Ÿ’–

checkForDeadlocks() ๐Ÿ”’

Checks if the system is deadlocked while running service jobs. Nobody wants a deadlock, no cap ๐Ÿ˜ญ

feed_deadlock_watchdog() ๐Ÿ•

Notes that progress has been made, so any pending deadlock checks get reset. Good girl watchdog ๐Ÿซถ

  • Return type None

issueJob(jobNode) ๐Ÿ“ฅ

Adds a job to the queue of jobs that are currently trying to run. Main character energy ๐ŸŒธ

  • Parameters: jobNode (toil.job.JobDescription)
  • Return type None

issueJobs(jobs) ๐Ÿ“ฆ

Adds a whole list of jobs, each one represented as a jobNode object. Batch hours ๐Ÿ“

issueServiceJob(service_id) ๐Ÿ›Ž๏ธ

Issues a service job. If the maximum number of service jobs to be scheduled has already been reached, it goes on a queue instead, so it just waits its turn ๐Ÿ’…

  • Parameters: service_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type None

issueQueingServiceJobs() โณ

Issues any queuing service jobs, up to the limit of the maximum allowed. Queue slay ๐Ÿงš

getNumberOfJobsIssued(preemptible=None) ๐Ÿ”ข

Gets the number of jobs that have been added by issueJob(s) and not removed by removeJob. Iconic counting moment ๐Ÿ’œ

  • Parameters: preemptible (Optional[bool], see /usr/share/doc/python3/html/library/functions.html#bool)
    • If None, it returns all types of jobs.
    • If True, it returns just the number of preemptible jobs.
    • If False, it returns just the number of non-preemptible jobs.
  • Return type int, see /usr/share/doc/python3/html/library/functions.html#int

removeJob(jobBatchSystemID) ๐Ÿ—‘๏ธ

Removes a job from the system by its batch system ID. Bye bye, job ๐Ÿ‘‹

  • Returns the job description as it was issued.
  • Parameters: jobBatchSystemID (int, see /usr/share/doc/python3/html/library/functions.html#int)
  • Return type toil.job.JobDescription

getJobs(preemptible=None) ๐Ÿ“‹

Gets all the issued jobs. Full list, no skips ๐Ÿฆ‹

  • Parameters: preemptible (Optional[bool], see /usr/share/doc/python3/html/library/functions.html#bool)
    • If specified, it selects only preemptible jobs or only non-preemptible jobs.
  • Return type list[toil.job.JobDescription], see /usr/share/doc/python3/html/library/stdtypes.html#list

killJobs(jobsToKill, exit_reason=BatchJobExitReason.KILLED) ๐Ÿ’€

Kills the given set of jobs and then sends them off for processing. Harsh but fair ๐Ÿ˜ญ

  • Returns the jobs that were reissued once they got processed.
  • Parameters: exit_reason (toil.batchSystems.abstractBatchSystem.BatchJobExitReason)

reissueOverLongJobs() โฐ

Checks each issued job. If a job has been running for longer than is desirable, it issues a kill instruction. Then it waits for the job to die, and after that the job gets passed to process_finished_job. ๐Ÿซ 

  • Return type None

reissueMissingJobs(killAfterNTimesMissing=3) ๐Ÿ•ต๏ธโ€โ™€๏ธ

Checks that all the current job IDs are in the list of currently issued batch system jobs. If a job is missing, it gets marked as missing. If it stays missing for a number of runs of this function (say 10).. then the leader tries deleting the job (though it's probably lost). It waits after that, then passes the job to process_finished_job. Detective era ๐Ÿ”

processRemovedJob(issuedJob, result_status) ๐Ÿคทโ€โ™€๏ธ

No description is given for this one, so it's a little mysterious ๐Ÿ™ˆ

process_finished_job(batch_system_id, result_status, wall_time=None, exit_reason=None) ๐Ÿ

Processes finished jobs. This gets called when an attempt to run a job finishes, whether it succeeded or not. It takes the job out of the issued state, then works out what to do about the success or failure. โœจ

  • Returns True if the job is going to run again, and False if the job is fully done or completely failed.
  • Return type bool, see /usr/share/doc/python3/html/library/functions.html#bool

process_finished_job_description(finished_job, result_status, wall_time=None, exit_reason=None, batch_system_id=None) ๐Ÿ—‚๏ธ

Processes a finished JobDescription based on whether it succeeded or failed. Here's the breakdown, bestie:

  • If wall-clock time is available, it tells the cluster scaler about the job finishing.
  • If the job failed and a batch system ID is available, it checks for and reports batch system logs.
  • It checks whether the job succeeded and was removed, or whether it failed and needs to be set up after failure, then dispatches to the appropriate function.
  • Returns True if the job is going to run again, and False if the job is fully done or completely failed.
  • Parameters:
    • finished_job (toil.job.JobDescription)
    • result_status (int, see /usr/share/doc/python3/html/library/functions.html#int)
    • wall_time (Optional[float], see /usr/share/doc/python3/html/library/functions.html#float)
    • exit_reason (Optional[toil.batchSystems.abstractBatchSystem.BatchJobExitReason])
    • batch_system_id (Optional[int], see /usr/share/doc/python3/html/library/functions.html#int)
  • Return type bool, see /usr/share/doc/python3/html/library/functions.html#bool

getSuccessors(job_id, alreadySeenSuccessors) ๐ŸŒณ

Gets the successors of the given job by walking the job graph recursively. Tree climbing era ๐Ÿง—โ€โ™€๏ธ

  • Parameters:
    • alreadySeenSuccessors (set[str], see /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” any successor seen here is ignored and not traversed.
    • job_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Returns the set of successors that were found. This set is added to alreadySeenSuccessors.
  • Return type set[str], see /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/stdtypes.html#str

processTotallyFailedJob(job_id) ๐Ÿ’”

Processes a totally failed job. Rough, but we process it anyway ๐Ÿซถ

  • Parameters: job_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type None

โœจ toil.lib โœจ

๐Ÿงฉ Submodules

Okay bestie, this is the toil.lib grab bag ๐ŸŽ€ Right now it's got one submodule that I'm obsessed with:

๐Ÿ”ฅ toil.lib.accelerators

Accelerator (i.e. GPU) utilities for Toil. It's giving hardware realness ๐Ÿ’…

๐Ÿ”ง Functions

  • have_working_nvidia_smi(): checks whether nvidia's CUDA userspace nvidia-smi binary is there and actually runs ๐Ÿ’–
  • get_host_accelerator_numbers(): works out what accelerator is what ๐Ÿฆ‹
  • have_working_nvidia_docker_runtime(): checks if Docker can handle an "nvidia" runtime and the "--gpus" option ๐Ÿณ
  • count_nvidia_gpus(): counts the nvidia GPUs nvidia-smi can see, or gives back 0 if it's not working ๐ŸŒธ
  • count_amd_gpus(): counts the amd GPUs rocm-smi can see, or gives back 0 if it's not working ๐Ÿ“
  • get_individual_local_accelerators(): finds every local accelerator and reports each one with count 1 โœจ
  • get_restrictive_environment_for_local_accelerators(...): builds environment variables you can apply to a process so it only uses certain accelerators ๐Ÿ”’

๐Ÿ“š Module Contents

toil.lib.accelerators.have_working_nvidia_smi()

Returns True if the nvidia-smi binary, from nvidia's CUDA userspace utilities, is installed and runs successfully. It's giving confirmed working ๐Ÿ™Œ

TODO: This isn't quite the same as the check that cwltool uses to decide if it can fulfill a CUDARequirement. ๐Ÿ™ˆ
  • Return type: bool (docs: /usr/share/doc/python3/html/library/functions.html#bool)

toil.lib.accelerators.get_host_accelerator_numbers()

Figures out what accelerator is what. For each accelerator we can see, it returns the host-side number, meaning the one outside something like a Slurm job. Usually it matches the apparent number, so no drama ๐Ÿ’œ

It can be used with Docker's --gpus='"device=#,#,#"' option to forward the right GPUs as seen from a Docker daemon ๐Ÿณ

  • Return type: list[int] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/functions.html#int)

toil.lib.accelerators.have_working_nvidia_docker_runtime()

Returns True if Docker exists and can handle an "nvidia" runtime and the "--gpus" option. Main character energy ๐Ÿ‘‘

  • Return type: bool (docs: /usr/share/doc/python3/html/library/functions.html#bool)

toil.lib.accelerators.count_nvidia_gpus()

Returns how many nvidia GPUs nvidia-smi sees, or 0 if it isn't working. Simple, iconic ๐ŸŒˆ

  • Return type: int (docs: /usr/share/doc/python3/html/library/functions.html#int)

toil.lib.accelerators.count_amd_gpus()

Returns how many amd GPUs rocm-smi sees, or 0 if it isn't working. :return: ๐Ÿ“

  • Return type: int (docs: /usr/share/doc/python3/html/library/functions.html#int)

toil.lib.accelerators.get_individual_local_accelerators()

Finds all the local accelerators available. Each one gets reported with count 1, in the order of the number used to assign them. It's a whole lineup ๐Ÿ’–

TODO: How will numbers work with multiple types of accelerator? We need an accelerator assignment API. ๐Ÿซถ
  • Return type: list[toil.job.AcceleratorRequirement] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list and #toil.job.AcceleratorRequirement)

toil.lib.accelerators.get_restrictive_environment_for_local_accelerators(accelerator_numbers)

Gets environment variables you can apply to a process to restrict it to using only the given accelerator numbers. Lowkey the best way to keep your processes in their lane ๐Ÿ”’โœจ

The numbers are in the space of accelerators returned by get_individual_local_accelerators().

  • Parameters: accelerator_numbers (Union[set[int], list[int]], with docs at /usr/share/doc/python3/html/library/stdtypes.html#set, /usr/share/doc/python3/html/library/functions.html#int, and /usr/share/doc/python3/html/library/stdtypes.html#list)
  • Return type: dict[str, str] (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŒ toil.lib.aws

๐Ÿงฉ Submodules

  • toil.lib.aws.ami: the AMI submodule, where the AWS machine images live ๐Ÿ–ผ๏ธ

๐ŸŽ€ toil.lib.aws.ami

๐Ÿท๏ธ Attributes

  • logger: a logger attribute, no description needed ๐Ÿฆ‹

๐Ÿ’ฅ Exceptions

  • ReleaseFeedUnavailableError: raised when a Flatcar release can't be located ๐Ÿ™ˆ

๐Ÿ”ง Functions

  • get_flatcar_ami(ec2_client[, architecture]): retrieves the Flatcar AMI image to use as the base for all Toil autoscaling instances โœจ
  • flatcar_release_feed_ami(region[, architecture, source]): yields AMI IDs for the given architecture from the Flatcar release feed ๐ŸŒธ
  • feed_flatcar_ami_release(ec2_client[, architecture, ...]): checks a Flatcar release feed for the latest Flatcar AMI ๐Ÿ“
  • aws_marketplace_flatcar_ami_search(ec2_client[, ...]): queries AWS for all AMI names matching Flatcar-stable-* and returns the most recent one ๐Ÿ”Ž

๐Ÿ“š Module Contents

toil.lib.aws.ami.logger

exception toil.lib.aws.ami.ReleaseFeedUnavailableError

Bases: RuntimeError (docs: /usr/share/doc/python3/html/library/exceptions.html#RuntimeError)

Raised when a Flatcar releases can't be located. That's a whole mood ๐Ÿ˜ญ

toil.lib.aws.ami.get_flatcar_ami(ec2_client, architecture='amd64')

Retrieves the Flatcar AMI image to use as the base for all Toil autoscaling instances. It's the foundation, literally ๐Ÿงš๐Ÿ’œ

AMI must be available to you on AWS ๐Ÿ’… Attempting to launch one without access gets you a 403, so check that first, bestie ๐Ÿ’€

Here's the priority order for picking an AMI ๐Ÿซถ

  1. User specified AMI via TOIL_AWS_AMI โœจ
  2. Official AMI from stable.release.flatcar-linux.net ๐Ÿฆ‹
  3. Search the AWS Marketplace ๐Ÿ›๏ธ

If all three sources fail, it raises ReleaseFeedUnavailableError (#toil.lib.aws.ami.ReleaseFeedUnavailableError) ๐Ÿ˜ญ

Parameters

  • ec2_client (botocore.client.BaseClient): the Boto3 EC2 Client ๐Ÿงš
  • architecture (str </usr/share/doc/python3/html/library/stdtypes.html#str>): the architecture type for the new AWS machine. It can be either amd64 or arm64 ๐Ÿ’œ

Return type

str </usr/share/doc/python3/html/library/stdtypes.html#str>

toil.lib.aws.ami.flatcar_release_feed_ami

toil.lib.aws.ami.flatcar_release_feed_ami(region, architecture='amd64', source='stable')

This one yields AMI IDs for the given architecture from the Flatcar release feed ๐ŸŒธ

Parameters

  • source (str </usr/share/doc/python3/html/library/stdtypes.html#str>): can be set to a Flatcar release channel ('stable', 'beta', or 'alpha'), 'archive' to check the Internet Archive for a feed, or 'toil' to check if the Toil project has put up a feed ๐Ÿ”ฅ
  • region (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐ŸŒˆ
  • architecture (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐ŸŽ€

Return type

Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]

It retries if the release feed can't be fetched. If the release feed has a permanent error, it yields nothing. If some entries in the release feed are unparseable, it still yields the others ๐Ÿงš

toil.lib.aws.ami.feed_flatcar_ami_release

toil.lib.aws.ami.feed_flatcar_ami_release(ec2_client, architecture='amd64', source='stable')

This checks a Flatcar release feed for the latest flatcar AMI and verifies that it's on AWS โญ

It does not raise exceptions. ๐Ÿ™ˆ

Parameters

  • ec2_client (botocore.client.BaseClient): the Boto3 EC2 Client ๐Ÿงš
  • architecture (str </usr/share/doc/python3/html/library/stdtypes.html#str>): the architecture type for the new AWS machine. It can be either amd64 or arm64 ๐Ÿ’œ
  • source (str </usr/share/doc/python3/html/library/stdtypes.html#str>): can be set to a Flatcar release channel ('stable', 'beta', or 'alpha'), 'archive' to check the Internet Archive for a feed, or 'toil' to check if the Toil project has put up a feed ๐Ÿ”ฅ

Return type

Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]

toil.lib.aws.ami.aws_marketplace_flatcar_ami_search(ec2_client, architecture='amd64')

This queries AWS for all AMI names matching Flatcar-stable-* and returns the most recent one ๐Ÿ‘‘

It does not raise exceptions. ๐Ÿ™ˆ

Returns

An AMI name, or None if no matching AMI was found or we couldn't talk to AWS ๐Ÿ“

Parameters

  • ec2_client (botocore.client.BaseClient) ๐Ÿงš
  • architecture (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿ’œ

Return type

Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]

toil.lib.aws.config

Attributes

  • S3_PARALLELIZATION_FACTOR ๐Ÿฆ‹
  • S3_PART_SIZE ๐ŸŒธ
  • KiB โœจ
  • MiB โœจ
  • AWS_MIN_CHUNK_SIZE ๐Ÿ’…
  • MULTIPART_THRESHOLD ๐ŸŽ€
  • AWS_MAX_MULTIPART_COUNT ๐Ÿ‘‘

Functions

  • get_s3_multipart_chunk_size(filesize): returns the chunk size of the S3 multipart object, given a file's size in bytes ๐Ÿงš

Module Contents

toil.lib.aws.config.S3_PARALLELIZATION_FACTOR = 8
toil.lib.aws.config.S3_PART_SIZE = 16777216
toil.lib.aws.config.KiB = 1024
toil.lib.aws.config.MiB = 1048576
toil.lib.aws.config.AWS_MIN_CHUNK_SIZE = 67108864
toil.lib.aws.config.MULTIPART_THRESHOLD = 67108865
toil.lib.aws.config.AWS_MAX_MULTIPART_COUNT = 10000

toil.lib.aws.config.get_s3_multipart_chunk_size

toil.lib.aws.config.get_s3_multipart_chunk_size(filesize)

This returns the chunk size of the S3 multipart object, given a file's size in bytes ๐Ÿ’–

Parameters

  • filesize (int </usr/share/doc/python3/html/library/functions.html#int>) ๐ŸŒˆ

Return type

int </usr/share/doc/python3/html/library/functions.html#int>

toil.lib.aws.iam

Attributes

  • logger ๐ŸŽ€
  • CLUSTER_LAUNCHING_PERMISSIONS ๐Ÿซถ
  • AllowedActionCollection ๐Ÿ”ฅ

โœจ Functions โœจ

Okay bestie, here's the whole lineup of IAM helpers ๐Ÿ’… Every function is listed with its signature, and I gave the description the glow-up it needed ๐Ÿฆ‹

  • delete_iam_instance_profile(instance_profile_name[, ...]) ๐Ÿ—‘๏ธ (there's no blurb for this one in the table, so it's just the signature)
  • delete_iam_role(role_name[, region, quiet]) โ€” Nukes an AWS IAM role ๐Ÿ’€ Any separate policies get detached from the role, and any inline policies get deleted.
  • create_iam_role(role_name, ...[, region]) โ€” Makes a brand new AWS IAM role โœจ Any separate policies get detached from the role, and any inline policies get deleted.
  • init_action_collection() โ€” Sets up a fresh action collection ๐ŸŽ€. An action collection holds allowed Actions and NotActions.
  • add_to_action_collection(a, b) โ€” Mashes two action collections together ๐Ÿซถ
  • policy_permissions_allow(given_permissions[, ...]) โ€” Checks whether one given set of actions is a subset of another given set of actions. It returns true if they are ๐Ÿฆ‹
  • permission_matches_any(perm, list_perms) โ€” Takes a permission and checks whether it's contained within a list of given permissions ๐Ÿ‘€
  • get_actions_from_policy_document(policy_doc) โ€” Given a policy document, it goes through each statement and creates an AllowedActionCollection representing theโ€ฆ (and the table just stops there ๐Ÿ’€)
  • allowed_actions_attached(iam, attached_policies) โ€” Goes through all the attached policy documents and creates an AllowedActionCollection representing granted permissions ๐ŸŒธ
  • allowed_actions_roles(iam, policy_names, role_name) โ€” Returns a dictionary holding a list of all AWS actions allowed for a given role ๐Ÿงš
  • collect_policy_actions(policy_documents) โ€” Collects all of the actions allowed by the given policy documents into one AllowedActionCollection ๐Ÿ’œ
  • allowed_actions_user(iam, policy_names, user_name) โ€” Gets all allowed actions for a user given by user_name. It returns a dictionary, keyed by resource, (and then it trails off too ๐Ÿ™ˆ)
  • allowed_actions_group(iam, policy_names, group_name) โ€” Gets all allowed actions for a group given by group_name. It returns a dictionary, keyed by resource, (same trailing vibe ๐Ÿ™ˆ)
  • get_policy_permissions(region) โ€” Returns an action collection containing lists of all permission grant patterns, keyed by resource ๐Ÿ”ฅ
  • get_aws_account_num() โ€” Returns the AWS account num ๐Ÿ“

โœจ Module Contents โœจ

Here's what lives inside the module, bestie ๐ŸŒˆ

  • toil.lib.aws.iam.logger ๐Ÿ“’
  • toil.lib.aws.iam.CLUSTER_LAUNCHING_PERMISSIONS ๐Ÿš€ It's a list of permissions, and it starts like this:
toil.lib.aws.iam.CLUSTER_LAUNCHING_PERMISSIONS = ['iam:CreateRole',
'iam:CreateInstanceProfile', 'iam:TagInstanceProfile',
'iam:DeleteRole',...
  • toil.lib.aws.iam.AllowedActionCollection ๐Ÿ’–

toil.lib.aws.iam.delete_iam_instance_profile(instance_profile_name, region=None, quiet=True)

Parameters ๐Ÿ“

  • instance_profile_name (str, </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • region (Optional[str], </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • quiet (bool, </usr/share/doc/python3/html/library/functions.html#bool>)

Return type: None ๐ŸŽ€

toil.lib.aws.iam.delete_iam_role(role_name, region=None, quiet=True)

Deletes an AWS IAM role. Any separate policies are detached from the role, and any inline policies are deleted ๐Ÿ—‘๏ธ

Parameters ๐Ÿ“

  • role_name (str, </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” The name of the AWS IAM role.
  • region (Optional[str], </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” The AWS region that the role_name is in.
  • quiet (bool, </usr/share/doc/python3/html/library/functions.html#bool>) โ€” Whether or not to print/log information about the deletion to stdout.

Return type: None โœจ

toil.lib.aws.iam.create_iam_role(role_name, assume_role_policy_document, policies, region=None)

Creates an AWS IAM role. Any separate policies are detached from the role, and any inline policies are deleted ๐ŸŒธ

Parameters ๐Ÿ“

toil.lib.aws.iam ๐Ÿ”

  • role_name (str): the name of the AWS IAM role ๐ŸŽ€
  • region (Optional[str]): the AWS region that the role_name is in ๐ŸŒ
  • assume_role_policy_document (str): policies to create inline with the role ๐Ÿ“œ
  • policies (dict[str, Any]): global policies to attach to the role ๐Ÿ’…

Return type: str

toil.lib.aws.iam.init_action_collection()

okay so this one makes a fresh, empty action collection ๐Ÿงบ. An action collection holds allowed Actions and NotActions sorted by resource, and the entries are patterns with wildcards. An Action explicitly allows whatever it matches, so ec2:* lets through every ec2 permission โœจ. A NotAction explicitly allows everything that doesn't match its pattern, so iam:* lets through all the non-iam actions ๐Ÿ™ˆ

Return type: AllowedActionCollection

toil.lib.aws.iam.add_to_action_collection(a, b)

this just mashes two action collections together into one ๐Ÿซถ

Parameters

  • a (AllowedActionCollection)
  • b (AllowedActionCollection)

Return type: AllowedActionCollection

toil.lib.aws.iam.policy_permissions_allow(given_permissions, required_permissions=[])

this checks whether one set of actions is a subset of another set ๐Ÿ‘€. It returns true if it is, and false otherwise. If the check fails it also prints a warning, so keep an eye on your console โš ๏ธ

Parameters

  • required_permissions (list[str]): dictionary containing the actions required, keyed by resource
  • given_permissions (AllowedActionCollection): the set of actions granted to a user or role

Return type: bool

toil.lib.aws.iam.permission_matches_any(perm, list_perms)

checks whether a single permission shows up inside a list of permissions. It returns True if it does and False if it doesn't ๐Ÿ’–

Parameters

  • perm (str): the permission to check, in string form
  • list_perms (list[str]): the permission list to check against

Return type: bool

toil.lib.aws.iam.get_actions_from_policy_document(policy_doc)

give this a policy document and it goes through every statement, then builds an AllowedActionCollection that represents the permissions that document grants ๐Ÿง 

Parameters

  • policy_doc (mypy_boto3_iam.type_defs.PolicyDocumentDictTypeDef): the policy document to examine

Return type: AllowedActionCollection

toil.lib.aws.iam.allowed_actions_attached(iam, attached_policies)

goes through every attached policy document and builds an AllowedActionCollection showing what's granted ๐Ÿฆ‹

Parameters

  • iam (mypy_boto3_iam.IAMClient): the IAM client to use
  • attached_policies (list[mypy_boto3_iam.type_defs.AttachedPolicyTypeDef]): the attached policies

Return type: AllowedActionCollection

toil.lib.aws.iam.allowed_actions_roles(iam, policy_names, role_name)

returns a dictionary with a list of every aws action a given role is allowed to do ๐ŸŒธ. The dictionary is keyed by resource, and each key gives you the list of policies allowed on that resource.

Parameters

  • iam (mypy_boto3_iam.IAMClient): the IAM client to use
  • policy_names (list[str]): the names of the policy documents attached to a role
  • role_name (str): the name of the role to look up its policies for

Return type: AllowedActionCollection

toil.lib.aws.iam.collect_policy_actions(policy_documents)

takes a bunch of policy documents and squishes all the allowed actions into one AllowedActionCollection ๐Ÿง

Parameters

  • policy_documents (list[Union[str, mypy_boto3_iam.type_defs.PolicyDocumentDictTypeDef]]): no description given, sadly ๐Ÿ˜ญ

Return type: AllowedActionCollection

toil.lib.aws.iam.allowed_actions_user(iam, policy_names, user_name)

gets every allowed action for the user named user_name ๐Ÿง‘โ€๐Ÿ’ป. It returns a dictionary keyed by resource, with a list of the permissions allowed on each resource.

Parameters

  • iam (mypy_boto3_iam.IAMClient): the IAM client to use
  • policy_names (list[str]): the names of the policy documents attached to a user
  • user_name (str): the name of the user to look up its policies for

Return type: AllowedActionCollection

toil.lib.aws.iam.allowed_actions_group(iam, policy_names, group_name)

same energy as the user version, but for a group named group_name ๐Ÿ‘ฏ. It returns a dictionary keyed by resource, with the permissions allowed on each one.

Parameters

  • iam (mypy_boto3_iam.IAMClient): the IAM client to use
  • policy_names (list[str]): the names of the policy documents associated with a user (yes, the original says user here, the vibe is slightly off ๐Ÿ™ƒ)
  • group_name (str): the name of the group to look up its policies for

Return type: AllowedActionCollection

toil.lib.aws.iam.get_policy_permissions(region)

returns an action collection full of all the permission grant patterns, keyed by the resource they're allowed on ๐Ÿ—๏ธ. You need AWS credentials tied to a user or an assumed role for this one to work ๐Ÿ”‘

Parameters

  • zone: the AWS zone to connect to ๐Ÿ“
  • region (str)

Return type: AllowedActionCollection

toil.lib.aws.iam.get_aws_account_num()

gives you the AWS account number ๐Ÿ”ข

Return type: Optional[str]


๐Ÿง toil.lib.aws.s3

Attributes

  • logger ๐Ÿชต
  • AWS_MAX_MULTIPART_COUNT ๐Ÿงฉ
  • AWS_MAX_CHUNK_SIZE ๐Ÿ“ฆ
  • AWS_MIN_CHUNK_SIZE ๐Ÿฃ
  • DEFAULT_AWS_CHUNK_SIZE โœจ

Exceptions

  • AWSKeyNotFoundError: common base class for all non-exit exceptions ๐Ÿ’€
  • AWSKeyAlreadyExistsError: common base class for all non-exit exceptions ๐Ÿ’€
  • AWSBadEncryptionKeyError: common base class for all non-exit exceptions ๐Ÿ’€

Classes

  • MultiPartPipe: an object-oriented wrapper for os.pipe. Clients should subclass it and implement (the docs cut off right there, bestie ๐Ÿ˜ญ)

โœจ Functions โœจ

okay bestie, here's the whole lineup of S3 helper functions in toil.lib.aws.s3 ๐Ÿชฃ๐Ÿ’–

  • create_s3_bucket(s3_resource, bucket_name, region[, ...]) โ€” makes a brand new AWS S3 bucket using the Boto3 S3 session you hand it, with the name and region you want ๐ŸŽ€
  • delete_s3_bucket(s3_resource, bucket_name[, quiet]) โ€” deletes the bucket called bucket_name ๐Ÿ—‘๏ธ
  • bucket_exists(s3_resource, bucket)
  • head_s3_object(bucket, key, header[, region]) โ€” attempts a HEAD request on an s3 object and hands back its response ๐Ÿ‘€
  • list_multipart_uploads(bucket, region, prefix[, ...])
  • copy_s3_to_s3(s3_resource, src_bucket, src_key, ...[, ...])
  • copy_local_to_s3(s3_resource, local_file_path, ...[, ...])
  • copy_s3_to_local(s3_resource, local_file_path, ...[, ...])
  • parse_s3_uri(uri)
  • list_s3_items(s3_resource, bucket, prefix[, startafter])
  • upload_to_s3(readable, s3_resource, bucket, key[, ...]) โ€” uploads a readable object to s3, using multipart uploading when it applies ๐Ÿš€
  • download_stream(s3_resource, bucket, key[, ...]) โ€” a context manager that gives you a download stream so you can pull the data down ๐Ÿงš
  • download_fileobject(s3_resource, bucket, key, fileobj)
  • s3_key_exists(s3_resource, bucket, key[, check, ...]) โ€” returns True if the s3 object exists and False if it doesn't. Heads up: it will error if the encryption args are incorrect ๐Ÿ’€
  • get_s3_object(s3_resource, bucket, key[, extra_args])
  • put_s3_object(s3_resource, bucket, key, body[, extra_args])
  • generate_presigned_url(s3_resource, bucket, key_name, ...)
  • create_public_url(s3_resource, bucket, key)
  • get_s3_bucket_region(s3_resource, bucket)

๐ŸŒˆ Module Contents ๐ŸŒˆ

  • toil.lib.aws.s3.logger
  • toil.lib.aws.s3.AWS_MAX_MULTIPART_COUNT = 10000
  • toil.lib.aws.s3.AWS_MAX_CHUNK_SIZE = 5000000000000
  • toil.lib.aws.s3.AWS_MIN_CHUNK_SIZE = 5000000
  • toil.lib.aws.s3.DEFAULT_AWS_CHUNK_SIZE = 134217728

๐Ÿ’… Exceptions

Okay, these three exceptions are all the same vibe. Each one is a subclass of Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception), and the description is "Common base class for all non-exit exceptions." ๐Ÿ™ˆ

  • exception toil.lib.aws.s3.AWSKeyNotFoundError โ€” bases: Exception
  • exception toil.lib.aws.s3.AWSKeyAlreadyExistsError โ€” bases: Exception
  • exception toil.lib.aws.s3.AWSBadEncryptionKeyError โ€” bases: Exception

๐Ÿซถ Function Details

  • toil.lib.aws.s3.create_s3_bucket(s3_resource, bucket_name, region, tags=None, public=True)

Create an AWS S3 bucket using the given Boto3 S3 session, with the given name, in the given region. It supports the us-east-1 region, where bucket creation is special. ALL S3 bucket creation should use this function. ๐Ÿ’–

Parameters:

  • s3_resource (mypy_boto3_s3.S3ServiceResource)
  • bucket_name (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • region (Union[mypy_boto3_s3.literals.BucketLocationConstraintType, Literal['us-east-1']])
  • tags (Optional[Dict[str, str]])
  • public (bool (/usr/share/doc/python3/html/library/functions.html#bool))

Return type: mypy_boto3_s3.service_resource.Bucket

  • toil.lib.aws.s3.delete_s3_bucket(s3_resource, bucket_name, quiet=True)

Delete the bucket with 'bucket_name'. ๐Ÿ—‘๏ธ

Note: 'quiet' is False when used for a clean up utility script (contrib/admin/cleanup_aws_resources.py) that prints progress rather than logging. Logging should be used for all other internal Toil usage.

Parameters:

  • s3_resource (mypy_boto3_s3.S3ServiceResource)
  • bucket_name (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • quiet (bool (/usr/share/doc/python3/html/library/functions.html#bool))

Return type: None

  • toil.lib.aws.s3.bucket_exists(s3_resource, bucket)

Parameters:

  • s3_resource (mypy_boto3_s3.S3ServiceResource)
  • bucket (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: Union[bool (/usr/share/doc/python3/html/library/functions.html#bool), mypy_boto3_s3.service_resource.Bucket]

  • toil.lib.aws.s3.head_s3_object(bucket, key, header, region=None)

Attempt to HEAD an s3 object and return its response. ๐Ÿ‘€

Parameters:

  • bucket (str (/usr/share/doc/python3/html/library/stdtypes.html#str)) -- AWS bucket name
  • key (str (/usr/share/doc/python3/html/library/stdtypes.html#str)) -- AWS Key name for the s3 object
  • header (Dict[str, Any]) โ€” the headers to include, mostly for encryption stuff ๐Ÿ”. There's a boto3 head_object reference page at boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3/client/head_object.html if you want the full tea ๐Ÿต
  • region (Optional[str]) โ€” the region where we want to look for the bucket ๐ŸŒธ

Return type: mypy_boto3_s3.type_defs.HeadObjectOutputTypeDef โœจ


โœจ toil.lib.aws.s3.list_multipart_uploads โœจ

toil.lib.aws.s3.list_multipart_uploads(bucket, region, prefix, max_uploads=1)
  • bucket (str) ๐Ÿชฃ
  • region (str) ๐Ÿ—บ๏ธ
  • prefix (str) ๐Ÿท๏ธ
  • max_uploads (int) โ€” defaults to 1 ๐Ÿ”ข

Return type: mypy_boto3_s3.type_defs.ListMultipartUploadsOutputTypeDef ๐Ÿ’–


โœจ toil.lib.aws.s3.copy_s3_to_s3 โœจ

toil.lib.aws.s3.copy_s3_to_s3(s3_resource, src_bucket, src_key, dst_bucket, dst_key, extra_args=None)
  • s3_resource (mypy_boto3_s3.S3ServiceResource) ๐Ÿงš
  • src_bucket (str) ๐Ÿ“ฆ
  • src_key (str) ๐Ÿ”‘
  • dst_bucket (str) ๐Ÿ“ฆ
  • dst_key (str) ๐Ÿ”‘
  • extra_args (Optional[Dict[Any, Any]]) โ€” defaults to None ๐ŸŽ€

Return type: None ๐Ÿซถ


โœจ toil.lib.aws.s3.copy_local_to_s3 โœจ

toil.lib.aws.s3.copy_local_to_s3(s3_resource, local_file_path, dst_bucket, dst_key, extra_args=None)
  • s3_resource (mypy_boto3_s3.S3ServiceResource) ๐Ÿงš
  • local_file_path (str) ๐Ÿ’ป
  • dst_bucket (str) ๐Ÿ“ฆ
  • dst_key (str) ๐Ÿ”‘
  • extra_args (Optional[Dict[Any, Any]]) โ€” defaults to None ๐ŸŽ€

Return type: None ๐Ÿซถ


โœจ toil.lib.aws.s3.copy_s3_to_local โœจ

toil.lib.aws.s3.copy_s3_to_local(s3_resource, local_file_path, src_bucket, src_key, extra_args=None)
  • s3_resource (mypy_boto3_s3.S3ServiceResource) ๐Ÿงš
  • local_file_path (str) ๐Ÿ’ป
  • src_bucket (str) ๐Ÿ“ฆ
  • src_key (str) ๐Ÿ”‘
  • extra_args (Optional[Dict[Any, Any]]) โ€” defaults to None ๐ŸŽ€

Return type: None ๐Ÿซถ


โœจ class toil.lib.aws.s3.MultiPartPipe โœจ

class toil.lib.aws.s3.MultiPartPipe(part_size, s3_resource, bucket_name, file_id, encryption_args, encoding=None, errors=None)

Bases: toil.lib.pipes.WritablePipe ๐Ÿฆ‹

okay so this class is an object-oriented wrapper for os.pipe and it is so clean ๐Ÿงผ. You subclass it, implement readFrom() to consume the readable end of the pipe, and then instantiate the class as a context manager to get the writable end. Here's the vibe:

>>> import sys, shutil, codecs
>>> class MyPipe(WritablePipe):
...     def readFrom(self, readable):
...         shutil.copyfileobj(codecs.getreader('utf-8')(readable), sys.stdout)
>>> with MyPipe() as writable:
...     _ = writable.write('Hello, world!\n'.encode('utf-8'))
Hello, world!

Each instance creates a thread and invokes the readFrom method in that thread ๐Ÿงต. The thread gets join()ed upon normal exit from the context manager, which means the body of the with statement finishing up nicely ๐Ÿ’…. If an exception occurs, the thread will not be joined, but a well-behaved readFrom() implementation will terminate shortly thereafter because the pipe has been closed ๐Ÿซ .

Now, exceptions in the reader thread get reraised in the main thread, so you won't be left wondering what went wrong ๐Ÿ‘€:

>>> class MyPipe(WritablePipe):
...     def readFrom(self, readable):
...         raise RuntimeError('Hello, world!')
>>> with MyPipe() as writable:
...     pass
Traceback (most recent call last):
...
RuntimeError: Hello, world!

More complicated, less illustrative tests (bestie, these are the nerdy ones ๐Ÿค“):

Same as above, but proving that handles are closed:

>>> x = os.dup(0); os.close(x)
>>> class MyPipe(WritablePipe):
...     def readFrom(self, readable):
...         raise RuntimeError('Hello, world!')
>>> with MyPipe() as writable:
...     pass
Traceback (most recent call last):
...
RuntimeError: Hello, world!
>>> y = os.dup(0); os.close(y); x == y
True

Exceptions in the body of the with statement aren't masked, and handles are closed too ๐Ÿ™Œ:

>>> x = os.dup(0); os.close(x)
>>> class MyPipe(WritablePipe):
...     def readFrom(self, readable):
...         pass
>>> with MyPipe() as writable:
...     raise RuntimeError('Hello, world!')
Traceback (most recent call last):
...
RuntimeError: Hello, world!
>>> y = os.dup(0); os.close(y); x == y
True

Parameters ๐ŸŽ€

  • part_size (int) ๐Ÿ“
  • s3_resource (mypy_boto3_s3.S3ServiceResource) ๐Ÿงš
  • bucket_name (str) ๐Ÿ“ฆ
  • file_id (str) ๐Ÿ†”
  • encryption_args (Optional[Dict[Any, Any]]) ๐Ÿ”
  • encoding (Optional[str]) ๐Ÿ”ค
  • errors (Optional[str]) โš ๏ธ

Class attributes ๐ŸŒˆ

  • encoding = None
  • errors = None
  • part_size
  • s3_client
  • bucket_name
  • file_id
  • encryption_args

โœจ readFrom(readable) โœจ

Implement this method to read data from the pipe ๐Ÿ“–. It should support both binary and text mode output, so make it work for both bestie ๐Ÿ’œ.

  • readable (file) โ€” the file object representing the readable end of the pipe. Do not explicitly invoke the close() method of the object, because that gets done automatically ๐Ÿ™…โ€โ™€๏ธ.

Return type: None ๐Ÿซถ


โœจ toil.lib.aws.s3.parse_s3_uri โœจ

toil.lib.aws.s3.parse_s3_uri(uri)
  • uri (str) ๐Ÿ—บ๏ธ

Return type: Tuple[str, str] ๐Ÿ’…


โœจ toil.lib.aws.s3.list_s3_items โœจ

toil.lib.aws.s3.list_s3_items(s3_resource, bucket, prefix, startafter=None)
  • s3_resource (mypy_boto3_s3.S3ServiceResource) ๐Ÿงš
  • bucket (str) ๐Ÿ“ฆ
  • prefix (str) ๐Ÿท๏ธ
  • startafter (Optional[str]) โ€” defaults to None โญ๏ธ

Return type: Iterator[mypy_boto3_s3.type_defs.ObjectTypeDef] ๐Ÿ”


โœจ toil.lib.aws.s3.upload_to_s3 โœจ

toil.lib.aws.s3.upload_to_s3(readable, s3_resource, bucket, key, extra_args=None)

Upload a readable object to S3, using multipart uploading if applicable ๐Ÿš€.

  • readable (IO[Any]) โ€” a readable stream or a local file path to upload to S3 ๐Ÿ“ค
  • resource (S.Resource) โ€” boto3 resource ๐Ÿงš
  • bucket (str) โ€” name of the bucket to upload to ๐Ÿ“ฆ
  • key (str) โ€” the name of the file to upload to ๐Ÿ”‘
  • extra_args (dict) โ€” HTTP headers to use when uploading, generally used for encryption purposes ๐Ÿ”
  • partSize (int) โ€” max size of each part in the multipart upload, in bytes ๐Ÿ“
  • s3_resource (mypy_boto3_s3.S3ServiceResource) ๐Ÿงš

Returns: version of the newly uploaded file โœจ

Return type: None ๐Ÿซถ


โœจ toil.lib.aws.s3.download_stream โœจ

toil.lib.aws.s3.download_stream(s3_resource, bucket, key, checksum_to_verify=None, extra_args=None, encoding=None, errors=None)

Context manager that gives out a download stream to download data ๐Ÿ“ฅ.

  • s3_resource (mypy_boto3_s3.S3ServiceResource) ๐Ÿงš
  • bucket (str) ๐Ÿ“ฆ
  • key (str) ๐Ÿ”‘
  • checksum_to_verify (Optional[str]) โ€” defaults to None โœ…
  • extra_args (Optional[Dict[Any, Any]]) โ€” defaults to None ๐ŸŽ€
  • encoding (Optional[str]) โ€” defaults to None ๐Ÿ”ค
  • errors (Optional[str]) โ€” defaults to None โš ๏ธ

Return type: Iterator[IO[Any]] ๐Ÿ”


โœจ toil.lib.aws.s3.download_fileobject โœจ

toil.lib.aws.s3.download_fileobject(s3_resource, bucket, key, fileobj, extra_args=None)
  • s3_resource (mypy_boto3_s3.S3ServiceResource) ๐Ÿงš
  • bucket (mypy_boto3_s3.service_resource.Bucket) ๐Ÿ“ฆ
  • key (str) ๐Ÿ”‘
  • fileobj (io.BytesIO </usr/share/doc/python3/html/library/io.html#io.BytesIO>) ๐Ÿงš
  • extra_args (Optional[Dict[Any, Any]]) ๐ŸŽ€

Return type: None ๐Ÿ’–


๐Ÿ”Ž toil.lib.aws.s3.s3_key_exists ๐Ÿ”Ž

Okay bestie, this one is the "does this thing even exist?" check ๐Ÿ‘€ It gives back True if the s3 object is there and False if not. Heads up though, it will error if your encryption args are incorrect ๐Ÿ’€

toil.lib.aws.s3.s3_key_exists(s3_resource, bucket, key, check=False, extra_args=None)

Parameters

  • s3_resource (mypy_boto3_s3.S3ServiceResource) โœจ
  • bucket (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿชฃ
  • key (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿ”‘
  • check (bool </usr/share/doc/python3/html/library/functions.html#bool>) ๐Ÿง
  • extra_args (Optional[Dict[Any, Any]]) ๐ŸŽ€

Return type: bool </usr/share/doc/python3/html/library/functions.html#bool> ๐Ÿ’…


๐Ÿช„ toil.lib.aws.s3.get_s3_object ๐Ÿช„

This one is the "go grab me the object" move ๐Ÿงบ

toil.lib.aws.s3.get_s3_object(s3_resource, bucket, key, extra_args=None)

Parameters

  • s3_resource (mypy_boto3_s3.S3ServiceResource) โœจ
  • bucket (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿชฃ
  • key (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿ”‘
  • extra_args (Optional[Dict[Any, Any]]) ๐ŸŽ€

Return type: mypy_boto3_s3.type_defs.GetObjectOutputTypeDef ๐Ÿ‘‘


๐Ÿ“ฆ toil.lib.aws.s3.put_s3_object ๐Ÿ“ฆ

The "drop it in the bucket" energy ๐Ÿซถ

toil.lib.aws.s3.put_s3_object(s3_resource, bucket, key, body, extra_args=None)

Parameters

  • s3_resource (mypy_boto3_s3.S3ServiceResource) โœจ
  • bucket (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿชฃ
  • key (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿ”‘
  • body (Union[str </usr/share/doc/python3/html/library/stdtypes.html#str>, bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes>]) ๐Ÿ“
  • extra_args (Optional[Dict[Any, Any]]) ๐ŸŽ€

Return type: mypy_boto3_s3.type_defs.PutObjectOutputTypeDef ๐Ÿ’œ


๐Ÿ”— toil.lib.aws.s3.generate_presigned_url ๐Ÿ”—

toil.lib.aws.s3.generate_presigned_url(s3_resource, bucket, key_name, expiration)

Parameters

  • s3_resource (mypy_boto3_s3.S3ServiceResource) โœจ
  • bucket (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿชฃ
  • key_name (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿ”‘
  • expiration (int </usr/share/doc/python3/html/library/functions.html#int>) โณ

Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str> ๐Ÿฆ‹


๐ŸŒ toil.lib.aws.s3.create_public_url ๐ŸŒ

toil.lib.aws.s3.create_public_url(s3_resource, bucket, key)

Parameters

  • s3_resource (mypy_boto3_s3.S3ServiceResource) โœจ
  • bucket (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿชฃ
  • key (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿ”‘

Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str> ๐ŸŒˆ


๐Ÿ—บ๏ธ toil.lib.aws.s3.get_s3_bucket_region ๐Ÿ—บ๏ธ

toil.lib.aws.s3.get_s3_bucket_region(s3_resource, bucket)

Parameters

  • s3_resource (mypy_boto3_s3.S3ServiceResource) โœจ
  • bucket (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿชฃ

Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str> โญ


๐ŸŒธ toil.lib.aws.session ๐ŸŒธ

๐ŸŽ€ Attributes ๐ŸŽ€

  • logger ๐Ÿ“
  • ANONYMOUS_CONFIG ๐Ÿ™ˆ

๐Ÿง Classes ๐Ÿง

  • AWSConnectionManager โ€” a class that represents a connection to AWS and caches Boto 3 and Boto 2 objects ๐Ÿ’–

๐Ÿ› ๏ธ Functions ๐Ÿ› ๏ธ

  • establish_boto3_session([region_name]) โ€” gets a Boto 3 session that the current thread can use ๐Ÿงš
  • client(โ€ฆ) โ€” gets a Boto 3 client for a particular AWS service, usable by the current thread ๐Ÿฆ‹
  • resource(โ€ฆ) โ€” gets a Boto 3 resource for a particular AWS service, usable by the current thread ๐Ÿ’…

๐Ÿ“š Module Contents ๐Ÿ“š

  • toil.lib.aws.session.logger
  • toil.lib.aws.session.ANONYMOUS_CONFIG
  • class toil.lib.aws.session.AWSConnectionManager

Okay so this class is literally the connection hub ๐Ÿ‘‘ It represents a connection to AWS and caches Boto 3 and Boto 2 objects by region โœจ

Anytime you want an item, you go through the method for the thing you want (session, resource, service, Boto2 Context) and then pass in the region you want to work in, plus the type of thing you want if it applies ๐Ÿ’…

This class is meant to eventually enable multi-region clusters, where connections to several regions might need to be managed in the same provisioner ๐ŸŒˆ

We also support None for a region. In that case no region gets passed to Boto or Boto3, so the caller is responsible for implementing things like TOIL_AWS_REGION support ๐Ÿซถ

Connection objects may not be thread safe, so one is created for each thread that calls the relevant lookup method ๐Ÿ™ˆ See https://boto3.amazonaws.com/v1/documentation/api/1.14.31/guide/session.html#multithreading-or-multiprocessing-with-sessions for the details.

Attributes of the class

sessions_by_region: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, threading.local </usr/share/doc/python3/html/library/threading.html#threading.local>]

resource_cache: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>], threading.local </usr/share/doc/python3/html/library/threading.html#threading.local>]

client_cache: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>], threading.local </usr/share/doc/python3/html/library/threading.html#threading.local>]

boto2_cache: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, str </usr/share/doc/python3/html/library/stdtypes.html#str>], threading.local </usr/share/doc/python3/html/library/threading.html#threading.local>]

session(region) ๐ŸŒค๏ธ

Gets the Boto3 Session to use for the given region โœจ

Parameters

  • region (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]) ๐Ÿ—บ๏ธ

Return type: boto3.session.Session ๐Ÿ’œ

resource(...) ๐Ÿงฉ

resource(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['s3'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_s3.S3ServiceResource

โœจ API REFERENCE, continued โœจ

okay so the resource methods are up next and they're giving whole main character energy ๐Ÿฆ‹ Each one takes a service_name and hands you back a Boto3 resource object for that service ๐Ÿ’…

resource(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['iam'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_iam.IAMServiceResource

resource(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['ec2'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_ec2.EC2ServiceResource

Get the Boto3 Resource to use with the given service (like 'ec2') in the given region. ๐ŸŒธ

Parameters

  • endpoint_url โ€” AWS endpoint URL to use for the client. If not specified, a default is used. ๐Ÿซถ

Next up are the client methods, which are the same vibe but hand you a client instead of a resource ๐Ÿ’œ Pick your service_name and you're set โœจ

client(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['ec2'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_ec2.EC2Client

client(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['iam'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_iam.IAMClient

client(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['s3'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_s3.S3Client

client(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['sts'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_sts.STSClient

client(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['sdb'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_sdb.SimpleDBClient

client(region: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>, service_name: Literal['autoscaling'], endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_autoscaling.AutoScalingClient

Get the Boto3 Client to use with the given service (like 'ec2') in the given region. ๐ŸŽ€

Parameters

  • endpoint_url โ€” AWS endpoint URL to use for the client. If not specified, a default is used. ๐Ÿฆ‹
  • config โ€” Custom configuration to use for the client. โญ

toil.lib.aws.session

Now we're in the session module, and this one's a whole mood ๐ŸŒˆ

establish_boto3_session

toil.lib.aws.session.establish_boto3_session(region_name=None)

Get a Boto 3 session usable by the current thread. Heads up bestie: this function may not always establish a brand-new session, because it can be memoized ๐Ÿงš

Parameters

  • region_name (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]) โ€” the page doesn't describe this one any further ๐Ÿ™ˆ

Return type

  • boto3.Session ๐Ÿ’–

client

These are the module-level version of the client methods. They're the global alternative to AWSConnectionManager, and they're usable by the current thread ๐Ÿซถ

toil.lib.aws.session.client(service_name: Literal['ec2'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_ec2.EC2Client

toil.lib.aws.session.client(service_name: Literal['iam'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_iam.IAMClient

toil.lib.aws.session.client(service_name: Literal['s3'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_s3.S3Client

toil.lib.aws.session.client(service_name: Literal['sts'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_sts.STSClient

toil.lib.aws.session.client(service_name: Literal['sdb'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_sdb.SimpleDBClient

toil.lib.aws.session.client(service_name: Literal['autoscaling'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_autoscaling.AutoScalingClient

Get a Boto 3 client for a particular AWS service, usable by the current thread. ๐Ÿ’…

resource

And the module-level resource version, which is also a global alternative to AWSConnectionManager and usable by the current thread โœจ

toil.lib.aws.session.resource(service_name: Literal['s3'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_s3.S3ServiceResource

toil.lib.aws.session.resource(service_name: Literal['iam'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_iam.IAMServiceResource

toil.lib.aws.session.resource(service_name: Literal['ec2'], region_name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, endpoint_url: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, config: botocore.client.Config | None </usr/share/doc/python3/html/library/constants.html#None> = None) -> mypy_boto3_ec2.EC2ServiceResource

Get a Boto 3 resource for a particular AWS service, usable by the current thread. ๐Ÿฆ‹


toil.lib.aws.utils

Last stop on this part: the utils module ๐ŸŒธ

Attributes

  • logger โ€” the page leaves this one blank, so no details yet ๐Ÿ™ˆ
  • THROTTLED_ERROR_CODES โ€” the page leaves this one blank too ๐Ÿ’€

๐Ÿ’… Exceptions

  • NoBucketLocationError โ€” okay so this is the error that shows up when we literally could not get a location for a bucket ๐Ÿ˜ญ

๐Ÿ”ฅ Functions

  • delete_sdb_domain(sdb_domain_name[, region, quiet]) โ€” no description for this one, bestie ๐Ÿ™ˆ
  • connection_reset(e) โ€” returns true if an error is a connection reset error ๐Ÿ”Œ
  • connection_error(e) โ€” returns True if an error represents a failure to make a network connection ๐ŸŒ
  • retryable_s3_errors(e) โ€” returns true if this is an S3 error that looks like we ought to retry our request ๐Ÿ”
  • retry_s3([delays, timeout, predicate]) โ€” a retry iterator of context managers, specifically for S3 operations ๐Ÿ’œ
  • delete_s3_bucket(s3_resource, bucket[, quiet]) โ€” deletes the given S3 bucket ๐Ÿ—‘๏ธ
  • create_s3_bucket(s3_resource, bucket_name, region) โ€” creates an AWS S3 bucket using the given Boto3 S3 session, with the... (the docs trail off right there, bestie ๐Ÿ’€)
  • enable_public_objects(bucket_name) โ€” lets a bucket hold objects that are public ๐ŸŒ
  • get_bucket_region(bucket_name[, endpoint_url, ...]) โ€” gets the AWS region name associated with the given S3 bucket, or raises NoBucketLocationError โœจ
  • get_bucket_region_if_available(bucket_name[, ...]) โ€” gets the AWS region name associated with the given S3 bucket, or returns None ๐ŸŽ€
  • region_to_bucket_location(region) โ€” no description here either, bestie ๐Ÿ™ˆ
  • bucket_location_to_region(location) โ€” also no description, the docs are giving mysterious ๐Ÿ•ต๏ธ
  • get_object_for_url(url[, existing, anonymous]) โ€” extracts a key (object) from a given parsed s3:// URL ๐Ÿงš
  • list_objects_for_url(url[, anonymous]) โ€” extracts a key (object) from a given parsed s3:// URL. The URL will be... (and the docs stop mid-sentence, not me being messy ๐Ÿ˜ญ)
  • flatten_tags(tags) โ€” converts tags from a key-to-value dict into a list of 'Key': xxx, 'Value': xxx dicts ๐Ÿท๏ธ
  • boto3_pager(requestor_callable, result_attribute_name, ...) โ€” yields all the results from calling the given Boto 3 method with the (cut off again, the docs be like "with the" ๐Ÿ’€)

๐ŸŒˆ Module Contents

  • toil.lib.aws.utils.logger โ€” a logger just chilling in the module ๐Ÿชต
  • toil.lib.aws.utils.THROTTLED_ERROR_CODES = ['Throttling', 'ThrottlingException', 'ThrottledException', 'RequestThrottledException',... โ€” the list of "slow down" error codes, lowkey iconic ๐Ÿข

๐ŸŒธ toil.lib.aws.utils.delete_sdb_domain

toil.lib.aws.utils.delete_sdb_domain(sdb_domain_name, region=None, quiet=True)

Parameters

  • sdb_domain_name (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • region (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>])
  • quiet (bool </usr/share/doc/python3/html/library/functions.html#bool>)

Return type: None

๐ŸŒธ toil.lib.aws.utils.connection_reset

toil.lib.aws.utils.connection_reset(e)

Returns true if the error is a connection reset error, periodt ๐Ÿ”Œ

Parameters

  • e (Exception </usr/share/doc/python3/html/library/exceptions.html#Exception>)

Return type: bool </usr/share/doc/python3/html/library/functions.html#bool>

๐ŸŒธ toil.lib.aws.utils.connection_error

toil.lib.aws.utils.connection_error(e)

Returns True if the error represents a failure to make a network connection ๐ŸŒ

Parameters

  • e (Exception </usr/share/doc/python3/html/library/exceptions.html#Exception>)

Return type: bool </usr/share/doc/python3/html/library/functions.html#bool>

๐ŸŒธ toil.lib.aws.utils.retryable_s3_errors

toil.lib.aws.utils.retryable_s3_errors(e)

Returns true if this is an S3 error that looks like we ought to retry our request. It's giving "try again, bestie" ๐Ÿ”

Parameters

  • e (Exception </usr/share/doc/python3/html/library/exceptions.html#Exception>)

Return type: bool </usr/share/doc/python3/html/library/functions.html#bool>

๐ŸŒธ toil.lib.aws.utils.retry_s3

toil.lib.aws.utils.retry_s3(delays=DEFAULT_DELAYS, timeout=DEFAULT_TIMEOUT, predicate=retryable_s3_errors)

A retry iterator of context managers, specifically for S3 operations ๐Ÿ’œ

Parameters

  • delays (collections.abc.Iterable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterable>[float </usr/share/doc/python3/html/library/functions.html#float>])
  • timeout (float </usr/share/doc/python3/html/library/functions.html#float>)
  • predicate (Callable[[Exception </usr/share/doc/python3/html/library/exceptions.html#Exception>], bool </usr/share/doc/python3/html/library/functions.html#bool>])

Return type: collections.abc.Iterator </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterator>[ContextManager[None]]

๐ŸŒธ toil.lib.aws.utils.delete_s3_bucket

toil.lib.aws.utils.delete_s3_bucket(s3_resource, bucket, quiet=True)

Deletes the given S3 bucket ๐Ÿ—‘๏ธ

โš ๏ธ bestie, read this part: S3 bucket deletion is only eventually-consistent, and anyone can register any S3 bucket name. For both of these reasons, a bucket name might not be immediately (or ever) available for re-use after this function returns.

Parameters

๐Ÿชฃ toil.lib.aws.utils.create_s3_bucket

toil.lib.aws.utils.create_s3_bucket(s3_resource, bucket_name, region)

Okay so this one makes an AWS S3 bucket ๐Ÿชฃโœจ You give it a Boto3 S3 session, a name, and a region, and it creates a bucket with that name in that region. Iconic.

It supports the us-east-1 region, where bucket creation is special ๐Ÿ™ˆ so bestie, keep that in mind.

ALL S3 bucket creation should use this function. Like, all of it ๐Ÿ’…

Parameters

  • s3_resource (mypy_boto3_s3.S3ServiceResource)
  • bucket_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • region (toil.lib.aws.AWSRegionName)

Return type mypy_boto3_s3.service_resource.Bucket ๐ŸŽ


๐Ÿ”“ toil.lib.aws.utils.enable_public_objects

toil.lib.aws.utils.enable_public_objects(bucket_name)

Lowkey the most dramatic one ๐ŸŽญ This makes a bucket able to hold objects that are public. It changes the bucket's Public Access Block setting so it doesn't block all public access, and it changes the bucket's Object Ownership setting to one that enables object ACLs ๐Ÿ”“

It does not touch the account's Public Access Block setting, which can also interfere here. That's probably best left to the account administrator ๐Ÿ™…

This configuration used to be the default, and it's what most of Toil's code is written to expect ๐Ÿซถ But it got changed so new buckets default to the more restrictive setting https://aws.amazon.com/about-aws/whats-new/2022/12/amazon-s3-automatically-enable-block-public-access-disable-access-control-lists-buckets-april-2023/, with the expectation that people would write IAM policies for the buckets to allow public access if needed. Toil expects to be able to make arbitrary objects in arbitrary places public, and naming them all in an IAM policy would be a very awkward way to do it. So we restore the old behavior ๐Ÿ”

Parameters

  • bucket_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type None


๐Ÿ’ฅ exception toil.lib.aws.utils.NoBucketLocationError

exception toil.lib.aws.utils.NoBucketLocationError

Bases Exception (see /usr/share/doc/python3/html/library/exceptions.html#Exception)

This is the error for when we couldn't figure out a location for a bucket ๐Ÿ˜ญ


๐Ÿ—บ๏ธ toil.lib.aws.utils.get_bucket_region

toil.lib.aws.utils.get_bucket_region(bucket_name, endpoint_url=None,
only_strategies=None, anonymous=None)

Gets the AWS region name for the given S3 bucket, or raises NoBucketLocationError ๐Ÿ™ƒ

It doesn't log at info level or above when this doesn't work, since failures are totally expected in some contexts ๐Ÿคท It also takes an optional S3 API URL override.

Parameters

  • only_strategies (Optional[set[int]], see /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/functions.html#int) โ€” for testing, use only strategies with 1-based numbers in this set ๐Ÿงช
  • bucket_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • endpoint_url (Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • anonymous (Optional[bool], see /usr/share/doc/python3/html/library/functions.html#bool)

Raises

  • toil.lib.aws.utils.NoBucketLocationError โ€” if the bucket's region can't be determined (possibly due to lack of permissions) ๐Ÿšซ

Return type str (see /usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ—บ๏ธ toil.lib.aws.utils.get_bucket_region_if_available

toil.lib.aws.utils.get_bucket_region_if_available(bucket_name,
endpoint_url=None, only_strategies=None, anonymous=None)

Same vibe as the one above, but if it can't find the region it just returns None ๐ŸŒธ

It caches results, so it might not return the location for a bucket that's been created but was previously seen as nonexistent. Main character glitch ๐Ÿ‘€

Parameters

  • only_strategies (Optional[set[int]], see /usr/share/doc/python3/html/library/stdtypes.html#set and /usr/share/doc/python3/html/library/functions.html#int) โ€” for testing, use only strategies with 1-based numbers in this set ๐Ÿงช
  • bucket_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • endpoint_url (Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • anonymous (Optional[bool], see /usr/share/doc/python3/html/library/functions.html#bool)

Return type Optional[str] (see /usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ” toil.lib.aws.utils.region_to_bucket_location

toil.lib.aws.utils.region_to_bucket_location(region)

Parameters

  • region (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type str (see /usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ” toil.lib.aws.utils.bucket_location_to_region

toil.lib.aws.utils.bucket_location_to_region(location)

Parameters

  • location (Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type str (see /usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ”— toil.lib.aws.utils.get_object_for_url

toil.lib.aws.utils.get_object_for_url(url, existing=None,
anonymous=None)

Pulls out a key (object) from a given parsed s3:// URL ๐Ÿ”

If existing is true and the object doesn't exist, this raises FileNotFoundError ๐Ÿ˜ฌ

Parameters

  • existing (bool, see /usr/share/doc/python3/html/library/functions.html#bool) โ€” if True, the key is expected to exist. If False, the key is expected not to exist, and it'll be created. If None, the key gets created if it doesn't already exist ๐Ÿง 
  • url (urllib.parse.ParseResult, see /usr/share/doc/python3/html/library/urllib.parse.html#urllib.parse.ParseResult)
  • anonymous (Optional[bool], see /usr/share/doc/python3/html/library/functions.html#bool)

Raises

  • FileNotFoundError (see /usr/share/doc/python3/html/library/exceptions.html#FileNotFoundError) โ€” when existing is True and the object doesn't exist ๐Ÿ‘ป
  • RuntimeError (see /usr/share/doc/python3/html/library/exceptions.html#RuntimeError) โ€” when existing is False but the object does exist ๐Ÿ’€
  • PermissionError (see /usr/share/doc/python3/html/library/exceptions.html#PermissionError) โ€” when we aren't authorized to look at the object ๐Ÿ”’

Return type mypy_boto3_s3.service_resource.Object


๐Ÿ“‹ toil.lib.aws.utils.list_objects_for_url

toil.lib.aws.utils.list_objects_for_url(url, anonymous=None)

Pulls out a key (object) from a given parsed s3:// URL. If the URL is missing a trailing slash, one gets added for you ๐Ÿช„

Raises

  • PermissionError (see /usr/share/doc/python3/html/library/exceptions.html#PermissionError) โ€” when we aren't authorized to do the list operation ๐Ÿ™…

Parameters

  • url (urllib.parse.ParseResult, see /usr/share/doc/python3/html/library/urllib.parse.html#urllib.parse.ParseResult)
  • anonymous (Optional[bool], see /usr/share/doc/python3/html/library/functions.html#bool)

Return type list[str] (see /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿท๏ธ toil.lib.aws.utils.flatten_tags

toil.lib.aws.utils.flatten_tags(tags)

Converts tags from a key-to-value dict into a list of 'Key': xxx, 'Value': xxx dicts ๐Ÿท๏ธโœจ

Parameters

  • tags (dict[str, str], see /usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type list[dict[Union[Literal['Key'], Literal['Value']], str]] (see /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#dict)


๐Ÿ”„ toil.lib.aws.utils.boto3_pager

toil.lib.aws.utils.boto3_pager(requestor_callable,
result_attribute_name, **kwargs)

This one yields all the results from calling the given Boto3 method with the given keyword arguments ๐ŸŒŠ It pages through the results using the Marker or NextToken, then fetches out and loops over the list in the response with the given attribute name. So you never miss a single one ๐Ÿ’–

Parameters

  • requestor_callable (Callable[Ellipsis, Any])
  • result_attribute_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • kwargs (Any)

Return type collections.abc.Iterable[Any] (see /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterable)


โœจ Attributes โœจ

Here's the lineup ๐Ÿ‘‘

  • AWSRegionName
  • AWSServerErrors
  • logger

โœจ Functions โœจ

okay bestie, here's the whole AWS zone squad at a glance ๐Ÿ’…

  • get_current_aws_region() โ€” returns the AWS region that the currently configured AWS zone (see get_current_aws_zone()) is in ๐Ÿ’–
  • get_aws_zone_from_environment() โ€” grabs the AWS zone from TOIL_AWS_ZONE if it's set ๐ŸŒธ
  • get_aws_zone_from_metadata() โ€” gets the zone from instance metadata if you're on EC2 and the boto module is available. Otherwise it checks ECS task metadata, if you're on ECS โœจ
  • get_aws_zone_from_boto() โ€” gets the zone from the Boto3 config file or from AWS_DEFAULT_REGION, if it's configured and the boto3 module is available ๐ŸŽ€
  • get_aws_zone_from_environment_region() โ€” picks an AWS zone in the region defined by TOIL_AWS_REGION, if it's set ๐Ÿงš
  • get_current_aws_zone() โ€” gets the currently configured or occupied AWS zone to use ๐Ÿ‘‘
  • zone_to_region(zone) โ€” gets a region (e.g. us-west-2) from a zone (e.g. us-west-1c) ๐Ÿฆ‹
  • running_on_ec2() โ€” returns True if we're running on EC2, and false otherwise ๐ŸŒˆ
  • running_on_ecs() โ€” returns True if we're running on Amazon ECS, and false otherwise ๐Ÿ’œ
  • build_tag_dict_from_env([environment]) โ€” no summary given for this one, so the details below are your best friend ๐Ÿ™ˆ

โœจ Package Contents โœจ

the goods, all in toil.lib.aws:

  • toil.lib.aws.AWSRegionName
  • toil.lib.aws.AWSServerErrors
  • toil.lib.aws.logger

toil.lib.aws.get_current_aws_region()

Return the AWS region that the currently configured AWS zone (see get_current_aws_zone()) is in. It's giving "find my region" energy ๐Ÿ’–

  • Return type: Optional[str] (see /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.aws.get_aws_zone_from_environment()

Get the AWS zone from TOIL_AWS_ZONE if set. Simple and iconic ๐ŸŒธ

  • Return type: Optional[str] (see /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.aws.get_aws_zone_from_metadata()

Get the AWS zone from instance metadata, if on EC2 and the boto module is available. Otherwise, gets the AWS zone from ECS task metadata, if on ECS. Multi-platform queen behavior โœจ

  • Return type: Optional[str] (see /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.aws.get_aws_zone_from_boto()

Get the AWS zone from the Boto3 config file or from AWS_DEFAULT_REGION, if it is configured and the boto3 module is available ๐ŸŽ€

  • Return type: Optional[str] (see /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.aws.get_aws_zone_from_environment_region()

Pick an AWS zone in the region defined by TOIL_AWS_REGION, if it is set ๐Ÿงš

  • Return type: Optional[str] (see /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.aws.get_current_aws_zone()

Get the currently configured or occupied AWS zone to use. This is the main character of the whole group ๐Ÿ‘‘

Reports the TOIL_AWS_ZONE environment variable if set.

Otherwise, if we have boto and are running on EC2, or if we are on ECS, reports the zone we are running in.

Otherwise, if we have the TOIL_AWS_REGION variable set, chooses a zone in that region.

Finally, if we have boto2, and a default region is configured in Boto 2, chooses a zone in that region.

Returns 'us-east-1a' if no method can produce a zone to use. Lowkey the fallback era ๐Ÿ’€

  • Return type: Optional[str] (see /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.aws.zone_to_region(zone)

Get a region (e.g. us-west-2) from a zone (e.g. us-west-1c). Zone in, region out ๐Ÿฆ‹

  • Parameters: zone (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: AWSRegionName

toil.lib.aws.running_on_ec2()

Return True if we are currently running on EC2, and false otherwise. Yes or no, no drama ๐ŸŒˆ

  • Return type: bool (see /usr/share/doc/python3/html/library/functions.html#bool)

toil.lib.aws.running_on_ecs()

Return True if we are currently running on Amazon ECS, and false otherwise. Same energy, different cloud ๐Ÿ’œ

  • Return type: bool (see /usr/share/doc/python3/html/library/functions.html#bool)

toil.lib.aws.build_tag_dict_from_env(environment=os.environ)

  • Parameters: environment (collections.abc.MutableMapping[str, str], see /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.MutableMapping and /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: dict[str, str] (see /usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿฆ‹ toil.lib.bioio ๐Ÿฆ‹

โœจ Functions โœจ

  • system(command) โ€” a convenience wrapper around subprocess.check_call that logs the command before passing it along ๐ŸŒธ
  • getLogLevelString([logger]) โ€” no summary given, just vibes ๐Ÿ™ˆ
  • setLoggingFromOptions(options) โ€” no summary given, just vibes ๐Ÿ™ˆ
  • getTempFile([suffix, rootDir]) โ€” no summary given, just vibes ๐Ÿ™ˆ

โœจ Module Contents โœจ

toil.lib.bioio.system(command)

A convenience wrapper around subprocess.check_call that logs the command before passing it on. The command can be either a string or a sequence of strings. If it is a string shell=True will be passed to subprocess.check_call. Iconic wrapper behavior ๐Ÿ’–

:type command: str | sequence[string]

  • Parameters: command (list[str], see /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: None

toil.lib.bioio.getLogLevelString(logger=None)

toil.lib.bioio.setLoggingFromOptions(options)

toil.lib.bioio.getTempFile(suffix='', rootDir=None)

โœจ toil.lib.checksum โœจ

okay bestie, this module is all about hashing and checking that your files are exactly what they're supposed to be ๐Ÿ”๐Ÿ’œ let's go ๐Ÿ’…

๐Ÿชž Attributes ๐Ÿชž

  • logger ๐Ÿชต โ€” one of the module's attributes, just vibing
  • hashers ๐Ÿง โ€” the other attribute, also just vibing

๐Ÿšจ Exceptions ๐Ÿšจ

  • ChecksumError ๐Ÿ™…โ€โ™€๏ธ โ€” raised when a download does not contain the correct data. Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)

๐Ÿ’… Classes ๐Ÿ’…

  • Etag ๐Ÿงš โ€” a hasher for s3 etags

๐Ÿ› ๏ธ Functions ๐Ÿ› ๏ธ

  • compute_checksum_for_file(local_file_path[, algorithm]) ๐Ÿ“ โ€” no description given, but it's the one that works on a local file
  • compute_checksum_for_content(fh[, algorithm]) ๐ŸŒŠ โ€” Note: chunk size matters for s3 etags, and it must be the same to get the same hash from the same object. Therefore this buffer is not modifiable throughout Toil. Do not mess with this, it's not changeable ๐Ÿ™…โ€โ™€๏ธ

๐Ÿ“– Module Contents ๐Ÿ“–

toil.lib.checksum.logger

exception toil.lib.checksum.ChecksumError

Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)

Raised when a download does not contain the correct data. Sus download alert ๐Ÿšจ

class toil.lib.checksum.Etag(chunk_size)

A hasher for s3 etags.

Parameters: chunk_size (int, /usr/share/doc/python3/html/library/functions.html#int)

Attributes:

etag_bytes: int = 0
etag_parts: List[bytes] = []
etag_hasher: hashlib._Hash
chunk_size: int

Methods:

  • update(chunk) โ€” takes chunk (bytes, /usr/share/doc/python3/html/library/stdtypes.html#bytes) and returns None ๐Ÿซง
  • hexdigest() โ€” returns a str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ”ฅ

toil.lib.checksum.hashers

toil.lib.checksum.compute_checksum_for_file(local_file_path, algorithm='sha1')

Parameters:

  • local_file_path (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • algorithm (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.checksum.compute_checksum_for_content(fh, algorithm='sha1')

Note: chunk size matters for s3 etags, and must be the same to get the same hash from the same object. Therefore this buffer is not modifiable throughout Toil. ๐Ÿ”’

Parameters:

  • fh (Union[BinaryIO, io.BytesIO], /usr/share/doc/python3/html/library/io.html#io.BytesIO)
  • algorithm (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


โœจ toil.lib.compatibility โœจ

this one is the glue that keeps old and new Python friends ๐Ÿฆ‹

๐Ÿงฉ Functions ๐Ÿงฉ

  • deprecated(new_function_name) ๐Ÿ—‘๏ธ โ€” no description given
  • compat_bytes(s) ๐Ÿซง โ€” no description given
  • compat_bytes_recursive(data) ๐ŸŒณ โ€” convert a tree of objects over bytes to objects over strings

๐Ÿ“– Module Contents ๐Ÿ“–

toil.lib.compatibility.deprecated(new_function_name)

Parameters: new_function_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Callable[Ellipsis, Any]

toil.lib.compatibility.compat_bytes(s)

Parameters: s (Union[bytes, str], /usr/share/doc/python3/html/library/stdtypes.html#bytes, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.compatibility.compat_bytes_recursive(data)

Convert a tree of objects over bytes to objects over strings. ๐ŸŒฒโœจ

Parameters: data (Any)

Return type: Any


โœจ toil.lib.conversions โœจ

Conversion utilities for mapping memory, disk, and core declarations from strings to numbers and vice versa ๐Ÿงฎ. There are also general conversion functions in here too, so it's a whole vibe ๐Ÿ’–

๐ŸŽ€ Attributes ๐ŸŽ€

  • KIB ๐ŸŽ€
  • MIB ๐ŸŽ€
  • GIB ๐ŸŽ€
  • TIB ๐ŸŽ€
  • PIB ๐ŸŽ€
  • EIB ๐ŸŽ€
  • KB ๐ŸŒธ
  • MB ๐ŸŒธ
  • GB ๐ŸŒธ
  • TB ๐ŸŒธ
  • PB ๐ŸŒธ
  • EB ๐ŸŒธ
  • BINARY_PREFIXES ๐Ÿฆ‹ โ€” the binary prefix set
  • DECIMAL_PREFIXES ๐Ÿ“ โ€” the decimal prefix set
  • VALID_PREFIXES ๐Ÿ‘‘ โ€” the valid prefixes

๐Ÿ’– Functions ๐Ÿ’–

okay bestie, here's the whole function lineup ๐ŸŽ€ the table cuts off on a few of these, so I'm keeping them exactly as they're written ๐Ÿ˜ญ

  • bytes_in_unit([unit]) โ€” the table left this one's description blank ๐Ÿ™ˆ
  • convert_units(num, src_unit[, dst_unit]) โ€” returns a float with the converted input in dst_units โœจ
  • parse_memory_string(string) โ€” takes a string like '1024 Mib' and returns the ๐Ÿซถ
  • human2bytes(string) โ€” same vibe as above, takes a string like '1024 Mib' and returns the ๐Ÿ’…
  • bytes2human(n) โ€” turns a binary value into a human readable string with units ๐ŸŒธ
  • b_to_mib(n) โ€” converts a number from bytes to mibibytes ๐Ÿฆ‹
  • mib_to_b(n) โ€” converts a number from mibibytes to bytes ๐Ÿฆ‹
  • hms_duration_to_seconds(hms) โ€” parses a time string in hours:minutes:seconds โฐ
  • strtobool(val) โ€” makes a human-readable string into a bool ๐Ÿ”ฎ
  • opt_strtobool(b) โ€” converts an optional string representation of a bool to None or a bool ๐Ÿ’œ
  • modify_url(url, remove) โ€” given a valid URL string, it splits out the params and removes any offending ones ๐ŸŒˆ

๐ŸŒˆ Module Contents ๐ŸŒˆ

๐ŸŽ€ Size constants

  • toil.lib.conversions.KIB = 1024
  • toil.lib.conversions.MIB = 1048576
  • toil.lib.conversions.GIB = 1073741824
  • toil.lib.conversions.TIB = 1099511627776
  • toil.lib.conversions.PIB = 1125899906842624
  • toil.lib.conversions.EIB = 1152921504606846976
  • toil.lib.conversions.KB = 1000
  • toil.lib.conversions.MB = 1000000
  • toil.lib.conversions.GB = 1000000000
  • toil.lib.conversions.TB = 1000000000000
  • toil.lib.conversions.PB = 1000000000000000
  • toil.lib.conversions.EB = 1000000000000000000

๐Ÿงš Prefix lists

  • toil.lib.conversions.BINARY_PREFIXES = ['ki', 'mi', 'gi', 'ti', 'pi', 'ei', 'kib', 'mib', 'gib', 'tib', 'pib', 'eib']
  • toil.lib.conversions.DECIMAL_PREFIXES = ['b', 'k', 'm', 'g', 't', 'p', 'e', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb']
  • toil.lib.conversions.VALID_PREFIXES = ['ki', 'mi', 'gi', 'ti', 'pi', 'ei', 'kib', 'mib', 'gib', 'tib', 'pib', 'eib', 'b', 'k', 'm',...]

๐Ÿฆ‹ bytes_in_unit

toil.lib.conversions.bytes_in_unit(unit='B')

Parameters

  • unit (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

int </usr/share/doc/python3/html/library/functions.html#int>

โœจ convert_units

toil.lib.conversions.convert_units(num, src_unit, dst_unit='B')

Returns a float representing the converted input in dst_units. ๐Ÿ’–

Parameters

  • num (float </usr/share/doc/python3/html/library/functions.html#float>)
  • src_unit (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • dst_unit (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

float </usr/share/doc/python3/html/library/functions.html#float>

๐Ÿซถ parse_memory_string

toil.lib.conversions.parse_memory_string(string)

Given a string representation of some memory (i.e. '1024 Mib'), return the number and unit. ๐Ÿ’…

Parameters

  • string (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[float </usr/share/doc/python3/html/library/functions.html#float>, str </usr/share/doc/python3/html/library/stdtypes.html#str>]

๐Ÿ’… human2bytes

toil.lib.conversions.human2bytes(string)

Given a string representation of some memory (i.e. '1024 Mib'), return the integer number of bytes. ๐ŸŒธ

Parameters

  • string (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

int </usr/share/doc/python3/html/library/functions.html#int>

๐ŸŒธ bytes2human

toil.lib.conversions.bytes2human(n)

Return a binary value as a human readable string with units. ๐Ÿ“

Parameters

  • n (SupportsInt)

Return type

str </usr/share/doc/python3/html/library/stdtypes.html#str>

๐Ÿฆ‹ b_to_mib

toil.lib.conversions.b_to_mib(n)

Convert a number from bytes to mibibytes. ๐Ÿฆ‹

Parameters

  • n (Union[int </usr/share/doc/python3/html/library/functions.html#int>, float </usr/share/doc/python3/html/library/functions.html#float>])

Return type

float </usr/share/doc/python3/html/library/functions.html#float>

๐Ÿฆ‹ mib_to_b

toil.lib.conversions.mib_to_b(n)

Convert a number from mibibytes to bytes. ๐Ÿฆ‹

Parameters

  • n (Union[int </usr/share/doc/python3/html/library/functions.html#int>, float </usr/share/doc/python3/html/library/functions.html#float>])

Return type

float </usr/share/doc/python3/html/library/functions.html#float>

โฐ hms_duration_to_seconds

toil.lib.conversions.hms_duration_to_seconds(hms)

Parses a given time string in hours:minutes:seconds, returns an equivalent total seconds value. โฐ

Parameters

  • hms (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

float </usr/share/doc/python3/html/library/functions.html#float>

๐Ÿ”ฎ strtobool

toil.lib.conversions.strtobool(val)

Make a human-readable string into a bool. ๐Ÿ”ฎ

Convert a string along the lines of "y", "1", "ON", "TrUe", or "Yes" to True, and the corresponding false-ish values to False. ๐Ÿ™ˆ

Parameters

  • val (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

bool </usr/share/doc/python3/html/library/functions.html#bool>

๐Ÿ’œ opt_strtobool

toil.lib.conversions.opt_strtobool(b)

Convert an optional string representation of bool to None or bool. ๐Ÿ’œ

Parameters

  • b (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>])

Return type

Optional[bool </usr/share/doc/python3/html/library/functions.html#bool>]

๐ŸŒˆ modify_url

toil.lib.conversions.modify_url(url, remove)

Given a valid URL string, split out the params, remove any offending params in 'remove', and return the cleaned URL. ๐ŸŒˆ

Parameters

  • url (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • remove (List[str </usr/share/doc/python3/html/library/stdtypes.html#str>])

Return type

str </usr/share/doc/python3/html/library/stdtypes.html#str>


๐Ÿฆ‹ toil.lib.directory

๐Ÿ‘‘ Attributes

  • TOIL_DIR_URI_SCHEME โ€” listed with no value ๐Ÿซถ
  • DirectoryContents โ€” listed with no value ๐Ÿซถ

โœจ Functions โœจ

okay bestie, here's the whole lineup for the directory helpers ๐ŸŽ€ they all live in toil.lib.directory and they're basically all about toildir: paths ๐Ÿฆ‹

  • check_directory_dict_invariants(contents) โ€” makes sure a directory structure dict actually makes sense ๐Ÿ’… it throws an error if it doesn't
  • decode_directory(dir_path) โ€” decodes a directory from a "toildir:" path into a directory (or a file inside it) ๐ŸŒธ
  • encode_directory(contents[, name, source]) โ€” encodes a directory from a "toildir:" path into a directory (or a file inside it) โœจ
  • directory_item_exists(dir_path) โ€” checks that a URL to a Toil directory, or something inside it, is real ๐Ÿซถ
  • get_directory_contents_item(contents, remaining_path) โ€” grabs a subdirectory or file from a decoded directory plus the leftover path ๐Ÿ’œ
  • get_directory_item(dir_path) โ€” grabs a subdirectory or file from a URL that points to, or into, a toildir: directory ๐Ÿงš
  • directory_contents_items(contents) โ€” yields every file or directory under the given contents, including itself ๐Ÿ“
  • directory_items(dir_path) โ€” yields every file or directory under the given path, including itself ๐ŸŒˆ

โœจ Module Contents โœจ

bestie, quick heads up before we get into the details ๐Ÿ™ˆ the type links in this part go to the Python docs at /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#tuple, and /usr/share/doc/python3/html/library/functions.html#bool.

toil.lib.directory.TOIL_DIR_URI_SCHEME = 'toildir:'

this is the constant that holds the toildir: URI scheme ๐Ÿ’–

toil.lib.directory.DirectoryContents

this one's just listed as a name in the module, no extra details given โœจ

toil.lib.directory.check_directory_dict_invariants(contents)

okay so this one is the bouncer ๐Ÿ’… it makes sure a directory structure dict makes sense, and if it doesn't, it throws an error.

Right now it only checks one thing: that no empty-string keys exist ๐Ÿฅบ

Parameters

  • contents (DirectoryContents)

Return type

  • None

toil.lib.directory.decode_directory(dir_path)

this is giving decoder energy ๐Ÿ”ฅ it takes a "toildir:" path and turns it into a directory, or into a file sitting inside that directory.

Returns

  • the decoded directory dict
  • the remaining part of the path, which may be None
  • an identifier string for the directory, which is the stored name URI if one was provided
  • the name URI and source task info

Parameters

  • dir_path (str)

Return type

  • tuple[DirectoryContents, Optional[str], str, Optional[str], Optional[str]]

toil.lib.directory.encode_directory(contents, name=None, source=None)

encode is giving main character energy ๐Ÿ‘‘ it takes a directory from a "toildir:" path into a directory, or a file in it.

Parameters

  • contents (DirectoryContents) โ€” the directory dict, which maps a name to a URI for a file, or to another dict for a subdirectory
  • name (Optional[str]) โ€” the path or URI the directory belongs at, including its basename. It can't be empty if it's set ๐ŸŒธ
  • source (Optional[str]) โ€” the name of the workflow component that uploaded the directory. It can't be empty if it's set ๐Ÿฆ‹

Return type

  • str

toil.lib.directory.directory_item_exists(dir_path)

this one is a vibe check โœ… it checks that a URL to a Toil directory, or a thing inside it, actually exists.

It assumes all the pointed-to URLs exist already. It only checks that the thing is in the encoded directory structure ๐Ÿซถ

Parameters

  • dir_path (str)

Return type

  • bool

toil.lib.directory.get_directory_contents_item(contents, remaining_path)

this one grabs a subdirectory or file from a decoded directory, using the remaining path ๐Ÿ’œ

Parameters

  • contents (DirectoryContents)
  • remaining_path (Optional[str])

Return type

  • Union[DirectoryContents, str]

toil.lib.directory.get_directory_item(dir_path)

okay this is the one that takes a URL pointing to, or into, a toildir: directory and pulls out a subdirectory or file ๐Ÿงš

Parameters

  • dir_path (str)

Return type

  • Union[DirectoryContents, str]

toil.lib.directory.directory_contents_items(contents)

this is a generator that yields each file or directory under the given contents, including itself ๐Ÿ“ it's iconic for listing everything.

Parents always come out before their children ๐ŸŒˆ each item is yielded as a str path from the root (which can be empty), paired with either a str value for files or a None for directories.

The path never has trailing slashes โœจ

Parameters

  • contents (DirectoryContents)

Return type

  • Iterator[tuple[str, Union[str, None]]]

toil.lib.directory.directory_items(dir_path)

same energy as the one above, but this one starts from a path instead of contents ๐ŸŽ€ it yields each file or directory under the given path, including itself.

Parents still come before children ๐ŸŒธ each item is a str path from the root (possibly empty), paired with a str value for files or a None for directories.

The path won't have trailing slashes ๐Ÿ’–

Parameters

  • dir_path (str)

Return type

  • Iterator[tuple[str, Union[str, None]]]

toil.lib.docker

โœจ Attributes โœจ

bestie, this module has four attributes ๐Ÿณ the docs don't describe any of them, they're just the names.

  • logger
  • FORGO
  • STOP
  • RM

โœจ Functions โœจ

okay so these are the docker helpers toil hands us ๐Ÿ’… the table is a little wonky in the terminal, so here's the full tea:

  • dockerCheckOutput(*args, **kwargs): no blurb on this one bestie, it just vibes there ๐Ÿซ 
  • dockerCall(*args, **kwargs): also no blurb, same energy ๐ŸŒธ
  • subprocessDockerCall(*args, **kwargs): again, nothing written, but it's giving main character ๐Ÿฆ‹
  • apiDockerCall(โ€ฆ): a toil wrapper for the python docker API โœจ
  • dockerKill(container_name[, gentleKill, remove, timeout]): immediately kills a container ๐Ÿ’€ it's equivalent to "docker kill":
  • dockerStop(container_name[, remove]): gracefully kills a container ๐Ÿซถ it's equivalent to "docker stop":
  • containerIsRunning(container_name[, timeout]): checks whether the container is running or not ๐Ÿ‘€
  • getContainerName(job): creates a random string including the job name, and returns it. Name will ๐Ÿ™ˆ (the page cuts off right there, iykyk)

โœจ Module Contents โœจ

bestie, the module is literally full of goodies ๐ŸŽ€

toil.lib.docker.logger is hanging out in there ๐Ÿ“

Here are the constants, and they're iconic:

  • toil.lib.docker.FORGO = 0
  • toil.lib.docker.STOP = 1
  • toil.lib.docker.RM = 2

toil.lib.docker.dockerCheckOutput(*args, **kwargs)

  • Parameters
    • args (Any)
    • kwargs (Any)
  • Return type: NoReturn

toil.lib.docker.dockerCall(*args, **kwargs)

  • Parameters
    • args (Any)
    • kwargs (Any)
  • Return type: NoReturn

toil.lib.docker.subprocessDockerCall(*args, **kwargs)

  • Parameters
    • args (Any)
    • kwargs (Any)
  • Return type: NoReturn

toil.lib.docker.apiDockerCall(...)

ngl this one is a whole mood ๐Ÿ˜ญ the full signature is below, and every single default is included so you can see exactly what you're working with:

toil.lib.docker.apiDockerCall(job: toil.job.Job <#toil.job.Job>, image: str </usr/share/doc/python3/html/library/stdtypes.html#str>, parameters: list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | list </usr/share/doc/python3/html/library/stdtypes.html#list>[list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]] | None </usr/share/doc/python3/html/library/constants.html#None> = None, deferParam: int </usr/share/doc/python3/html/library/functions.html#int> | None </usr/share/doc/python3/html/library/constants.html#None> = None, volumes: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str>]] | None </usr/share/doc/python3/html/library/constants.html#None> = None, working_dir: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, containerName: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, entrypoint: str </usr/share/doc/python3/html/library/stdtypes.html#str> | list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | None </usr/share/doc/python3/html/library/constants.html#None> = None, detach: Literal[False] = False, log_config: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str>] | None </usr/share/doc/python3/html/library/constants.html#None> = None, auto_remove: bool </usr/share/doc/python3/html/library/functions.html#bool> | None </usr/share/doc/python3/html/library/constants.html#None> = None, remove: bool </usr/share/doc/python3/html/library/functions.html#bool> | None </usr/share/doc/python3/html/library/constants.html#None> = False, user: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, environment: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str>] | None </usr/share/doc/python3/html/library/constants.html#None> = None, stdout: bool </usr/share/doc/python3/html/library/functions.html#bool> | None </usr/share/doc/python3/html/library/constants.html#None> = None, stderr: bool </usr/share/doc/python3/html/library/functions.html#bool> = False, stream: bool </usr/share/doc/python3/html/library/functions.html#bool> = False, demux: Literal[False] = False, streamfile: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None> = None, accelerators: list </usr/share/doc/python3/html/library/stdtypes.html#list>[int </usr/share/doc/python3/html/library/functions.html#int>] | None </usr/share/doc/python3/html/library/constants.html#None> = None, timeout: int </usr/share/doc/python3/html/library/functions.html#int> = 365 * 24 * 60 * 60, **kwargs: Any) -> str </usr/share/doc/python3/html/library/stdtypes.html#str>

Okay bestie, apiDockerCall comes in three looks ๐Ÿ’… The return type changes depending on how you set stream and detach โœจ

toil.lib.docker.apiDockerCall(job: toil.job.Job, image: str, parameters: list[str] | list[list[str]] | None = None, deferParam: int | None = None, volumes: dict[str, dict[str, str]] | None = None, working_dir: str | None = None, containerName: str | None = None, entrypoint: str | list[str] | None = None, detach: Literal[False] = False, log_config: dict[str, str] | None = None, auto_remove: bool | None = None, remove: bool | None = False, user: str | None = None, environment: dict[str, str] | None = None, stdout: bool | None = None, stderr: bool = False, stream: Literal[True] = True, demux: Literal[True] = True, streamfile: str | None = None, accelerators: list[int] | None = None, timeout: int = 365 * 24 * 60 * 60, **kwargs: Any) -> collections.abc.Generator[tuple[str, str]]

Here's the first one ๐ŸŽ€ With stream and demux both set to True, it hands back a generator that yields tuple[str, str] pairs ๐ŸŒธ

toil.lib.docker.apiDockerCall(job: toil.job.Job, image: str, parameters: list[str] | list[list[str]] | None = None, deferParam: int | None = None, volumes: dict[str, dict[str, str]] | None = None, working_dir: str | None = None, containerName: str | None = None, entrypoint: str | list[str] | None = None, detach: Literal[False] = False, log_config: dict[str, str] | None = None, auto_remove: bool | None = None, remove: bool | None = False, user: str | None = None, environment: dict[str, str] | None = None, stdout: bool | None = None, stderr: bool = False, stream: Literal[False] = False, demux: Literal[True] = True, streamfile: str | None = None, accelerators: list[int] | None = None, timeout: int = 365 * 24 * 60 * 60, **kwargs: Any) -> tuple[str, str]

Look at this one, it's the non-streaming version ๐Ÿฆ‹ Same detach of False, but stream is Literal[False], so you get a single tuple[str, str] back instead of a generator ๐Ÿซถ

toil.lib.docker.apiDockerCall(job: toil.job.Job, image: str, parameters: list[str] | list[list[str]] | None = None, deferParam: int | None = None, volumes: dict[str, dict[str, str]] | None = None, working_dir: str | None = None, containerName: str | None = None, entrypoint: str | list[str] | None = None, detach: Literal[True] = True, log_config: dict[str, str] | None = None, auto_remove: bool | None = None, remove: bool | None = False, user: str | None = None, environment: dict[str, str] | None = None, stdout: bool | None = None, stderr: bool = False, stream: bool = False, demux: bool = False, streamfile: str | None = None, accelerators: list[int] | None = None, timeout: int = 365 * 24 * 60 * 60, **kwargs: Any) -> docker.models.containers.Container

And the final main-character version ๐Ÿ‘‘ With detach set to True, it returns a docker.models.containers.Container object, and stream and demux both default to False here ๐ŸŒˆ

toil.lib.docker.apiDockerCall(job: toil.job.Job, image: str, parameters: list[str] | list[list[str]] | None = None, deferParam: int | None = None, volumes: dict[str, dict[str, str]] | None = None, working_dir: str | None = None, containerName: str | None = None, entrypoint: str | list[str] | None = None, detach: bool = False, log_config: dict[str, str] | None = None, auto_remove: bool | None = None, remove: bool | None = False, user: str | None = None, environment: dict[str, str] | None = None, stdout: bool | None = None, stderr: bool = False, stream: bool = False, demux: bool = False, streamfile: str | None = None, accelerators: list[int] | None = None, timeout: int = 365 * 24 * 60 * 60, **kwargs: Any) -> str | docker.models.containers.Container | collections.abc.Generator[tuple[str, str]] | collections.abc.Generator[str] | tuple[str, str]

okay bestie, this one is the main character ๐Ÿ’…โœจ apiDockerCall is toil's own wrapper for the python docker API ๐Ÿณ๐Ÿ’–. It's docker's python API running inside toil, so every call gets run as a job ๐ŸŽ€. The whole point is that if a docker job fails or gets orphaned, toil can handle it properly ๐Ÿซถ.

Example ๐Ÿงš

Here's how you'd use dockerCall in toil to index a FASTA file with SAMtools ๐ŸŒธ:

def toil_job(job):
    working_dir = job.fileStore.getLocalTempDir()
    path = job.fileStore.readGlobalFile(ref_id,
                                      os.path.join(working_dir, 'ref.fasta')
    parameters = ['faidx', path]
    apiDockerCall(job,
                  image='quay.io/ucgc_cgl/samtools:latest',
                  working_dir=working_dir,
                  parameters=parameters)
โš ๏ธ Heads up: when this runs with detach=False, or with detach=True and stdout=True or stderr=True, it's a blocking call. With detach=True and no output capture, the container gets started and returned without waiting for it to finish.

Parameters ๐Ÿ’–

  • job โ€” the Job instance for the function calling this one ๐Ÿ’
  • image โ€” name of the Docker image to use, like 'quay.io/ucsc_cgl/samtools:latest'
  • parameters โ€” a list of string elements. If there are multiple elements, they get joined with spaces. This keeps things backwards compatible with older versions that called docker with subprocess.check_call(). If you pass a list of lists (list[list[str]]), each inner list is treated as a successive command, chained with a pipe ๐Ÿ”—
  • deferParam โ€” what happens to the container when the job wraps up ๐Ÿ:
    • FORGO (0) leaves the container untouched and running
    • STOP (1) sends SIGTERM, then SIGKILL if necessary, to the container
    • RM (2) immediately sends SIGKILL to the container
    • If deferParam is None, RM is the default behavior
  • volumes โ€” a dictionary of volume locations to volume options ๐Ÿ“ฆ
  • working_dir โ€” the working directory ๐Ÿ“‚
  • containerName โ€” the name or ID of the container ๐Ÿท๏ธ
  • entrypoint โ€” prepends commands sent to the container. See https://docker-py.readthedocs.io/en/stable/containers.html
  • detach โ€” runs the container in detached mode (equivalent to -d) ๐Ÿฆ‹
  • log_config โ€” specifies which logs to return from the container. See https://docker-py.readthedocs.io/en/stable/containers.html
  • remove โ€” removes the container on exit, or doesn't ๐Ÿ—‘๏ธ
  • user โ€” the privileges the container runs with. This can be an actual name, like 'root' or 'lifeisaboutfishtacos', or the uid or gid ('0' is root, '1000' is an example of a less privileged uid or gid), or a complement of the uid:gid (RECOMMENDED), like '0:0' (root user : root group) or '1000:1000' (some other user : some other user group) ๐Ÿ‘‘
  • environment โ€” lets you set environment variables inside the container ๐ŸŒˆ
  • stdout โ€” returns logs from STDOUT when detach=False (default: True). When detach=True, it blocks and captures stdout to a file (default: False). Output capture defaults to output.log, and you can change that with the "streamfile" kwarg
  • stderr โ€” returns logs from STDERR when detach=False (default: False). When detach=True, it blocks and captures stderr to a file (default: False). Output capture defaults to output.log, and you can change that with the "streamfile" kwarg
  • stream โ€” if True and detach=False, you get a log generator instead of a string. Ignored if detach=True (default: False)
  • demux โ€” similar to demux in container.exec_run(). If True and detach=False, you get back a tuple of (stdout, stderr). If stream=True, you get a log generator with tuples of (stdout, stderr). Ignored if detach=True (default: False)
  • streamfile โ€” where container output gets collected if detach=True and stderr and/or stdout are True. Defaults to "output.log" ๐Ÿ“
  • accelerators โ€” Toil accelerator numbers (usually GPUs) to forward to the container ๐Ÿ”ฅ. These are interpreted in the current Python process's environment. Check toil.lib.accelerators.get_individual_local_accelerators() for the menu of available accelerators
  • timeout โ€” the timeout in seconds for interactions with the Docker daemon โณ. Defaults to 1 year (i.e. wait essentially indefinitely)
๐Ÿšจ Caveat: the underlying docker module isn't always able to abort ongoing reads and writes in order to respect the timeout.

Returns ๐ŸŽ€

When detach=False, you get the standard output/standard error text back, as requested. When detach=True, you get the underlying docker.models.containers.Container object from the Docker API.


toil.lib.docker.dockerKill ๐Ÿ’€

toil.lib.docker.dockerKill(container_name, gentleKill=False, remove=False, timeout=365 * 24 * 60 * 60)

This one is giving "immediate and no crying about it" ๐Ÿ˜ญ. It kills a container right away, and it's equivalent to docker kill. Check out https://docs.docker.com/engine/reference/commandline/kill/ if you want the deets ๐Ÿฆ‹.

Parameters

  • container_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the container being killed ๐Ÿ’€
  • gentleKill (bool, /usr/share/doc/python3/html/library/functions.html#bool) โ€” if this is True, it triggers a graceful shutdown โœจ the polite way to say goodbye ๐Ÿซถ
  • remove (bool, /usr/share/doc/python3/html/library/functions.html#bool) โ€” if True, the container gets removed after it exits ๐Ÿงน
  • timeout (int, /usr/share/doc/python3/html/library/functions.html#int) โ€” the number of seconds to wait for interactions with the Docker daemon. Heads up, bestie: the underlying docker module isn't always able to abort ongoing reads and writes to actually respect the timeout ๐Ÿฅบ It defaults to 1 year (i.e. wait essentially indefinitely) โณ

Return type โ€” None ๐Ÿ’–

toil.lib.docker.dockerStop(container_name, remove=False)

Gracefully kills a container. It's equivalent to docker stop, see https://docs.docker.com/engine/reference/commandline/stop/ ๐Ÿ›‘

Parameters

  • container_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the container being stopped ๐Ÿซง
  • remove (bool, /usr/share/doc/python3/html/library/functions.html#bool) โ€” if True, the container gets removed after it exits ๐Ÿงน

Return type โ€” None ๐Ÿ’–

toil.lib.docker.containerIsRunning(container_name, timeout=365 * 24 * 60 * 60)

Checks whether the container is running or not. Main character check ๐Ÿ”

Parameters

  • container_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the container being checked ๐Ÿ‘€
  • timeout (int, /usr/share/doc/python3/html/library/functions.html#int) โ€” the number of seconds to wait for interactions with the Docker daemon. Same tea as before: the underlying docker module is not always able to abort ongoing reads and writes in order to respect the timeout. It defaults to 1 year (i.e. wait essentially indefinitely) โณ

Returns

True if the status is 'running', False if the status is anything else, and None if the container does not exist ๐Ÿซฅ

Return type โ€” Optional[bool] (/usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’œ

toil.lib.docker.getContainerName(job)

Creates a random string that includes the job name, then returns it. The name will match [a-zA-Z0-9][a-zA-Z0-9_.-] ๐ŸŽ€

Parameters

  • job (toil.job.Job, #toil.job.Job) ๐Ÿงš

Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’–


โœจ toil.lib.dockstore โœจ

Okay so this module is all about integrating Toil with UCSC Dockstore, for reporting metrics ๐Ÿ“Š It's giving data girl energy ๐Ÿ’…

For basic TRS functionality for fetching workflows, see trs.py ๐Ÿฆ‹

โœจ Attributes โœจ

  • logger
  • DEFAULT_DOCKSTORE_TOKEN
  • DOCKSTORE_TOKEN
  • DOCKSTORE_PLATFORM
  • ExecutionStatus

โœจ Classes โœจ

  • Cost โ€” representation of the cost of running something ๐Ÿ’ธ
  • RunExecution โ€” Dockstore metrics data for a workflow or task run ๐Ÿƒโ€โ™€๏ธ
  • TaskExecutions โ€” Dockstore metrics data for all the tasks in a workflow ๐ŸŒธ

โœจ Functions โœจ

  • ensure_valid_id(execution_id) โ€” make sure the given execution ID is in Dockstore format and will be accepted by Dockstore ๐Ÿชช
  • pack_workflow_metrics(execution_id, start_time, ...[, ...]) โ€” pack up per-workflow metrics into a format that can be submitted to Dockstore ๐Ÿ“ฆ
  • pack_single_task_metrics(execution_id, start_time, ...) โ€” pack up metrics for a single task execution in a format that can be used in a Dockstore submission ๐ŸŽ
  • pack_workflow_task_set_metrics(execution_id, ...) โ€” pack up metrics for all the tasks in a workflow execution into a format that can be submitted to Dockstore ๐Ÿงƒ
  • send_metrics(trs_workflow_id, trs_version, ...) โ€” send packed workflow and/or task metrics to Dockstore ๐Ÿ“จ
  • get_metrics_url(trs_workflow_id, trs_version, execution_id) โ€” get the URL where a workflow metrics object (for a workflow, or for a set of tasks) can be fetched back from ๐Ÿ”—

โœจ Module Contents โœจ

  • toil.lib.dockstore.logger
  • toil.lib.dockstore.DEFAULT_DOCKSTORE_TOKEN = '2bff46294daddef6df185452b04db6143ea8a59f52ee3c325d3e1df418511b7d'
  • toil.lib.dockstore.DOCKSTORE_TOKEN
  • toil.lib.dockstore.DOCKSTORE_PLATFORM = 'TOIL'
  • toil.lib.dockstore.ExecutionStatus

โœจ class toil.lib.dockstore.Cost โœจ

Bases: TypedDict ๐ŸŒˆ

Representation of the cost of running something.

  • value (float, /usr/share/doc/python3/html/library/functions.html#float) โ€” the cost in US Dollars ๐Ÿ’ต

โœจ class toil.lib.dockstore.RunExecution โœจ

Bases: TypedDict ๐ŸŒˆ

Dockstore metrics data for a workflow or task run. Okay, this is the big one, so pay attention ๐Ÿ‘€

  • executionId (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the executor-generated unique execution ID for this workflow or task ๐Ÿ†”
  • dateExecuted (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” an ISO 8601 UTC timestamp for when the execution happened โฐ
  • executionStatus (ExecutionStatus) โ€” did the execution work? That's the whole question ๐Ÿคž
  • executionTime (typing_extensions.NotRequired[str], /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the total time of the run in ISO 8601 duration format โฑ๏ธ
  • memoryRequirementsGB (typing_extensions.NotRequired[float], /usr/share/doc/python3/html/library/functions.html#float) โ€” the memory required for the execution in gigabytes (not GiB, so don't mix them up!) ๐Ÿง 
  • cpuRequirements (typing_extensions.NotRequired[int], /usr/share/doc/python3/html/library/functions.html#int) โ€” the number of CPUs required ๐Ÿ–ฅ๏ธ
  • cost (typing_extensions.NotRequired[Cost], #toil.lib.dockstore.Cost) โ€” how much the execution cost to run ๐Ÿ’ฐ
  • region (typing_extensions.NotRequired[str], /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the (cloud) region the workflow was executed in โ˜๏ธ

additionalProperties: typing_extensions.NotRequired[dict[str, Any]]

Got extra stuff to send? This is where it goes ๐ŸŽ Any additional properties you want to ship off to Dockstore. Dockstore is lowkey so accommodating that it takes any JSON-able structured data ๐Ÿ’…

Type docs: dict at /usr/share/doc/python3/html/library/stdtypes.html#dict, and str at /usr/share/doc/python3/html/library/stdtypes.html#str.

class toil.lib.dockstore.TaskExecutions

Bases: TypedDict

Dockstore metrics for every task in a workflow, all bundled up in one place ๐Ÿงš

executionId: str

The unique ID the executor generated for this run ๐Ÿ†” Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.

dateExecuted: str

When it happened, written as an ISO 8601 UTC timestamp โฐ Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.

taskExecutions: list[RunExecution]

Each individual task execution in the workflow, one by one ๐ŸŒธ Type docs: /usr/share/doc/python3/html/library/stdtypes.html#list for list, and RunExecution is defined as toil.lib.dockstore.RunExecution.

additionalProperties: typing_extensions.NotRequired[dict[str, Any]]

Any additional properties to send, again, because it's giving extra ๐ŸŽ€ Dockstore takes any JSON-able structured data. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/stdtypes.html#str.

toil.lib.dockstore.ensure_valid_id(execution_id)

toil.lib.dockstore.ensure_valid_id(execution_id)

Make sure the execution ID is in Dockstore format so Dockstore doesn't side-eye it ๐Ÿ‘€ It has to be accepted, or else ๐Ÿ’€

The ID must be alphanumeric, though internal underscores are allowed ๐Ÿซถ It also has to be <100 characters long, so keep it short and sweet.

Raises ValueError if the ID isn't in the right format.

Parameters

  • execution_id (str) โ€” the execution ID you want to check. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.

Return type: None

toil.lib.dockstore.pack_workflow_metrics(...)

toil.lib.dockstore.pack_workflow_metrics(execution_id, start_time, runtime, succeeded, job_store_type=None, batch_system=None, caching=None, toil_version=None, python_version=None, platform_system=None, platform_machine=None)

Okay, this one packs up per-workflow metrics into a format Dockstore will actually accept ๐Ÿ”ฅ

Parameters

  • execution_id (str) โ€” unique ID for the workflow execution. Has to be in Dockstore format. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • start_time (float) โ€” when the execution started, in seconds since the Unix epoch. Type docs: /usr/share/doc/python3/html/library/functions.html#float.
  • rutime โ€” how long the execution ran, in seconds.
  • jobstore_type โ€” the kind of job store used, like "file" or "aws".
  • batch_system (Optional[str]) โ€” the Python class name of the batch system that got used. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • caching (Optional[bool]) โ€” whether Toil filestore-level caching was on. Type docs: /usr/share/doc/python3/html/library/functions.html#bool.
  • toil_version (Optional[str]) โ€” the Toil version, without any Git hash ๐Ÿฆ‹ Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • python_version (Optional[str]) โ€” the Python version used. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • platform_system (Optional[str]) โ€” the operating system type, like "Darwin" or "Linux". Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • platform_machine (Optional[str]) โ€” the machine architecture of the leader, like "AMD64". Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • runtime (float) โ€” type docs: /usr/share/doc/python3/html/library/functions.html#float.
  • succeeded (bool) โ€” type docs: /usr/share/doc/python3/html/library/functions.html#bool.
  • job_store_type (Optional[str]) โ€” type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.

Return type: RunExecution, which is toil.lib.dockstore.RunExecution.

toil.lib.dockstore.pack_single_task_metrics(...)

toil.lib.dockstore.pack_single_task_metrics(execution_id, start_time, runtime, succeeded, job_name=None, cores=None, cpu_seconds=None, memory_bytes=None, disk_bytes=None)

This one packs up metrics for a single task execution so it's ready for a Dockstore submission ๐Ÿ’–

Parameters

  • execution_id (str) โ€” unique ID for the workflow execution. Has to be in Dockstore format. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • start_time (float) โ€” when the execution started, in seconds since the Unix epoch. Type docs: /usr/share/doc/python3/html/library/functions.html#float.
  • rutime โ€” how long the execution ran, in seconds.
  • succeeded (bool) โ€” whether the execution succeeded. Type docs: /usr/share/doc/python3/html/library/functions.html#bool.
  • job_name (Optional[str]) โ€” the name of the job within the workflow. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • cores (Optional[float]) โ€” CPU cores allocated to the job. Type docs: /usr/share/doc/python3/html/library/functions.html#float.
  • cpu_seconds (Optional[float]) โ€” CPU seconds the job consumed. Type docs: /usr/share/doc/python3/html/library/functions.html#float.
  • memory_bytes (Optional[int]) โ€” memory the job consumed, in bytes. Type docs: /usr/share/doc/python3/html/library/functions.html#int.
  • disk_bytes (Optional[int]) โ€” disk space the job consumed, in bytes. Type docs: /usr/share/doc/python3/html/library/functions.html#int.
  • runtime (float) โ€” type docs: /usr/share/doc/python3/html/library/functions.html#float.

Return type: RunExecution, which is toil.lib.dockstore.RunExecution.

toil.lib.dockstore.pack_workflow_task_set_metrics(...)

toil.lib.dockstore.pack_workflow_task_set_metrics(execution_id, start_time, tasks)

Packs up metrics for every task in a workflow execution into something Dockstore can take ๐ŸŒˆ

Parameters

  • execution_id (str) โ€” unique ID for the workflow execution. Has to be in Dockstore format. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • start_time (float) โ€” when the overall workflow execution started, in seconds since the Unix epoch. Type docs: /usr/share/doc/python3/html/library/functions.html#float.
  • tasks (list[RunExecution]) โ€” packed tasks from pack_single_task_metrics(). Type docs: /usr/share/doc/python3/html/library/stdtypes.html#list and toil.lib.dockstore.RunExecution.

Return type: TaskExecutions, which is toil.lib.dockstore.TaskExecutions.

toil.lib.dockstore.send_metrics(...)

toil.lib.dockstore.send_metrics(trs_workflow_id, trs_version, workflow_runs, workflow_task_sets)

Sends your packed workflow and/or task metrics off to Dockstore ๐Ÿš€

Parameters

  • workflow_runs (list[RunExecution]) โ€” a list of packed metrics objects, one for each workflow. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#list and toil.lib.dockstore.RunExecution.
  • workflow_task_sets (list[TaskExecutions]) โ€” a list of packed metrics objects for the tasks in each workflow. Each workflow should have one entry with all of its tasks. It doesn't have to match the same order or set of workflows as workflow_runs. Type docs: /usr/share/doc/python3/html/library/stdtypes.html#list and toil.lib.dockstore.TaskExecutions.
  • trs_workflow_id (str) โ€” type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • trs_version (str) โ€” type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
Heads up: if Dockstore doesn't accept the metrics, this raises requests.HTTPError ๐Ÿ˜ญ

Return type: None

toil.lib.dockstore.get_metrics_url(...)

toil.lib.dockstore.get_metrics_url(trs_workflow_id, trs_version, execution_id)

Gets the URL where a workflow metrics object can be fetched back from, whether it's for a whole workflow or a set of tasks ๐Ÿ”—

Parameters

  • trs_workflow_id (str) โ€” type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • trs_version (str) โ€” type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.
  • execution_id (str) โ€” type docs: /usr/share/doc/python3/html/library/stdtypes.html#str.

Return type: str, with type docs at /usr/share/doc/python3/html/library/stdtypes.html#str.

toil.lib.ec2

Attributes

The attributes are below. The table doesn't give descriptions for any of them, so I'm not going to guess ๐Ÿ™ˆ

  • a_short_time
  • a_long_time
  • logger
  • INCONSISTENCY_ERRORS
  • iam_client

โœจ Exceptions โœจ

okay bestie, these are the error bffs of this module ๐Ÿซถ they're giving "something went wrong and we're gonna tell you about it" ๐Ÿ’€

  • UserError โ€” Unspecified run-time error. ๐Ÿ™ˆ
  • UnexpectedResourceState โ€” the common base class for all non-exit exceptions ๐Ÿ’…

โœจ Functions โœจ

here's the full guest list ๐ŸŽ€ some of these descriptions get cut off mid-sentence in the docs (๐Ÿ˜ญ not my fault), so I'm giving you exactly what's there and nothing more

  • is_base64(value) โ€” Return True if value is base64-decodeable, and False otherwise. โœจ
  • not_found(e) โ€” no blurb for this one, it's giving mystery ๐Ÿ”ฎ
  • inconsistencies_detected(e) โ€” no blurb either, very mysterious ๐Ÿงš
  • retry_ec2([t, retry_for, retry_while]) โ€” no blurb ๐Ÿ™ˆ
  • wait_transition(boto3_ec2, resource, from_states, to_state) โ€” waits until the specified EC2 resource (instance, image, volume, ...) transitions from any (the description stops right there ๐Ÿ˜ญ)
  • wait_instances_running(boto3_ec2, instances) โ€” waits until no instance in the given iterable is 'pending'. Yields every instance that (also cut off, babe ๐Ÿ’€)
  • wait_spot_requests_active(boto3_ec2, requests[, ...]) โ€” waits until no spot request in the given iterator is in the 'open' state or, optionally, (cut off again ๐Ÿฅฒ)
  • create_spot_instances(boto3_ec2, price, image_id, spec) โ€” creates instances on the spot market. ๐ŸŒธ
  • create_ondemand_instances(boto3_ec2, image_id, spec[, ...]) โ€” requests the RunInstances EC2 API call but accounts for the race between recently created (cut off, the drama continues ๐ŸŽญ)
  • increase_instance_hop_limit(boto3_ec2, boto_instance_list) โ€” increases the default HTTP hop limit, as we are running Toil and Kubernetes inside a Docker container, so the default (and stops there ๐Ÿ˜ญ)
  • prune(bushy) โ€” prunes entries in the given dict with false-y values. ๐Ÿ“
  • wait_until_instance_profile_arn_exists(...) โ€” no blurb ๐Ÿ‘€
  • create_instances(ec2_resource, image_id, key_name, ...) โ€” replaces create_ondemand_instances. Uses boto3 and returns a list of Boto3 instance dicts. ๐Ÿ‘‘
  • create_launch_template(ec2_client, template_name, ...) โ€” creates a launch template with the given name for launching instances with the given parameters. ๐Ÿš€
  • create_auto_scaling_group(autoscaling_client, ...[, ...]) โ€” creates a new Auto Scaling Group with the given name (which is also its (cut off, babe ๐Ÿ’€)

โœจ Module Contents โœจ

okay the module contents are where the receipts are ๐Ÿงพ let's go

Constants and names first:

toil.lib.ec2.a_short_time = 5

toil.lib.ec2.a_long_time = 3600

toil.lib.ec2.logger

Now is_base64. It's giving return True or False vibes ๐Ÿฆ‹

toil.lib.ec2.is_base64(value)

Return True if value is base64-decodeable, and False otherwise.

  • Parameters: value (str)
  • Return type: bool

Next up is UserError, which is a RuntimeError underneath ๐Ÿซถ

exception toil.lib.ec2.UserError(message=None, cause=None)

Bases: RuntimeError. Unspecified run-time error. ๐Ÿ™ˆ

A few more names:

toil.lib.ec2.not_found(e)

toil.lib.ec2.inconsistencies_detected(e)

toil.lib.ec2.INCONSISTENCY_ERRORS

toil.lib.ec2.retry_ec2(t=a_short_time, retry_for=10 * a_short_time, retry_while=not_found)

Then UnexpectedResourceState, the base class that's basically everyone's mom ๐Ÿ’…

exception toil.lib.ec2.UnexpectedResourceState(resource, to_state, state)

Bases: Exception. Common base class for all non-exit exceptions. โœจ

Now wait_transition, which is a whole vibe ๐ŸŒˆ

toil.lib.ec2.wait_transition(boto3_ec2, resource, from_states, to_state, state_getter=lambda x: ...)

Waits until the specified EC2 resource (instance, image, volume, ...) transitions from any of the given 'from' states to the specified 'to' state. If the instance is found in a state other that the to state or any of the from states, an exception will be thrown. ๐Ÿ˜ฌ

  • Parameters:
    • resource (mypy_boto3_ec2.type_defs.InstanceTypeDef) -- the resource to monitor
    • from_states (collections.abc.Iterable[str]) -- a set of states that the resource is expected to be in before the transition occurs
    • to_state (str) -- the state of the resource when this method returns
    • boto3_ec2 (mypy_boto3_ec2.client.EC2Client)
    • state_getter (Callable[[mypy_boto3_ec2.type_defs.InstanceTypeDef], str])

And last but not least, wait_instances_running ๐Ÿ’–

toil.lib.ec2.wait_instances_running(boto3_ec2, instances)

Waits until no instance in the given iterable is 'pending'. Yields every instance that entered the running state as soon as it does. ๐Ÿฆ‹

  • Parameters:
    • boto3_ec2 (mypy_boto3_ec2.client.EC2Client) -- the EC2 connection to use for making requests
  • instances (collections.abc.Iterable[mypy_boto3_ec2.type_defs.InstanceTypeDef], docs: /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterable) โ€” the instances we're waiting on ๐Ÿซถ

Return type: collections.abc.Generator[mypy_boto3_ec2.type_defs.InstanceTypeDef, None, None] (docs: /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator) โœจ

๐Ÿฆ‹ toil.lib.ec2.wait_spot_requests_active

toil.lib.ec2.wait_spot_requests_active(boto3_ec2, requests,
timeout=None, tentative=False)

Okay so this one waits until no spot request in the iterator is still sitting in the 'open' state, or until a timeout hits, whichever comes first. ๐Ÿ’… It also yields spot requests the second they leave 'open', so you're not stuck waiting for the whole batch. Main character energy ๐Ÿ‘‘

Parameters

  • boto3_ec2 (mypy_boto3_ec2.client.EC2Client) โ€” the ec2 client ๐Ÿ’–
  • requests (collections.abc.Iterable[mypy_boto3_ec2.type_defs.SpotInstanceRequestTypeDef], docs: /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterable) โ€” the requests we're waiting on ๐ŸŒธ
  • timeout (float, docs: /usr/share/doc/python3/html/library/functions.html#float) โ€” the max number of seconds to wait, or None if you're down to wait forever ๐Ÿงš If the timeout goes off, any requests still open get cancelled ๐Ÿ’€
  • tentative (bool, docs: /usr/share/doc/python3/html/library/functions.html#bool) โ€” if True, give up on a spot request the moment it looks like it won't be fulfilled right away ๐Ÿ™ˆ

Return type: collections.abc.Iterable[list[mypy_boto3_ec2.type_defs.SpotInstanceRequestTypeDef]] (docs: /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterable, /usr/share/doc/python3/html/library/stdtypes.html#list) ๐ŸŽ€

๐ŸŒˆ toil.lib.ec2.create_spot_instances

toil.lib.ec2.create_spot_instances(boto3_ec2, price, image_id, spec,
num_instances=1, timeout=None, tentative=False, tags=None)

This one makes instances on the spot market. ๐Ÿ”ฅ

๐Ÿšจ Heads up bestie: the "UserData" field inside "LaunchSpecification" in spec MUST ALREADY BE base64-encoded. It will NOT be encoded for you, so don't skip this or you'll be crying later ๐Ÿ˜ญ

Parameters

  • tags (dict[str, str], docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” a dict of tag key to tag value, applied to the request ๐Ÿท๏ธ
  • boto3_ec2 (mypy_boto3_ec2.client.EC2Client) ๐Ÿ’œ
  • spec (dict[Literal['LaunchSpecification'], dict[str, Any]], docs: /usr/share/doc/python3/html/library/stdtypes.html#dict) ๐Ÿ“

Return type: collections.abc.Generator[mypy_boto3_ec2.type_defs.DescribeInstancesResultTypeDef, None, None] (docs: /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator) โœจ

๐Ÿซง toil.lib.ec2.create_ondemand_instances

toil.lib.ec2.create_ondemand_instances(boto3_ec2, image_id, spec,
num_instances=1)

This one calls the RunInstances EC2 API, but it's extra careful about a race condition ๐Ÿ™Œ Recently created instance profiles and IAM roles can still be settling when an instance tries to use them, so this handles that for you. Iconic behaviour ๐Ÿ’…

The "UserData" field in spec MUST NOT be base64-encoded. boto3 does that automatically ๐Ÿฉต For more, check https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2/client/run_instances.html.

Replaced by create_instances ๐Ÿฆ‹ so maybe use that one instead, bestie.

Parameters

  • boto3_ec2 (mypy_boto3_ec2.client.EC2Client) ๐ŸŒท
  • image_id (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“ธ
  • spec (collections.abc.Mapping[str, Any], docs: /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Mapping, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿง
  • num_instances (int, docs: /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ”ข

Return type: list[mypy_boto3_ec2.type_defs.InstanceTypeDef] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿ’–

๐Ÿงš toil.lib.ec2.increase_instance_hop_limit

toil.lib.ec2.increase_instance_hop_limit(boto3_ec2, boto_instance_list)

This one bumps up the default HTTP hop limit. โœจ Why? Because Toil and Kubernetes are running inside a Docker container, and the default hop limit of 1 just isn't enough when you're grabbing metadata with ec2_metadata ๐Ÿณ It has to be called after the instances are guaranteed to be running, so timing matters, babe โฐ

Parameters

  • boto_instance_list (list[mypy_boto3_ec2.type_defs.InstanceTypeDef], docs: /usr/share/doc/python3/html/library/stdtypes.html#list) โ€” the list of boto instances to modify ๐ŸŽฏ
  • boto3_ec2 (mypy_boto3_ec2.client.EC2Client) ๐Ÿซถ

Returns: (the docs leave this one blank)

Return type: None ๐Ÿซง

๐ŸŒธ toil.lib.ec2.prune

toil.lib.ec2.prune(bushy)

This one clears out any entries in the given dict that have false-y values. ๐Ÿงน Boto3 gets cranky about None and would rather the key just not exist at all, so this helps with that ๐Ÿ™„

Parameters

  • bushy (dict, docs: /usr/share/doc/python3/html/library/stdtypes.html#dict) ๐Ÿ€

Return type: dict (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict) ๐Ÿ’œ

๐ŸŽ€ toil.lib.ec2.iam_client

toil.lib.ec2.iam_client

No description for this one, bestie. Just vibes ๐Ÿคทโ€โ™€๏ธโœจ

๐ŸŒท toil.lib.ec2.wait_until_instance_profile_arn_exists

toil.lib.ec2.wait_until_instance_profile_arn_exists(instance_profile_arn)

Parameters

  • instance_profile_arn (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒˆ

๐Ÿš€ toil.lib.ec2.create_instances

toil.lib.ec2.create_instances(ec2_resource, image_id, key_name,
instance_type, num_instances=1, security_group_ids=None, user_data=None,
block_device_map=None, instance_profile_arn=None, placement_az=None,
subnet_id=None, tags=None)

This is the replacement for create_ondemand_instances ๐Ÿซถ It uses boto3 and gives back a list of Boto3 instance dicts. Lowkey the one you want ๐Ÿ’…

See "create_instances" (this one gives back a list of ec2.Instance objects): https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.ServiceResource.create_instances

๐Ÿ‘€ Don't mix this up with "run_instances". It takes the same input args but returns a dictionary instead: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.run_instances

Parameters

  • user_data (Optional[Union[str, bytes]], docs: /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#bytes) โ€” the user data that controls instance startup, not base64-encoded ๐Ÿงƒ
  • tags (Optional[dict[str, str]], docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” if you give these, they get applied to the instances and all volumes ๐Ÿท๏ธ
  • ec2_resource (mypy_boto3_ec2.service_resource.EC2ServiceResource) ๐ŸŒŠ
  • image_id (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“ธ
  • key_name (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ”‘
  • instance_type (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿฃ
  • num_instances (int, docs: /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ”ข
  • security_group_ids (Optional[list], docs: /usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿ›ก๏ธ
  • block_device_map (Optional[list[dict]], docs: /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#dict) ๐Ÿ’พ
  • instance_profile_arn (Optional[str], docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿชช
  • placement_az (Optional[str], docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ—บ๏ธ
  • subnet_id (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ•ธ๏ธ

Return type: list[mypy_boto3_ec2.service_resource.Instance] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list) โœจ

๐Ÿช„ toil.lib.ec2.create_launch_template

toil.lib.ec2.create_launch_template(ec2_client, template_name, image_id,
key_name, instance_type, security_group_ids=None, user_data=None,
block_device_map=None, instance_profile_arn=None, placement_az=None,
subnet_id=None, tags=None)

This one makes a launch template with the name you give it, so you can launch instances with the parameters you pass in ๐ŸŽ€

๐ŸŒŸ Just so you know, we only ever use the default version of any launch template ๐Ÿ’…

Under the hood, this calls https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html?highlight=create_launch_template#EC2.Client.create_launch_template ๐Ÿซถ

Parameters

  • tags (Optional[dict[str, str]], docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” if given, the tags get applied to the template itself, all instances, and all volumes ๐Ÿท๏ธ
  • user_data (Optional[Union[str, bytes]], docs: /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#bytes) โ€” user data to pass to the instances, not base64-encoded ๐Ÿงƒ
  • ec2_client (mypy_boto3_ec2.client.EC2Client) ๐Ÿ’œ
  • template_name (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“›
  • image_id (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“ธ
  • key_name (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ”‘
  • instance_type (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿฃ
  • security_group_ids โ€” Optional[list </usr/share/doc/python3/html/library/stdtypes.html#list>] ๐Ÿ›ก๏ธ
  • block_device_map โ€” Optional[list </usr/share/doc/python3/html/library/stdtypes.html#list>[dict </usr/share/doc/python3/html/library/stdtypes.html#dict>]] ๐Ÿ’พ
  • instance_profile_arn โ€” Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>] ๐Ÿชช
  • placement_az โ€” Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>] ๐Ÿ“
  • subnet_id โ€” Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>] ๐Ÿงš

Returns: the ID of the launch template. โœจ

Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str> ๐Ÿ’–


toil.lib.ec2.create_auto_scaling_group(autoscaling_client, asg_name, launch_template_ids, vpc_subnets, min_size, max_size, instance_types=None, spot_bid=None, spot_cheapest=False, tags=None)

toil.lib.ec2.create_auto_scaling_group(autoscaling_client, asg_name, launch_template_ids, vpc_subnets, min_size, max_size, instance_types=None, spot_bid=None, spot_cheapest=False, tags=None)

okay so this one makes a brand new Auto Scaling Group, and the name you give it is also its unique identifier ๐Ÿฆ‹ no duplicates allowed, bestie.

Parameters

  • autoscaling_client (mypy_boto3_autoscaling.client.AutoScalingClient) โ€” your Boto3 client for autoscaling ๐Ÿ”ฅ
  • asg_name (str </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” the unique name for the autoscaling group ๐ŸŒธ
  • launch_template_ids (dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str>]) โ€” the ID of the launch template to make instances from, one for each instance type ๐ŸŽ€
  • vpc_subnets (list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]) โ€” one or more subnet IDs to place the group's instances into. These decide which availability zone(s) the instances launch into ๐ŸŒˆ
  • min_size (int </usr/share/doc/python3/html/library/functions.html#int>) โ€” the minimum number of instances the group keeps at all times ๐Ÿซถ
  • max_size (int </usr/share/doc/python3/html/library/functions.html#int>) โ€” the maximum number of instances the group is allowed to have at any one time ๐Ÿ™ˆ
  • instance_types (Optional[collections.abc.Iterable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterable>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]]) โ€” this uses a pool over the instance types you list, instead of the type in the launch template. For on-demand groups it's a prioritized list. For spot groups, AWS balances things according to spot_strategy. It must be 20 types or fewer. ๐Ÿง 
  • spot_bid (Optional[float </usr/share/doc/python3/html/library/functions.html#float>]) โ€” if you set this, the ASG becomes a spot market ASG. The bid is in dollars per instance hour, and every instance type in the group gets bid on equivalently ๐Ÿ’ธ
  • spot_cheapest (bool </usr/share/doc/python3/html/library/functions.html#bool>) โ€” if true, it grabs the cheapest spot instances available out of instance_types, instead of the ones that minimize eviction probability ๐Ÿฆ‹
  • tags (Optional[dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str>]]) โ€” tags applied to the ASG only. If you want tags on the instances, add them to the launch template instead ๐Ÿท๏ธ

Return type: None ๐Ÿซง

The default version of the launch template is used. ๐Ÿ’…


toil.lib.ec2nodes

Attributes

  • logger ๐Ÿ“
  • manager ๐Ÿง‘โ€๐Ÿ’ผ
  • dirname ๐Ÿ“‚
  • region_json_dirname ๐Ÿ—‚๏ธ
  • EC2Regions ๐ŸŒ

Classes

  • InstanceType ๐Ÿ‘‘

Functions

  • is_number(s) โ€” determines if a unicode string (that may include commas) is a number. ๐Ÿ”ข
  • parse_storage(storage_info) โ€” parses the EC2 JSON storage param string into a number. ๐Ÿ’ฝ
  • parse_memory(mem_info) โ€” returns the EC2 'memory' string as a float. ๐Ÿง 
  • download_region_json(filename[, region]) โ€” downloads and writes the AWS Billing JSON to a file, using the AWS pricing API. ๐Ÿ’ฐ
  • reduce_region_json_size(filename) โ€” deletes the info in the JSON file that we don't need, then rewrites it. This makes the file smaller. โœ‚๏ธ
  • updateStaticEC2Instances() โ€” generates a new Python file of fetchable EC2 Instances by region, with current prices and specs. โญ

Module Contents

  • toil.lib.ec2nodes.logger ๐Ÿ“
  • toil.lib.ec2nodes.manager ๐Ÿง‘โ€๐Ÿ’ผ
  • toil.lib.ec2nodes.dirname ๐Ÿ“‚
  • toil.lib.ec2nodes.region_json_dirname ๐Ÿ—‚๏ธ
  • toil.lib.ec2nodes.EC2Regions ๐ŸŒ

class toil.lib.ec2nodes.InstanceType(name, cores, memory, disks, disk_capacity, architecture)

class toil.lib.ec2nodes.InstanceType(name, cores, memory, disks, disk_capacity, architecture)

Parameters

  • name (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐ŸŒท
  • cores (int </usr/share/doc/python3/html/library/functions.html#int>) ๐Ÿงฉ
  • memory (float </usr/share/doc/python3/html/library/functions.html#float>) ๐Ÿง 
  • disks (float </usr/share/doc/python3/html/library/functions.html#float>) ๐Ÿ’ฟ
  • disk_capacity (float </usr/share/doc/python3/html/library/functions.html#float>) ๐Ÿ“ฆ
  • architecture (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿ—๏ธ
__slots__ = ('name', 'cores', 'memory', 'disks', 'disk_capacity', 'architecture')

Attributes: name, cores, memory, disks, disk_capacity, architecture ๐Ÿฆ‹

  • __str__() โ€” Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str> ๐Ÿซถ
  • __eq__(other) โ€” Parameters: other (object </usr/share/doc/python3/html/library/functions.html#object>); Return type: bool </usr/share/doc/python3/html/library/functions.html#bool> ๐Ÿ”ฅ

toil.lib.ec2nodes.is_number(s)

toil.lib.ec2nodes.is_number(s)

Determines if a unicode string (that may include commas) is a number. ๐Ÿ”ข

Parameters

  • s (str </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” any unicode string ๐Ÿ’–

Returns: True if s represents a number, False otherwise. โœ…

Return type: bool </usr/share/doc/python3/html/library/functions.html#bool> ๐ŸŒˆ


toil.lib.ec2nodes.parse_storage(storage_info)

toil.lib.ec2nodes.parse_storage(storage_info)

Parses the EC2 JSON storage param string into a number. ๐Ÿ’ฝ

Examples:

"2 x 160 SSD" "3 x 2000 HDD" "EBS only" "1 x 410" "8 x 1.9 NVMe SSD" "900 GB NVMe SSD"

Parameters ๐Ÿ’–

  • storage_info (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the EC2 JSON storage param string. That's the whole input, bestie ๐Ÿ’พ

Returns โœจ

  • Two floats representing: (# of disks), and (disk_capacity in GiB of each disk). So you get the disk count and the size of each disk ๐Ÿซถ

Return type ๐ŸŽ€

Union[list[int], tuple[Union[int, float], float]]

Doc refs for the types above: list (/usr/share/doc/python3/html/library/stdtypes.html#list), int (/usr/share/doc/python3/html/library/functions.html#int), tuple (/usr/share/doc/python3/html/library/stdtypes.html#tuple), float (/usr/share/doc/python3/html/library/functions.html#float).


โœจ toil.lib.ec2nodes.parse_memory(mem_info) โœจ

okay so this one turns EC2's memory string into a float ๐Ÿง  The format should always be # GiB, like '244 GiB' or '1,952 GiB'. Amazon really loves putting commas in their numbers, so this function has to handle that ๐Ÿ˜ญ And if the syntax ever changes, it's going to raise. No silent guessing, which is honestly iconic ๐Ÿ’…

Parameters ๐ŸŒธ

  • mem_info (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the EC2 JSON memory param string.

Returns ๐Ÿ’œ

  • A float representing memory in GiB.

Return type ๐Ÿฆ‹

  • float (/usr/share/doc/python3/html/library/functions.html#float)

โœจ toil.lib.ec2nodes.download_region_json(filename, region='us-east-1') โœจ

this one downloads and writes the AWS Billing JSON to a file using the AWS pricing API ๐Ÿ›’ The API reference is here: https://aws.amazon.com/blogs/aws/new-aws-price-list-api/ ๐Ÿ”—

Returns ๐Ÿ“

  • A dict of InstanceType objects. The key is the string AWS instance name (example: 't2.micro'), and the value is an InstanceType object representing that AWS instance name. Main character energy ๐Ÿ‘‘

Parameters ๐Ÿงš

  • filename (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • region (str, /usr/share/doc/python3/html/library/stdtypes.html#str), with the default 'us-east-1'

Return type ๐ŸŒˆ

  • None

โœจ toil.lib.ec2nodes.reduce_region_json_size(filename) โœจ

this one deletes the info in the JSON file that we don't need, then rewrites it so the file is smaller ๐Ÿช„ The whole reason is the history ๐Ÿ˜ญ We used to download the unified AWS Bulk API JSON, and it eventually crept up to 5.6Gb. Loading that was impossible on a 32Gb RAM machine ๐Ÿ’€ Now we download each region JSON individually with AWS's new Query API. Those can still grow ridiculously large one day, so we do what we can to keep the file sizes down (and the amount loaded into memory too). That keeps this script working for longer ๐Ÿซถ

Parameters ๐Ÿ’…

  • filename (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type โœจ

  • list (/usr/share/doc/python3/html/library/stdtypes.html#list)[dict (/usr/share/doc/python3/html/library/stdtypes.html#dict)[str (/usr/share/doc/python3/html/library/stdtypes.html#str), Any]]

โœจ toil.lib.ec2nodes.updateStaticEC2Instances() โœจ

this one generates a brand new Python file of fetchable EC2 instances, sorted by region, with current prices and specs ๐Ÿค‘ Heads up, it takes a few (~3+) minutes to run, so you'll need decent internet ๐ŸŒ

Returns ๐Ÿ”ฅ

  • Nothing. It writes a new 'generatedEC2Lists.py' file. ๐Ÿ“

Return type ๐Ÿ’œ

  • None

โœจ toil.lib.encryption โœจ

Submodules ๐ŸŽ€

  • toil.lib.encryption.conftest

Attributes ๐ŸŒธ

  • collect_ignore

Module Contents ๐Ÿฆ‹

toil.lib.encryption.conftest.collect_ignore = []

โœจ toil.lib.exceptions โœจ

Exceptions ๐Ÿ™ˆ

  • UnimplementedURLException โ€” Unspecified run-time error.

Classes ๐Ÿ“

  • panic โ€” The Python idiom for reraising a primary exception fails when the except block raises a

Functions ๐Ÿงš

  • raise_(exc_type, exc_value, traceback)

Module Contents ๐Ÿ’œ

okay so panic is a class, and it's a contextmanager ๐Ÿซ  The Python idiom for reraising a primary exception fails when the except block raises a secondary exception, like while trying to clean up. Then the original exception gets lost and the secondary one is what gets reraised. The fix is to save the primary exception info from sys.exc_info() and reraise that instead โœจ

It's meant to be used like this:

try:   # do something that can fail

except:

       with panic( log ):
              # do cleanup that can also fail

If a logging logger is passed to panic(), any secondary Exception raised within the with block gets logged. Otherwise those exceptions are swallowed ๐Ÿ‘€ At the end of the with block, the primary exception gets reraised.

Parameters ๐ŸŒˆ

  • log (Optional[logging.Logger], /usr/share/doc/python3/html/library/logging.html#logging.Logger)

Class attributes and methods:

  • log = None
  • exc_info = None
  • __enter__() โ€” Return type: None
  • __exit__(*exc_info) โ€” Return type: None

toil.lib.exceptions.raise_(exc_type, exc_value, traceback) takes these:

  • exc_type (Optional[type[BaseException]], /usr/share/doc/python3/html/library/functions.html#type and /usr/share/doc/python3/html/library/exceptions.html#BaseException)
  • exc_value (Optional[BaseException], /usr/share/doc/python3/html/library/exceptions.html#BaseException)
  • traceback (Optional[types.TracebackType], /usr/share/doc/python3/html/library/types.html#types.TracebackType)

Return type ๐Ÿ’–

  • None

exception toil.lib.exceptions.UnimplementedURLException(url, operation) ๐Ÿšจ

Bases: RuntimeError (/usr/share/doc/python3/html/library/exceptions.html#RuntimeError). Unspecified run-time error, bestie ๐Ÿ’€

Parameters ๐Ÿซถ

  • url (urllib.parse.ParseResult, /usr/share/doc/python3/html/library/urllib.parse.html#urllib.parse.ParseResult)
  • operation (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ toil.lib.expando โœจ

Classes ๐Ÿ’…

  • Expando โ€” Pass initial attributes to the constructor:
  • MagicExpando โ€” Use MagicExpando for chained attribute access.

Module Contents โœจ

class toil.lib.expando.Expando(*args, **kwargs) is so cute ๐Ÿฅน

Bases: dict (/usr/share/doc/python3/html/library/stdtypes.html#dict)

Pass initial attributes to the constructor:

>>> o = Expando(foo=42)
>>> o.foo
42

Dynamically create new attributes:

>>> o.bar = 'hi'
>>> o.bar
'hi'

Expando is a dictionary:

>>> isinstance(o,dict)
True
>>> o['foo']
42

Works great with JSON:

>>> import json
>>> s='{"foo":42}'
>>> o = json.loads(s,object_hook=Expando)
>>> o.foo
42
>>> o.bar = 'hi'
>>> o.bar
'hi'

And since Expando is a dict, it serializes back to JSON just fine:

>>> json.dumps(o, sort_keys=True)
'{"bar": "hi", "foo": 42}'

Attributes can be deleted, too:

>>> o = Expando(foo=42)
>>> o.foo
42
>>> del o.foo
>>> o.foo
Traceback (most recent call last):
...
AttributeError: 'Expando' object has no attribute 'foo'
>>> o['foo']
Traceback (most recent call last):
...
KeyError: 'foo'

>>> del o.foo
Traceback (most recent call last):
...
AttributeError: 'Expando' object has no attribute 'foo'

And copied:

>>> o = Expando(foo=42)
>>> p = o.copy()
>>> isinstance(p,Expando)
True
>>> o == p
True
>>> o is p
False

Same with MagicExpando ...

>>> o = MagicExpando()
>>> o.foo.bar = 42
>>> p = o.copy()
>>> isinstance(p,MagicExpando)
True
>>> o == p
True
>>> o is p
False

... but the copy is shallow:

>>> o.foo is p.foo
True

Class attributes and methods:

  • __slots__ = None
  • __dict__
  • copy() โ€” Return a shallow copy of the dict.

class toil.lib.expando.MagicExpando(*args, **kwargs) ๐Ÿช„

Bases: Expando

MagicExpando is giving chained attribute access, bestie ๐Ÿ’… Use it when you want to dig through nested stuff without it being a whole thing ๐Ÿฆ‹

The first time you poke at a missing attribute, it gets auto-filled with a brand new child MagicExpando โœจ Watch:

>>> o=MagicExpando()
>>> o.foo = 42
>>> o
{'foo': 42}
>>> o.bar.hello = 'hi'
>>> o.bar
{'hello': 'hi'}

__getattribute__(name) ๐ŸŒธ Literally just returns getattr(self, name), no cap ๐Ÿ’–

Parameters

  • name (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

๐Ÿ’– toil.lib.ftp_utils ๐Ÿ’–

๐ŸŽ€ Attributes

  • logger

๐ŸŽ€ Classes

  • FtpFsAccess โ€” FTP access with upload ๐Ÿ“ค

๐ŸŽ€ Module Contents

toil.lib.ftp_utils.logger

class toil.lib.ftp_utils.FtpFsAccess(cache=None) ๐Ÿฆ‹ FTP access with upload. Taken and modified from <https://github.com/ohsu-comp-bio/cwl-tes/blob/03f0096f9fae8acd527687d3460a726e09190c3a/cwl_tes/ftp.py#L37-L251> ๐Ÿซถ

Parameters

  • cache (Optional[dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[Any, ftplib.FTP </usr/share/doc/python3/html/library/ftplib.html#ftplib.FTP>]])

Class attributes ๐ŸŽ€

  • cache
  • netrc = None

exists(fn) ๐Ÿ” Checks if a file or directory exists over an FTP server. You pass in an FTP url as fn, and you get back True or False depending on whether the object exists on the server ๐Ÿ’…

Parameters

  • fn (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

  • bool </usr/share/doc/python3/html/library/functions.html#bool>

isfile(fn) ๐Ÿ“„ Checks if the FTP url points to a file. True if it's a file, otherwise False ๐Ÿ™Œ

Parameters

  • fn (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

  • bool </usr/share/doc/python3/html/library/functions.html#bool>

isdir(fn) ๐Ÿ“ Checks if the FTP url points to a directory. True if it's a directory, otherwise False ๐Ÿ’–

Parameters

  • fn (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

  • bool </usr/share/doc/python3/html/library/functions.html#bool>

open(fn, mode) ๐Ÿ“– Opens an FTP url. Heads up, this one is read-only, so no write support here ๐Ÿ™…โ€โ™€๏ธ

Read-only, bestie. There is no write support for this method.

Parameters

  • fn (str </usr/share/doc/python3/html/library/stdtypes.html#str>), the FTP url
  • mode (str </usr/share/doc/python3/html/library/stdtypes.html#str>), the mode to open the FTP url in

Return type

  • IO[bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes>]

size(fn) ๐Ÿ“ Gets the size of an FTP object. You pass in the FTP url as fn and get back the size of the object ๐Ÿ’…

Parameters

  • fn (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type

  • Optional[int </usr/share/doc/python3/html/library/functions.html#int>]

๐Ÿ’œ toil.lib.generatedEC2Lists ๐Ÿ’œ

๐ŸŽ€ Attributes

  • E2Instances
  • regionDict
  • ec2InstancesByRegion

๐ŸŽ€ Module Contents

  • toil.lib.generatedEC2Lists.E2Instances
  • toil.lib.generatedEC2Lists.regionDict
  • toil.lib.generatedEC2Lists.ec2InstancesByRegion

๐Ÿงš toil.lib.history ๐Ÿงš

Contains tools for tracking history ๐Ÿ—‚๏ธ

๐ŸŽ€ Attributes

  • logger
  • RT

๐ŸŽ€ Exceptions

  • HistoryDatabaseSchemaTooNewError โ€” Raised when we would write to the history database, but its schema is too

๐ŸŽ€ Classes

  • WorkflowSummary โ€” Data class holding summary information for a workflow โœจ
  • WorkflowAttemptSummary โ€” Data class holding summary information for a workflow attempt โœจ
  • JobAttemptSummary โ€” Data class holding summary information for a job attempt within a known
  • HistoryManager โ€” Class responsible for managing the history of Toil runs ๐Ÿ‘‘

๐ŸŽ€ Functions

  • db_retry(function) โ€” Decorates a function with the appropriate retries for accessing the database ๐Ÿ”

๐ŸŽ€ Module Contents

toil.lib.history.logger

exception toil.lib.history.HistoryDatabaseSchemaTooNewError ๐Ÿ™ˆ Bases: RuntimeError </usr/share/doc/python3/html/library/exceptions.html#RuntimeError>

Raised when we would write to the history database, but its schema is too new for us to understand ๐Ÿ˜ญ

class toil.lib.history.WorkflowSummary ๐ŸŒˆ Data class holding summary information for a workflow. It represents all the attempts to execute one run of a workflow ๐Ÿ’–

Fields

  • id: str </usr/share/doc/python3/html/library/stdtypes.html#str>
  • name: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>
  • job_store: str </usr/share/doc/python3/html/library/stdtypes.html#str>
  • total_attempts: int </usr/share/doc/python3/html/library/functions.html#int>
  • total_job_attempts: int </usr/share/doc/python3/html/library/functions.html#int>
  • succeeded: bool </usr/share/doc/python3/html/library/functions.html#bool>
  • start_time: float </usr/share/doc/python3/html/library/functions.html#float> | None </usr/share/doc/python3/html/library/constants.html#None>
    • Time when the first workflow attempt started, in seconds since epoch โฐ
    • None if there are no attempts recorded
  • runtime: float </usr/share/doc/python3/html/library/functions.html#float> | None </usr/share/doc/python3/html/library/constants.html#None>
    • Time from the first workflow attempt's start to the last one's end, in seconds โฑ๏ธ
    • None if there are no attempts recorded
  • trs_spec: str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>

class toil.lib.history.WorkflowAttemptSummary ๐Ÿฆ‹ Data class holding summary information for a workflow attempt. It helpfully includes the workflow metadata for Dockstore ๐Ÿซถ

Fields

  • workflow_id: str </usr/share/doc/python3/html/library/stdtypes.html#str>
  • attempt_number: int </usr/share/doc/python3/html/library/functions.html#int>
  • succeeded: bool </usr/share/doc/python3/html/library/functions.html#bool>
  • start_time: float </usr/share/doc/python3/html/library/functions.html#float>
  • runtime: float </usr/share/doc/python3/html/library/functions.html#float>
  • submitted_to_dockstore: bool </usr/share/doc/python3/html/library/functions.html#bool>
  • batch_system ๐ŸŒธ is a str (/usr/share/doc/python3/html/library/stdtypes.html#str) or None (/usr/share/doc/python3/html/library/constants.html#None), so str | None.
  • caching ๐Ÿฆ‹ is a bool (/usr/share/doc/python3/html/library/functions.html#bool) or None, so bool | None.
  • toil_version ๐Ÿ’œ is a str or None, so str | None.
  • python_version ๐Ÿ is a str or None, so str | None.
  • platform_system ๐Ÿ’ป is a str or None, so str | None.
  • platform_machine ๐Ÿ–ฅ๏ธ is a str or None, so str | None.
  • workflow_job_store ๐Ÿ—‚๏ธ is a str (no None option here), so str.
  • workflow_trs_spec ๐Ÿงพ is a str or None, so str | None.

๐ŸŽ€ class toil.lib.history.JobAttemptSummary

okay so this one is a data class ๐Ÿ’… that holds the summary info for one job attempt inside a workflow attempt we already know about โœจ

  • id ๐Ÿ†” โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • job_name ๐Ÿท๏ธ โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • succeeded ๐Ÿ† โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool)
  • start_time โฐ โ€” float (/usr/share/doc/python3/html/library/functions.html#float)
  • runtime โฑ๏ธ โ€” float (/usr/share/doc/python3/html/library/functions.html#float)
  • submitted_to_dockstore โ˜๏ธ โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool)
  • cores ๐Ÿง  โ€” float (/usr/share/doc/python3/html/library/functions.html#float) or None (/usr/share/doc/python3/html/library/constants.html#None)
  • cpu_seconds ๐Ÿ”ฅ โ€” float (/usr/share/doc/python3/html/library/functions.html#float) or None (/usr/share/doc/python3/html/library/constants.html#None)
  • memory_bytes ๐Ÿ’พ โ€” int (/usr/share/doc/python3/html/library/functions.html#int) or None (/usr/share/doc/python3/html/library/constants.html#None)
  • disk_bytes ๐Ÿ’ฟ โ€” int (/usr/share/doc/python3/html/library/functions.html#int) or None (/usr/share/doc/python3/html/library/constants.html#None)

๐Ÿงš toil.lib.history.RT

this one is just a type alias, no extra frills ๐Ÿ’œ

๐Ÿ” toil.lib.history.db_retry(function)

Decorate a function with the appropriate retries for accessing the database. ๐Ÿซถ

Parameters:

  • function โ€” Callable[Ellipsis, RT]

Return type: Callable[Ellipsis, RT]


๐Ÿ‘‘ class toil.lib.history.HistoryManager

Class responsible for managing the history of Toil runs. It's the main character of this whole module ๐Ÿ’…

classmethod enabled()

Return True if history should be read from and written to the database. ๐Ÿ”ฅ

If False, no access at all should be made to the database. ๐Ÿ™ˆ

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

classmethod enabled_job()

Return True if job history should be read from and written to the database. ๐ŸŒˆ

Always returns False if enabled() returns False.

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

database_path_override

A str (/usr/share/doc/python3/html/library/stdtypes.html#str) or None (/usr/share/doc/python3/html/library/constants.html#None), so str | None, with a default of None โœจ

classmethod database_path()

Get the path at which the database we store history in lives. ๐Ÿ—บ๏ธ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

classmethod connection()

Connect to the history database. ๐Ÿ“

โš ๏ธ Caller must not actually use the connection without using ensure_tables() to protect reads and updates.
โš ๏ธ Must be called from inside a top-level method marked @db_retry.

The connection will be in DEFERRED isolation_level, with autocommit off on Python versions that support it. ๐Ÿงƒ If you want to run any commands outside of a transaction, use the no_transaction context manager.

Return type: sqlite3.Connection (/usr/share/doc/python3/html/library/sqlite3.html#sqlite3.Connection)

classmethod no_transaction(con)

Temporarily disable the constant active transaction on the database connection, on Python versions where it exists. ๐Ÿง

Commits the current transaction. ๐Ÿ’Œ

Parameters:

  • con โ€” sqlite3.Connection (/usr/share/doc/python3/html/library/sqlite3.html#sqlite3.Connection)

Return type: Iterator[None]

classmethod ensure_tables(con, cur)

Ensure that tables exist in the database and the schema is migrated to the current version. ๐Ÿงน

Leaves the cursor in a transaction where the schema version is known to be correct. ๐Ÿ”’

โš ๏ธ Must be called from inside a top-level method marked @db_retry.
๐Ÿšจ Raises HistoryDatabaseSchemaTooNewError (#toil.lib.history.HistoryDatabaseSchemaTooNewError) -- if the schema is newer than the current version. ๐Ÿ’€

Parameters:

  • con โ€” sqlite3.Connection (/usr/share/doc/python3/html/library/sqlite3.html#sqlite3.Connection)
  • cur โ€” sqlite3.Cursor (/usr/share/doc/python3/html/library/sqlite3.html#sqlite3.Cursor)

Return type: None

classmethod record_workflow_creation(workflow_id, job_store_spec)

Record that a workflow is being run. ๐Ÿฆ‹

Takes the Toil config's workflow ID and the location of the job store. ๐Ÿ—‚๏ธ

Should only be called on the first attempt on a job store, not on a restart. ๐Ÿ™…โ€โ™€๏ธ

A workflow may have multiple attempts to run it, some of which succeed and others of which fail. Probably only the last one should succeed. ๐Ÿคž

Parameters:

  • job_store_spec โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) -- The job store specifier for the workflow. It should be canonical and always start with the type and a colon. If the job store is later moved by the user, the location will not be updated. ๐Ÿ“
  • workflow_id โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None

classmethod record_workflow_metadata(workflow_id, workflow_name, trs_spec=None)

Associate a name and optionally a TRS ID and version with a workflow run. ๐Ÿท๏ธ๐Ÿ’–

Parameters:

  • workflow_id โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • workflow_name โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • trs_spec โ€” Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/constants.html#None)

Return type: None

classmethod record_job_attempt(workflow_id, workflow_attempt_number, job_name, succeeded, start_time, runtime, cores=None, cpu_seconds=None, memory_bytes=None, disk_bytes=None)

Record that a job ran in a workflow. ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

Doesn't expect the info you give it to uniquely identify the job attempt; it assigns the job attempt its own unique ID. ๐Ÿ†”

Thread safe! ๐ŸŒˆ

Parameters:

  • job_name โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) -- A human-readable name for the job. It's not expected to be a job store ID or to necessarily uniquely identify the job within the workflow. ๐Ÿ™ˆ
  • start_time โ€” float (/usr/share/doc/python3/html/library/functions.html#float) -- Job execution start time in seconds since epoch. โฐ
  • runtime โ€” float (/usr/share/doc/python3/html/library/functions.html#float) -- Job execution duration in seconds. โฑ๏ธ
  • cores โ€” Optional[float] (/usr/share/doc/python3/html/library/functions.html#float, /usr/share/doc/python3/html/library/constants.html#None) -- Number of CPU cores the job was scheduled on. ๐Ÿง 
  • cpu_seconds โ€” Optional[float] (/usr/share/doc/python3/html/library/functions.html#float, /usr/share/doc/python3/html/library/constants.html#None) -- CPU core-seconds actually consumed. ๐Ÿ”ฅ
  • memory_bytes โ€” Optional[int] (/usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/constants.html#None) -- Peak observed job memory usage. ๐Ÿ’พ
  • disk_bytes โ€” Optional[int] (/usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/constants.html#None) -- Observed job disk usage. ๐Ÿ’ฟ
  • workflow_id โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • workflow_attempt_number โ€” int (/usr/share/doc/python3/html/library/functions.html#int)
  • succeeded โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool)

Return type: None

โœจ record_workflow_attempt โœจ

classmethod record_workflow_attempt(workflow_id, workflow_attempt_number, succeeded, start_time, runtime, batch_system=None, caching=None, toil_version=None, python_version=None, platform_system=None, platform_machine=None)

Okay bestie, this one records a workflow attempt (a start or a restart) once it has finished or failed. ๐Ÿ’…

Parameters

  • batch_system (Optional[str]) โ€” the Python type name of the batch system implementation that got used ๐ŸšŒ
  • caching (Optional[bool]) โ€” whether Toil filestore-level caching was turned on ๐Ÿ’พ
  • toil_version (Optional[str]) โ€” the version of Toil that ran the workflow ๐Ÿงš
  • python_version (Optional[str]) โ€” the version of Python that ran the workflow ๐Ÿ
  • platform_system (Optional[str]) โ€” the OS that ran the workflow, like "Darwin", "Linux", etc. ๐ŸŽ
  • platform_machine (Optional[str]) โ€” the CPU type that ran the workflow leader, like "AMD64", etc. ๐Ÿ–ฅ๏ธ
  • workflow_id (str)
  • workflow_attempt_number (int)
  • succeeded (bool)
  • start_time (float)
  • runtime (float)

Return type: None


โœจ summarize_workflows โœจ

classmethod summarize_workflows()

This one is giving "show me everything" ๐Ÿ‘€. It lists all known workflows along with their summary stats. ๐Ÿ“Š

Return type: list[WorkflowSummary]


โœจ get_submittable_workflow_attempts โœจ

classmethod get_submittable_workflow_attempts(limit=sys.maxsize)

Lowkey a to-do list ๐Ÿ“. It lists every workflow attempt that hasn't been submitted to Dockstore yet.

Parameters

  • limit (int) โ€” get no more than this many ๐ŸŽฏ

Return type: list[WorkflowAttemptSummary]


โœจ get_workflow_attempts_with_submittable_job_attempts โœจ

classmethod get_workflow_attempts_with_submittable_job_attempts(limit=sys.maxsize)

This one gets all the workflow attempts that have job attempts still waiting to be submitted to Dockstore ๐Ÿฆ‹. The workflow attempts themselves will have already finished and been recorded, and they'll have TRS IDs.

Parameters

  • limit (int) โ€” get no more than this many ๐ŸŽฏ

Return type: list[WorkflowAttemptSummary]


โœจ get_workflow_attempt โœจ

classmethod get_workflow_attempt(workflow_id, attempt_number)

Main character energy ๐Ÿ‘‘. This gets a single workflow attempt summary, if it's there. It doesn't have to be unsubmitted, and it doesn't have to have a TRS ID, so it's pretty flexible ๐Ÿซถ.

Parameters

  • workflow_id (str)
  • attempt_number (int)

Return type: Optional[WorkflowAttemptSummary]


โœจ get_unsubmitted_job_attempts โœจ

classmethod get_unsubmitted_job_attempts(workflow_id, attempt_number)

This lists all the job attempts in the given workflow attempt that haven't been submitted to Dockstore yet ๐ŸŒธ. Heads up: it doesn't check whether the workflow actually has a TRS ID ๐Ÿ™ˆ.

Parameters

  • workflow_id (str)
  • attempt_number (int)

Return type: list[JobAttemptSummary]


โœจ mark_workflow_attempt_submitted โœจ

classmethod mark_workflow_attempt_submitted(workflow_id, attempt_number)

This one marks a workflow attempt as successfully submitted to Dockstore โœ…. It does not mark that attempt's job attempts as submitted, so those still need their own update ๐Ÿ™ƒ.

Parameters

  • workflow_id (str)
  • attempt_number (int)

Return type: None


โœจ mark_job_attempts_submitted โœจ

classmethod mark_job_attempts_submitted(job_attempt_ids)

Bulk update energy ๐Ÿ”ฅ. This marks a whole collection of job attempts as submitted to Dockstore in a single transaction.

Parameters

  • job_attempt_ids (list[str])

Return type: None


โœจ count_workflows โœจ

classmethod count_workflows()

Counts the workflows in the database ๐Ÿ”ข.

Return type: int


โœจ count_workflow_attempts โœจ

classmethod count_workflow_attempts()

Counts the workflow attempts in the database ๐Ÿ”ข.

Return type: int


โœจ count_job_attempts โœจ

classmethod count_job_attempts()

Counts the job attempts in the database ๐Ÿ”ข.

Return type: int


โœจ get_fully_submitted_workflow_ids โœจ

classmethod get_fully_submitted_workflow_ids(limit=sys.maxsize)

This one finds the workflows that have a successful attempt and no unsubmitted attempts or job attempts. Fully done and dusted ๐Ÿ’–.

Parameters

  • limit (int)

Return type: list[str]


โœจ get_oldest_workflow_ids โœจ

classmethod get_oldest_workflow_ids(limit=sys.maxsize)

Gets the workflows that are old ๐Ÿง“. Ngl, the name says it all.

Parameters

  • limit (int)

Return type: list[str]


โœจ delete_workflow โœจ

classmethod delete_workflow(workflow_id)
โš ๏ธ Bestie, this one is destructive. It deletes a workflow and all of its attempts and job attempts, so it's gone for good ๐Ÿ’€.

It succeeds if the workflow does not exist, so calling it on something that's already gone won't throw a fit ๐Ÿซถ.

Parameters

  • workflow_id (str)

Return type: None


โœจ get_database_byte_size โœจ

classmethod get_database_byte_size()

Gets the total number of bytes the database is using ๐Ÿ“.

Return type: int


โœจ compact_database โœจ

classmethod compact_database()

Declutter arc ๐Ÿงน. This shrinks the database to remove unused space ๐ŸŒˆ.

Return type: None


โœจ enforce_byte_size_limit โœจ

classmethod enforce_byte_size_limit(limit=100 * 1024 * 1024)

This is the glow-up you didn't know you needed โœจ. It shrinks the database until it's smaller than the given limit, or until it's empty, by throwing away workflows. The data gets tossed in a sensible order, from least important to most important ๐Ÿ—‘๏ธ.

Parameters

  • limit (int)

Return type: None


โœจ database_dump_lines โœจ

classmethod database_dump_lines()

This yields lines from the database dump ๐Ÿงพ. It's meant for debugging tests, so it's a dev-only kind of moment ๐Ÿ™ˆ.

Return type: Iterable[str]


โœจ toil.lib.history_submission โœจ

Contains logic for generating Toil usage history reports to send back to Toil HQ (via Dockstore) ๐Ÿ’œ, and for working out if the user actually wants to send them ๐Ÿซถ.

โœจ Attributes โœจ

okay so the attributes are literally just names on the page, no descriptions, so we're vibing off the vibes ๐Ÿ™ˆ

  • logger
  • KeyType
  • Decision
  • DIALOG_TITLE
  • DIALOG_TEXT
  • DIALOG_OPTIONS
  • DIALOG_TIMEOUT

Classes

  • Submission โ€” the class holding a package of information to submit to Dockstore, and the (the docs just trail off there ๐Ÿ’€)

Functions

bestie, this is the lineup of functions. the big ones get their own deep dive below ๐Ÿซถ

  • workflow_execution_id(workflow_attempt) โ€” get the execution ID for a workflow attempt.
  • workflow_task_set_execution_id(workflow_attempt) โ€” get the execution ID for a workflow attempt's collection of tasks.
  • job_execution_id(job_attempt) โ€” get the execution ID for a job attempt.
  • get_parsed_trs_spec(workflow_attempt) โ€” get the TRS ID and version of the workflow, or raise an error.
  • create_history_submission([batch_size, desired_tasks]) โ€” make a package of data about recent workflow runs to send in.
  • create_current_submission(workflow_id, attempt_number) โ€” make a package of data about the current workflow attempt to send in.
  • dialog_tkinter(title, text, options, timeout) โ€” display a dialog with tkinter.
  • display_dialog_tkinter(title, text, options, timeout, ...) โ€” display a dialog with tkinter in the current process.
  • dialog_tui(title, text, options, timeout) โ€” display a dialog in the terminal.
  • ask_user_about_publishing_metrics() โ€” ask the user to set standing workflow submission consent.

Module Contents

toil.lib.history_submission.logger

toil.lib.history_submission.workflow_execution_id(workflow_attempt)

Get the execution ID for a workflow attempt. โœจ

Result will follow Dockstore's rules.

Deterministic. (no randomness, no surprises, same input gives the same output ๐Ÿ”ฎ)

Parameters

  • workflow_attempt (toil.lib.history.WorkflowAttemptSummary)

Return type

  • str

toil.lib.history_submission.workflow_task_set_execution_id(workflow_attempt)

Get the execution ID for a workflow attempt's collection of tasks. ๐Ÿงš

Result will follow Dockstore's rules.

Deterministic.

Parameters

  • workflow_attempt (toil.lib.history.WorkflowAttemptSummary)

Return type

  • str

toil.lib.history_submission.job_execution_id(job_attempt)

Get the execution ID for a job attempt. ๐Ÿ’–

Result will follow Dockstore's rules.

Deterministic.

Parameters

  • job_attempt (toil.lib.history.JobAttemptSummary)

Return type

  • str

toil.lib.history_submission.get_parsed_trs_spec(workflow_attempt)

Get the TRS ID and version of the workflow, or raise an error. ๐Ÿ‘‘

Returns

The TRS ID and the TRS version of the workflow run.

Raises ValueError if the workflow does not have a TRS spec or if the spec does not contain a version. Not it, bestie ๐Ÿ˜ญ

Parameters

  • workflow_attempt (toil.lib.history.WorkflowAttemptSummary)

Return type

  • tuple[str, str]

class toil.lib.history_submission.Submission

Class holding a package of information to submit to Dockstore, and the information needed to mark the workflows/tasks as submitted if it is accepted.

Acceptance is at the TRS id/version combination level within the Submission, since we need one request per TRS ID/version combination. So it's one request per combo, no shortcuts ๐Ÿฆ‹

data:

dict[tuple[str, str], tuple[list[tuple[toil.lib.dockstore.RunExecution, str, int]], list[tuple[toil.lib.dockstore.TaskExecutions, list[str]]]]]

add_workflow_attempt(workflow_attempt)

Add a workflow attempt to the submission. ๐ŸŒธ

May raise an exception if the workflow attempt is not well-formed.

Parameters

  • workflow_attempt (toil.lib.history.WorkflowAttemptSummary)

Return type

  • None

add_job_attempts(workflow_attempt, job_attempts)

Add the job attempts for a workflow attempt to the submission. ๐ŸŽ€

Parameters

  • workflow_attempt (toil.lib.history.WorkflowAttemptSummary)
  • job_attempts (list[toil.lib.history.JobAttemptSummary]) ๐Ÿ’–

Return type: None ๐ŸŒธ

empty()

Okay so this one is the vibe check ๐Ÿซถ It returns True if there is literally nothing to submit. Zero tasks, zero workflows, it's giving "nothing to see here, bestie" ๐Ÿ’€

Return type: bool

report()

Need a recap before you hit send? โœจ report() composes a multi-line, human-readable string about everything that's going to get submitted. Main character recap energy ๐Ÿ’…

Return type: str

submit()

The big moment ๐Ÿ”ฅ submit() sends workflow and task information over to Dockstore. It takes for granted that you already approved this, so make sure you did ๐Ÿ™ˆ

If the submission succeeds for a TRS id/version combination, it gets recorded in the history database ๐Ÿ“ No ghosting, it's logged.

Errors get handled internally, so it will not raise if the submission doesn't go through ๐Ÿซถ

It returns False if there was any error, and True if the submission was accepted and recorded locally โœจ

Return type: bool

toil.lib.history_submission.create_history_submission(batch_size=None, desired_tasks=None)

Okay this one packages up a whole bundle of data about your recent workflow runs so it can be sent in ๐ŸŽ€ It hands back a Submission object that remembers how to update the history database to mark when it's successfully submitted. So organized, so iconic ๐Ÿ‘‘

Parameters

  • batch_size (Optional[int]) โ€” how many workflows to try and submit in one request ๐Ÿ“
  • desired_tasks (Optional[int]) โ€” how many tasks to try and squeeze into a task submission batch. Use 0 if you don't want any task information sent at all ๐Ÿ™…

Return type: Submission

toil.lib.history_submission.create_current_submission(workflow_id, attempt_number)

Same energy, smaller footprint ๐Ÿฆ‹ This one bundles up data about only the current workflow attempt. It's the move when you just want to publish metrics for this one time ๐Ÿ’œ

Parameters

  • workflow_id (str)
  • attempt_number (int)

Return type: Submission

toil.lib.history_submission.KeyType

Just a bare name in the docs, no extra details ๐Ÿงš

toil.lib.history_submission.dialog_tkinter(title, text, options, timeout)

Okay this dialog is so cute ๐ŸŽ€ It pops up a tkinter dialog with the title, text, and options you give it. It runs in its own separate Python process, so a Mac dock icon doesn't hang around for as long as Toil is running (nobody wants a zombie dock icon ๐Ÿ’€).

Parameters

  • options (dict[KeyType, str]) โ€” a dict mapping each machine-readable option key to its button text ๐ŸŒˆ
  • title (str)
  • text (str)
  • timeout (float)

Returns

The key of the option that got picked, or None if the user declined to pick one.

Raises an exception if the dialog can't be displayed ๐Ÿ˜ญ

Return type: Optional[KeyType]

toil.lib.history_submission.display_dialog_tkinter(title, text, options, timeout, result_queue)

Same tkinter dialog, but this one runs right in the current process ๐Ÿ’… Its whole job is to send back either the key of the chosen option or an exception through the result queue ๐Ÿ“ฌ

Parameters

  • options (dict[KeyType, str]) โ€” a dict mapping each machine-readable option key to its button text
  • title (str)
  • text (str)
  • timeout (float)
  • result_queue (multiprocessing.Queue[Union[Exception, Optional[KeyType]]])

Return type: None

toil.lib.history_submission.dialog_tui(title, text, options, timeout)

The terminal version of the dialog ๐Ÿ–ฅ๏ธ It shows the given title, text, and options right in your terminal, no pop-up window needed โœจ

Parameters

  • options (dict[KeyType, str]) โ€” a dict mapping each machine-readable option key to its button text
  • title (str)
  • text (str)
  • timeout (float)

Returns

The key of the option that got picked, or None if the user declined to pick one.

Raises an exception if the dialog can't be displayed ๐Ÿ˜ญ

Return type: Optional[KeyType]

toil.lib.history_submission.Decision

Another bare name with no extra details, bestie ๐Ÿงš

toil.lib.history_submission constants

  • toil.lib.history_submission.DIALOG_TITLE = 'Publish Workflow Metrics on Dockstore.org?' ๐Ÿซถ
  • toil.lib.history_submission.DIALOG_TEXT = '' (an empty string, so no body text by default)
  • toil.lib.history_submission.DIALOG_OPTIONS: dict[Decision, str] ๐Ÿ’œ
  • toil.lib.history_submission.DIALOG_TIMEOUT = 120 โฐ

toil.lib.history_submission.ask_user_about_publishing_metrics()

This one asks the user to set their standing consent for workflow submissions ๐Ÿ™‹ If they make a persistent choice, either always or never, it gets saved to the default Toil config file ๐Ÿ’พ

Returns the user's decision about when to publish metrics.

Return type: Union[Literal['all'], Literal['current'], Literal['no']]


toil.lib.humanize

Attributes

  • logger ๐Ÿชต

Functions

  • bytes2human(n) โ€” turns n bytes into a human readable string ๐Ÿ“
  • human2bytes(s) โ€” guesses the string format using the default symbols set, then gives you back the matching bytes as an integer ๐Ÿงฎ

Module Contents

  • toil.lib.humanize.logger

toil.lib.humanize.bytes2human(n)

Converts n bytes into a human readable string ๐ŸŒธ

Parameters

  • n (SupportsInt)

Return type: str

toil.lib.humanize.human2bytes(s)

Okay this one is lowkey clever ๐Ÿง  It attempts to guess the string format based on the default symbols set, then returns the corresponding bytes as an integer. If it can't recognize the format, a ValueError gets raised ๐Ÿ˜ญ

Parameters

  • s (str)

Return type: int


toil.lib.io

Attributes

  • logger
  • TOIL_URI_SCHEME
  • STANDARD_SCHEMES
  • REMOTE_SCHEMES
  • ALL_SCHEMES

None of these have a description listed, so you'll just have to vibe with the names ๐Ÿซง

โœจ Classes โœจ

okay so this section is only two classes, but they're both iconic ๐Ÿ’…

  • WriteWatchingStream โ€” a stream wrapper ๐ŸŒธ bestie, it quietly calls whatever functions you pass to onWrite(), and each time something gets written it tells them how many bytes were written that time ๐Ÿซถ
  • ReadableFileObj โ€” a Protocol ๐ŸŽ€ that's way more specific than what file_digest is willing to accept as an argument ๐Ÿ‘‘

โœจ Functions โœจ

the function list is huge, so here's the vibe check for each one ๐Ÿฆ‹

  • get_toil_home() โ€” gets the Toil home directory, where configuration and global state live ๐Ÿก
  • is_standard_url(filename) โ€” returns True if the given URL is a non-Toil, non-file: URL ๐ŸŒ
  • is_remote_url(filename) โ€” decides if a filename is a known, non-file kind of URL ๐Ÿ›ฐ๏ธ
  • is_any_url(filename) โ€” decides if a string is a URI like <http://> or <file://> ๐Ÿ”—
  • is_url_with_scheme(filename, schemes) โ€” returns True if filename is a URL with any of the given schemes, and False otherwise ๐ŸŽฏ
  • is_toil_url(filename) โ€” returns True if a URL is a toilfile: or toildir: URL ๐Ÿ’œ
  • is_toil_file_url(filename) โ€” returns True if a URL is a toilfile: URL ๐Ÿ“„
  • is_toil_dir_url(filename) โ€” returns True if a URL is a toildir: URL ๐Ÿ“
  • is_file_url(filename) โ€” returns True if a URL is a file: URL ๐Ÿซถ
  • is_directory_url(filename) โ€” returns True if a URL points to a directory ๐Ÿ—‚๏ธ
  • mkdtemp([suffix, prefix, dir]) โ€” makes a temporary directory just like tempfile.mkdtemp, but with relaxed permissions ๐Ÿงš
  • robust_rmtree(path) โ€” robustly tries to delete paths ๐Ÿงน
  • atomic_tmp_file(final_path) โ€” returns a tmp file name to use with atomic_install. This will be in theโ€ฆ (the docs literally just trail off right there ๐Ÿ’€)
  • atomic_install(tmp_path, final_path) โ€” atomically installs tmp_path as final_path โšก
  • AtomicFileCreate(final_path[, keep]) โ€” a context manager for creating a temporary file. Entering returns the path toโ€ฆ (and the docs cut off again, no cap ๐Ÿ™ˆ)
  • atomic_copy(src_path, dest_path[, executable]) โ€” copies a file using posix atomic creations semantics ๐Ÿ“‹
  • atomic_copyobj(src_fh, dest_path[, length, executable]) โ€” copies an open file using posix atomic creations semantics ๐Ÿ“‹
  • make_public_dir(in_directory[, suggested_name]) โ€” makes a publicly-accessible directory inside the given directory ๐Ÿ“ฃ
  • try_path(path[, min_size]) โ€” tries to use the given path. It returns it if it exists or can be made, ๐Ÿ’ญ (and the sentence just kinda hangs there with a comma)
  • file_digest(f, alg_name) โ€” a polyfilled hashlib.file_digest that works on Python <3.11 โช

๐Ÿ’– Module Contents ๐Ÿ’–

okay the main event ๐ŸŒˆ here's the full module reference, bestie

toil.lib.io.logger

โœจ toil.lib.io.get_toil_home() โœจ

Get the Toil home directory for storing configuration and global state.

Raises an error if it does not exist and cannot be created. Safe to run simultaneously in multiple processes. ๐Ÿงต

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŽ€ Constants ๐ŸŽ€

these are the scheme lists Toil uses, and they're literally the goods ๐Ÿงƒ

toil.lib.io.TOIL_URI_SCHEME = 'toilfile:'
toil.lib.io.STANDARD_SCHEMES = ['http:', 'https:', 's3:', 'gs:', 'ftp:']
toil.lib.io.REMOTE_SCHEMES = ['http:', 'https:', 's3:', 'gs:', 'ftp:', 'toilfile:', 'toildir:']
toil.lib.io.ALL_SCHEMES = ['http:', 'https:', 's3:', 'gs:', 'ftp:', 'toilfile:', 'toildir:', 'file:']

๐ŸŒ toil.lib.io.is_standard_url(filename) ๐ŸŒ

Return True if the given URL is a non-Toil, non-file: URL.

Parameters: filename (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿ›ฐ๏ธ toil.lib.io.is_remote_url(filename) ๐Ÿ›ฐ๏ธ

Decide if a filename is a known, non-file kind of URL.

Parameters: filename (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿ”— toil.lib.io.is_any_url(filename) ๐Ÿ”—

Decide if a string is a URI like <http://> or <file://>.

Otherwise it might be a bare path. ๐Ÿชต

Parameters: filename (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

๐ŸŽ€ toil.lib.io.is_url_with_scheme ๐ŸŽ€

toil.lib.io.is_url_with_scheme(filename, schemes)

Okay bestie, this one is the URL bouncer ๐Ÿ’… It returns True if filename is a URL with any of the given schemes, and False otherwise โœจ

Parameters

  • filename โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • schemes โ€” list[str] (/usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐Ÿฆ‹ toil.lib.io.is_toil_url ๐Ÿฆ‹

toil.lib.io.is_toil_url(filename)

Checks if a URL is a toilfile: or toildir: URL. Main character energy ๐Ÿ‘‘ Returns True if it is, False if not.

Parameters

  • filename โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐ŸŒธ toil.lib.io.is_toil_file_url ๐ŸŒธ

toil.lib.io.is_toil_file_url(filename)

This one is stricter. It only returns True for toilfile: URLs ๐Ÿซถ

Parameters

  • filename โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐Ÿงš toil.lib.io.is_toil_dir_url ๐Ÿงš

toil.lib.io.is_toil_dir_url(filename)

Returns True if a URL is a toildir: URL. ngl this is a little sneaky, so note that it might point to either a directory or a leaf file ๐Ÿ‘€

Parameters

  • filename โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐Ÿ’œ toil.lib.io.is_file_url ๐Ÿ’œ

toil.lib.io.is_file_url(filename)

Returns True if a URL is a file: URL.

Bare paths get a False, even if they're real. No cap, that's a real trap ๐Ÿ™ˆ

Parameters

  • filename โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐Ÿ“ toil.lib.io.is_directory_url ๐Ÿ“

toil.lib.io.is_directory_url(filename)

Returns True if a URL points to a directory. It covers toildir: URLs and determines whether they point to directories or leaf files. It also covers other supported remote URL schemes, so it's pretty inclusive ๐ŸŒˆ

Parameters

  • filename โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐Ÿ”ฅ toil.lib.io.mkdtemp ๐Ÿ”ฅ

toil.lib.io.mkdtemp(suffix=None, prefix=None, dir=None)

This is basically tempfile.mkdtemp, but with relaxed permissions ๐Ÿฆ‹ The directory gets 711 instead of 700, so the group and all other users can traverse it.

Why does this matter? If the directory is on NFS and the Docker daemon wants to mount it (or a file inside it) into a container, NFS makes even the Docker daemon act bound by the file permissions. Lowkey wild ๐Ÿ˜ญ

See <https://github.com/DataBiosphere/toil/issues/4644>, and <https://stackoverflow.com/a/67928880> which talks about a similar problem, but in the context of user namespaces ๐Ÿ“š

Parameters

  • suffix โ€” Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • prefix โ€” Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • dir โ€” Optional[toil.lib.misc.StrPath]

Return type

str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿงน toil.lib.io.robust_rmtree ๐Ÿงน

toil.lib.io.robust_rmtree(path)

Robustly tries to delete paths. It's the cleanup queen ๐Ÿ‘‘ It continues silently if the path is already gone, or if it goes away while the function is running.

It may still raise an error if a path changes between file and directory while the function is executing, or if a permission error is encountered. Not invincible, bestie ๐Ÿ’€

Parameters

  • path โ€” Union[str, bytes] (/usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#bytes)

Return type

None (/usr/share/doc/python3/html/library/constants.html#None)


๐ŸŒˆ toil.lib.io.atomic_tmp_file ๐ŸŒˆ

toil.lib.io.atomic_tmp_file(final_path)

Gives you a tmp file name to use with atomic_install. It lives in the same directory as final_path, and it keeps the same extension as finalPath โœจ

Special case alert ๐Ÿšจ If the final path is in /dev (like /dev/null or /dev/stdout), it gets returned unchanged, and atomic_tmp_install will do nothing.

Parameters

  • final_path โ€” toil.lib.misc.StrPath

Return type

str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ’– toil.lib.io.atomic_install ๐Ÿ’–

toil.lib.io.atomic_install(tmp_path, final_path)

Atomically installs tmp_path as final_path. Clean and iconic ๐Ÿซถ

Parameters

  • tmp_path โ€” toil.lib.misc.StrPath
  • final_path โ€” toil.lib.misc.StrPath

Return type

None (/usr/share/doc/python3/html/library/constants.html#None)


๐Ÿฆ‹ toil.lib.io.AtomicFileCreate ๐Ÿฆ‹

toil.lib.io.AtomicFileCreate(final_path, keep=False)

This is a context manager that creates a temporary file โœจ When you enter it, you get the path to the temp file, which sits in the same directory as finalPath.

If the code inside the context succeeds, the file gets renamed to its actual name. If an error happens, the file doesn't get installed and gets removed, unless keep is specified. Lowkey the best safety net ๐Ÿงธ

Parameters

  • final_path โ€” toil.lib.misc.StrPath
  • keep โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool)

Return type

collections.abc.Iterator[str] (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterator, /usr/share/doc/python3/html/library/stdtypes.html#str)


๐ŸŽ€ toil.lib.io.atomic_copy ๐ŸŽ€

toil.lib.io.atomic_copy(src_path, dest_path, executable=None)

Copies a file using POSIX atomic creation semantics. Super reliable energy ๐Ÿ’…

Parameters

  • src_path โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • dest_path โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • executable โ€” Optional[bool] (/usr/share/doc/python3/html/library/functions.html#bool)

Return type

None (/usr/share/doc/python3/html/library/constants.html#None)


๐ŸŒธ toil.lib.io.atomic_copyobj ๐ŸŒธ

toil.lib.io.atomic_copyobj(src_fh, dest_path, length=16384, executable=False)

Same vibe as atomic_copy, but this time you hand it an open file and it does POSIX atomic creation semantics on it ๐Ÿงš

Parameters

  • src_fh โ€” io.BytesIO (/usr/share/doc/python3/html/library/io.html#io.BytesIO)
  • dest_path โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • length โ€” int (/usr/share/doc/python3/html/library/functions.html#int)
  • executable โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool)

Return type

None (/usr/share/doc/python3/html/library/constants.html#None)


๐Ÿ“ toil.lib.io.make_public_dir ๐Ÿ“

toil.lib.io.make_public_dir(in_directory, suggested_name=None)

Makes a publicly-accessible directory inside the directory you give it ๐Ÿซถ

Parameters

  • suggested_name โ€” Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str) -- Use this directory name first if possible.
  • in_directory โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

str (/usr/share/doc/python3/html/library/stdtypes.html#str)

The naming process is giving strategic ๐Ÿง  It tries to make a random directory name with length 4 that doesn't exist yet, using the given prefix. If that's taken, it tries length 5, then 6, and so on, up to a max of 32 (the length of a uuid4 with the dashes replaced).

This is mostly here so you don't end up with super long file names when generating directories. And if somehow all of that fails (which should be incredibly unlikely), it defaults to a normal uuid4, which was our old default ๐Ÿฅน


๐Ÿ’… toil.lib.io.try_path ๐Ÿ’…

toil.lib.io.try_path(path, min_size=100 * 1024 * 1024)

Tries to use the given path. It returns the path if it exists (or can be made) and you can make things inside it. Otherwise, it returns None ๐Ÿ™ˆ

Parameters

  • min_size โ€” int (/usr/share/doc/python3/html/library/functions.html#int) -- Rejects paths on filesystems smaller than this many bytes.
  • path โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿงธ class toil.lib.io.WriteWatchingStream ๐Ÿงธ

class toil.lib.io.WriteWatchingStream(backingStream)

A stream wrapper that calls any functions you pass to onWrite() with the number of bytes written on every single write ๐Ÿ“Š

It's not seekable, so don't go looking for a rewind button ๐Ÿ™ƒ

Parameters

  • backingStream โ€” IO[Any]

Attributes

  • backingStream
  • writeListeners โ€” list[Callable[[int], None]] = [] (/usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/constants.html#None)

Methods

onWrite(listener)

Calls the given listener with the number of bytes written on every write ๐ŸŽ€

Parameters

  • listener โ€” Callable[[int], None] (/usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/constants.html#None)

Return type None (/usr/share/doc/python3/html/library/constants.html#None)

write(data)

Writes the given data to the file ๐Ÿ’–

Parameters

  • data โ€” bytes (/usr/share/doc/python3/html/library/stdtypes.html#bytes)

Return type None (/usr/share/doc/python3/html/library/constants.html#None)

writelines(datas)

Writes each string from the given iterable, without newlines. You're in charge of the line breaks ๐Ÿ™Œ

Parameters

  • datas โ€” collections.abc.Iterable[bytes] (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterable, /usr/share/doc/python3/html/library/stdtypes.html#bytes)

Return type None (/usr/share/doc/python3/html/library/constants.html#None)

flush()

Flushes the backing stream ๐ŸŒŠ

Return type None (/usr/share/doc/python3/html/library/constants.html#None)

close()

Closes the backing stream ๐Ÿ”’

Return type None (/usr/share/doc/python3/html/library/constants.html#None)


๐Ÿ‘‘ class toil.lib.io.ReadableFileObj ๐Ÿ‘‘

Bases: Protocol (/usr/share/doc/python3/html/library/typing.html#typing.Protocol)

okay so this little protocol is giving very specific ๐Ÿ’… it's a stricter version of what file_digest takes as an argument, and it guarantees a read() method ๐Ÿซถ ngl the plan was to extend the protocol from Typeshed for hashlib, but those only get declared for 3.11+, so no dice for older Pythons ๐Ÿ˜ญ

readinto(buf, /) ๐ŸŒธ

  • Parameters
    • buf (bytearray)
  • Return type
    • int

readable() ๐Ÿฆ‹

  • Return type
    • bool

read(number) โœจ

  • Parameters
    • number (int)
  • Return type
    • bytes

toil.lib.io.file_digest(f, alg_name) ๐Ÿงš

Polyfilled hashlib.file_digest that works on Python <3.11. It's the glow-up you didn't know you needed ๐Ÿ’–

  • Parameters
    • f (ReadableFileObj)
    • alg_name (str)
  • Return type
    • hashlib._Hash

โœจ toil.lib.memoize โœจ

๐Ÿ’… Attributes

  • memoize โ€” Memoizes a function result based on its parameters using this decorator.
  • MAT โ€” no description, it's a mystery ๐Ÿ™ˆ
  • MRT โ€” no description, it's a mystery ๐Ÿ™ˆ

๐ŸŽ€ Functions

  • sync_memoize(f) โ€” Like memoize, but guarantees the decorated function only gets called once, even when multiple threads are calling it with multiple parameters ๐Ÿ‘‘
  • parse_iso_utc(s) โ€” Parses an RFC 3339 ISO 8601 time in the UTC timezone ๐Ÿ•ฐ๏ธ
  • strict_bool(s) โ€” A variant of bool() that only accepts two possible string values ๐Ÿซถ

๐Ÿฆ‹ Module Contents

toil.lib.memoize.memoize

Memoize a function result based on its parameters using this decorator, bestie. It's giving lazy initialization vibes โœจ If the decorating function gets invoked by multiple threads, the decorated function might get called more than once with the same arguments, so keep that in mind ๐Ÿ‘€

toil.lib.memoize.MAT

nothing else to say about this one ๐Ÿ™ˆ

toil.lib.memoize.MRT

nothing else to say about this one ๐Ÿ™ˆ

toil.lib.memoize.sync_memoize(f)

Like memoize, but guarantees that the decorated function is only called once, even when multiple threads are calling the decorating function with multiple parameters. Main character energy ๐Ÿ‘‘

  • Parameters
    • f (Callable[[MAT], MRT])
  • Return type
    • Callable[[MAT], MRT]

toil.lib.memoize.parse_iso_utc(s)

Parses an RFC 3339 ISO 8601 time in the UTC timezone. Other timezones are not supported, so don't even try ๐Ÿ™…โ€โ™€๏ธ It returns a timezone-aware UTC datetime object.

  • Parameters
    • s (str) โ€” the ISO-formatted time
  • Returns
    • A timezone-aware UTC datetime object
  • Raises ValueError โ€” if the string isn't in the correct format or isn't in the UTC timezone. No notes, it'll yell at you ๐Ÿ’€
  • Return type
    • datetime.datetime

Here's how it behaves in action ๐Ÿฆ‹

>>> parse_iso_utc('2016-04-27T00:28:04.000Z')
datetime.datetime(2016, 4, 27, 0, 28, 4, tzinfo=datetime.timezone.utc)
>>> parse_iso_utc('2016-04-27T00:28:04Z')
datetime.datetime(2016, 4, 27, 0, 28, 4, tzinfo=datetime.timezone.utc)
>>> parse_iso_utc('2016-04-27T00:28:04X')
Traceback (most recent call last):
...
ValueError: Not a valid ISO datetime in UTC: 2016-04-27T00:28:04X

toil.lib.memoize.strict_bool(s)

A variant of bool() that only accepts two possible string values. Strict, but iconic ๐Ÿ’…

  • Parameters
    • s (str)
  • Return type
    • bool

โœจ toil.lib.misc โœจ

๐Ÿ’… Attributes

  • logger โ€” ๐Ÿ™ˆ
  • StrPath โ€” ๐Ÿ™ˆ
  • FileDescriptorOrPath โ€” ๐Ÿ™ˆ

๐ŸŒˆ Exceptions

  • CalledProcessErrorStderr โ€” a version of CalledProcessError that includes stderr in the error message if it's set ๐Ÿ˜ญ๐Ÿซถ

โœจ Functions โœจ

Okay bestie, here's the whole lineup of helpers in toil.lib.misc ๐Ÿ’… The table cuts off mid-sentence at slow_down, so the full details for that one are down below ๐Ÿ™ˆ

  • get_public_ip() โ€” grabs the IP this machine uses to reach the internet ๐ŸŒ
  • get_user_name() โ€” gets the current user name, or a suitable stand-in string if the user name isn't available ๐Ÿซถ
  • utc_now() โ€” gives you a datetime in the UTC timezone for right now โฐ
  • unix_now_ms() โ€” the current time in milliseconds since the Unix epoch โฑ๏ธ
  • unix_seconds_to_timestamp(timestamp) โ€” turns seconds since the Unix epoch into an ISO 8601 string ๐Ÿ“…
  • unix_seconds_to_local_time(timestamp) โ€” gives you a local time matching a number of seconds since the Unix epoch ๐Ÿ—บ๏ธ
  • seconds_to_duration(time_difference) โ€” turns a time difference in seconds into an ISO 8601 duration string โŒ›
  • slow_down(seconds) โ€” finished Toil jobs can't have taken 0 seconds, but the table cuts off right there ๐Ÿซ 
  • printq(msg, quiet[, log]) โ€” for functions that get used in both Toil proper and the admin scripts ๐Ÿงš
  • truncExpBackoff() โ€” the table has no description for this one, total mystery energy ๐ŸŒซ๏ธ
  • call_command(cmd, *args[, input, timeout, useCLocale, ...]) โ€” a simplified way to run external commands ๐Ÿš€

โœจ Module Contents โœจ

Next up is the module contents, starting with the logger ๐Ÿ“

  • toil.lib.misc.logger

Now the type aliases, which are basically nicknames for "this can be one of these things" ๐Ÿ’œ

type toil.lib.misc.StrPath = str </usr/share/doc/python3/html/library/stdtypes.html#str> | os.PathLike </usr/share/doc/python3/html/library/os.html#os.PathLike>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]
type toil.lib.misc.FileDescriptorOrPath = int </usr/share/doc/python3/html/library/functions.html#int> | bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes> | os.PathLike </usr/share/doc/python3/html/library/os.html#os.PathLike>[bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes>] | StrPath

โœจ toil.lib.misc.get_public_ip() โœจ

Okay so this grabs the IP this machine uses to contact the internet ๐ŸŒ If you're behind a NAT, you'll still get this computer's IP and not the router's ๐Ÿฆ‹

Return type: str โ€” /usr/share/doc/python3/html/library/stdtypes.html#str

โœจ toil.lib.misc.get_user_name() โœจ

Gets the current user name, or a suitable substitute string if the user name is not available ๐Ÿซถ

Return type: str โ€” /usr/share/doc/python3/html/library/stdtypes.html#str

โœจ toil.lib.misc.utc_now() โœจ

Gives you a datetime in the UTC timezone that matches right now โฐ

Return type: datetime.datetime โ€” /usr/share/doc/python3/html/library/datetime.html#datetime.datetime

โœจ toil.lib.misc.unix_now_ms() โœจ

Returns the current time in milliseconds since the Unix epoch, no cap โฑ๏ธ

Return type: float โ€” /usr/share/doc/python3/html/library/functions.html#float

โœจ toil.lib.misc.unix_seconds_to_timestamp(timestamp) โœจ

Converts a time in seconds since the Unix epoch into an ISO 8601 string ๐Ÿ“…

Parameters

  • timestamp (float โ€” /usr/share/doc/python3/html/library/functions.html#float)

Return type: str โ€” /usr/share/doc/python3/html/library/stdtypes.html#str

โœจ toil.lib.misc.unix_seconds_to_local_time(timestamp) โœจ

Returns a local time that lines up with the given number of seconds since the Unix epoch ๐Ÿ—บ๏ธ

Parameters

  • timestamp (float โ€” /usr/share/doc/python3/html/library/functions.html#float)

Return type: datetime.datetime โ€” /usr/share/doc/python3/html/library/datetime.html#datetime.datetime

โœจ toil.lib.misc.seconds_to_duration(time_difference) โœจ

Turns a time difference in seconds into an ISO 8601 duration string โŒ›

Parameters

  • time_difference (float โ€” /usr/share/doc/python3/html/library/functions.html#float)

Return type: str โ€” /usr/share/doc/python3/html/library/stdtypes.html#str

โœจ toil.lib.misc.slow_down(seconds) โœจ

Finished Toil jobs are not allowed to have taken 0 seconds ๐Ÿšซโฑ๏ธ The tricky part is that Kubernetes timestamps round things to the nearest second, so in some batch systems a pod can end up with identical start and end timestamps ๐Ÿ™ˆ

So this function takes a possibly 0 job length in seconds and enforces a minimum length so Toil stays happy ๐Ÿ’– It returns the seconds, or a small positive number if seconds is 0.

Parameters

  • seconds (float โ€” /usr/share/doc/python3/html/library/functions.html#float) โ€” the timestamp difference

Returns: seconds, or a small positive number if seconds is 0

Return type: float โ€” /usr/share/doc/python3/html/library/functions.html#float

โœจ toil.lib.misc.printq(msg, quiet, log=False) โœจ

This one is for functions used simultaneously in Toil proper and in the admin scripts ๐Ÿงš

Okay so the admin scripts "print" to stdout, while Toil proper uses logging ๐Ÿชต Say a script cleans up IAM, EC2, etc. cruft that got left behind after failed CI runs. It can call an AWS delete IAM role function, and that prints or logs progress (unless quiet is True), depending on whether the function is called in, say, the jobstore or a script ๐Ÿ’…

Parameters

  • msg (str โ€” /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the string to print or log to stdout
  • quiet (bool โ€” /usr/share/doc/python3/html/library/functions.html#bool) โ€” silences output to stdout
  • log (bool โ€” /usr/share/doc/python3/html/library/functions.html#bool) โ€” use logging instead of "print" to the screen

Return type: None

โœจ toil.lib.misc.truncExpBackoff() โœจ

No description here, bestie ๐ŸŒซ๏ธ

Return type: collections.abc.Iterator (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Iterator) of float (/usr/share/doc/python3/html/library/functions.html#float)


โœจ exception toil.lib.misc.CalledProcessErrorStderr โœจ

exception toil.lib.misc.CalledProcessErrorStderr(returncode, cmd, output=None, stderr=None)

Bases: subprocess.CalledProcessError โ€” /usr/share/doc/python3/html/library/subprocess.html#subprocess.CalledProcessError

This is a version of CalledProcessError that includes stderr in the error message if it is set ๐Ÿงพ

__str__() โ€” returns str(self) ๐Ÿซง

Return type: str โ€” /usr/share/doc/python3/html/library/stdtypes.html#str

โœจ toil.lib.misc.call_command(...) โœจ

toil.lib.misc.call_command(cmd, *args, input=None, timeout=None, useCLocale=True, env=None, quiet=False)

Simplified calling of external commands ๐Ÿš€

If the process fails, CalledProcessErrorStderr gets raised ๐Ÿ’ฅ

The captured stderr is always printed, even if an exception happens, so it can be logged ๐Ÿชต

It always logs the command at debug log level ๐Ÿ›

Parameters

โœจ toil.lib.objects โœจ

  • quiet (Optional[bool], see /usr/share/doc/python3/html/library/functions.html#bool) โ€” bestie, True means shh ๐Ÿคซ, don't log the command output at all. False is the default, and it means the output gets logged at the debug log level ๐Ÿ”.
  • useCLocale (bool, see /usr/share/doc/python3/html/library/functions.html#bool) โ€” True forces the C locale ๐ŸŒธ. This stops the failures that can happen on some batch systems when they're using a UTF-8 locale ๐Ÿ˜ญ.
  • cmd (list[str], see /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’…
  • args (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿงš
  • input (Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“
  • timeout (Optional[float], see /usr/share/doc/python3/html/library/functions.html#float) โฐ
  • env (Optional[dict[str, str]], see /usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒˆ

Returns

You get back the command's standard output, decoded as utf-8 โœจ.

Return type

str (see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿฆ‹


โœจ toil.lib.objects โœจ

Classes ๐Ÿ’–

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ InnerClass โ”‚ Note that this is  โ”‚
โ”‚            โ”‚ EXPERIMENTAL code. โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Module Contents ๐ŸŽ€

class toil.lib.objects.InnerClass(inner_class)

Okay so, this is EXPERIMENTAL code ๐Ÿงช, so be a little careful with it, bestie.

So a nested class (the inner class) decorated with this gets an extra attribute called outer. That attribute points at the instance of the nesting class (the outer class) that was used to make the inner class. You don't have to pass the outer instance into the inner class's constructor, because it gets set magically โœจ. This was shamelessly stolen from http://stackoverflow.com/questions/2278426/inner-classes-how-can-i-get-the-outer-class-object-at-construction-time#answer-2278595.

The names got made more descriptive (I hope ๐Ÿ™ˆ), and caching of the BoundInner classes got added too.

Caveat: Within the inner class, self.__class__ will not be the inner class. It'll be a dynamically created subclass of it ๐ŸŒ€. That subclass has the same name as the inner class, but its __module__ will be different. There's one dynamic subclass per inner class and per outer class instance, but only if that outer instance actually created any instances of the inner class.

Here's the vibe in code:

>>> class Outer(object):
...     def new_inner(self):
...         # self is an instance of the outer class
...         inner = self.Inner()
...         # the inner instance's 'outer' attribute is set to the outer instance
...         assert inner.outer is self
...         return inner
...     @InnerClass
...     class Inner(object):
...         def get_outer(self):
...             return self.outer
...         @classmethod
...         def new_inner(cls):
...             return cls()
>>> o = Outer()
>>> i = o.new_inner()
>>> i
<toil.lib.objects.Inner...> bound to <toil.lib.objects.Outer object at ...>

>>> i.get_outer()
<toil.lib.objects.Outer object at ...>

Now with inheritance for both the inner and outer classes ๐Ÿ‘‘:

>>> class DerivedOuter(Outer):
...     def new_inner(self):
...         return self.DerivedInner()
...     @InnerClass
...     class DerivedInner(Outer.Inner):
...         def get_outer(self):
...             assert super( DerivedOuter.DerivedInner, self ).get_outer() == self.outer
...             return self.outer
>>> derived_outer = DerivedOuter()
>>> derived_inner = derived_outer.new_inner()
>>> derived_inner
<toil.lib.objects...> bound to <toil.lib.objects.DerivedOuter object at ...>

>>> derived_inner.get_outer()
<toil.lib.objects.DerivedOuter object at ...>

Test a static references:

Test a static references: >>> Outer.Inner # doctest: +ELLIPSIS
<class 'toil.lib.objects...Inner'> >>> DerivedOuter.Inner #
doctest: +ELLIPSIS <class 'toil.lib.objects...Inner'> >>>
DerivedOuter.DerivedInner #doctest: +ELLIPSIS <class
'toil.lib.objects...DerivedInner'>

Can't decorate top-level classes ๐Ÿšซ. Unfortunately, this only gets detected when the instance is created, not when the class is defined ๐Ÿ˜ฉ.

Can't decorate top-level classes. Unfortunately, this is detected
when the instance is created, not when the class is defined.  >>>
@InnerClass ... class Foo(object): ...    pass >>> Foo()
Traceback (most recent call last): ...  RuntimeError: Inner
classes must be nested in another class.

All inner instances should refer to a single outer instance:

All inner instances should refer to a single outer instance: >>>
o = Outer() >>> o.new_inner().outer == o == o.new_inner().outer
True

All inner instances should be of the same class ...

All inner instances should be of the same class ...  >>>
o.new_inner().__class__ == o.new_inner().__class__ True

... but that class isn't the inner class ...

... but that class isn't the inner class ...  >>>
o.new_inner().__class__ != Outer.Inner True

... but a subclass of the inner class.

... but a subclass of the inner class.  >>> isinstance(
o.new_inner(), Outer.Inner ) True

Static and class methods, e.g. should work, too โœจ:

>>> o.Inner.new_inner().outer == o
True

Members:

  • inner_class
  • __get__(instance, owner)
  • __call__(**kwargs)

โœจ toil.lib.pipes โœจ

Attributes ๐ŸŒธ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”
โ”‚ log โ”‚   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜

Classes ๐Ÿฆ‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ WritablePipe             โ”‚ An object-oriented wrapper โ”‚
โ”‚                          โ”‚ for os.pipe. Clients       โ”‚
โ”‚                          โ”‚ should subclass it,        โ”‚
โ”‚                          โ”‚ implement                  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ReadablePipe             โ”‚ An object-oriented wrapper โ”‚
โ”‚                          โ”‚ for os.pipe. Clients       โ”‚
โ”‚                          โ”‚ should subclass it,        โ”‚
โ”‚                          โ”‚ implement                  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ReadableTransformingPipe โ”‚ A pipe which is            โ”‚
โ”‚                          โ”‚ constructed around a       โ”‚
โ”‚                          โ”‚ readable stream, and which โ”‚
โ”‚                          โ”‚ provides a                 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ HashingPipe              โ”‚ Class which checksums all  โ”‚
โ”‚                          โ”‚ the data read through it.  โ”‚
โ”‚                          โ”‚ If it                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Module Contents ๐ŸŽ€

toil.lib.pipes.log

class toil.lib.pipes.WritablePipe(encoding=None, errors=None)

Bases: abc.ABC (see /usr/share/doc/python3/html/library/abc.html#abc.ABC) ๐Ÿ“

So this is an object-oriented wrapper for os.pipe ๐Ÿ’–. You subclass it, implement readFrom() to consume the readable end of the pipe, and then use the class as a context manager to get the writable end. Here's the example ๐Ÿ‘‡.

>>> import sys, shutil, codecs
>>> class MyPipe(WritablePipe):
...     def readFrom(self, readable):
...         shutil.copyfileobj(codecs.getreader('utf-8')(readable), sys.stdout)
>>> with MyPipe() as writable:
...     _ = writable.write('Hello, world!\n'.encode('utf-8'))
Hello, world!

Each instance of this class creates a thread and invokes the readFrom method in that thread ๐Ÿงต. The thread gets join()ed on a normal exit from the context manager, which means the body of the with statement. If an exception happens, the thread won't be joined, but a well-behaved readFrom() implementation should wrap up shortly after, because the pipe got closed ๐Ÿ”’.

Now, exceptions in the reader thread get reraised in the main thread ๐Ÿ˜ฑ:

>>> class MyPipe(WritablePipe):
...     def readFrom(self, readable):
...         raise RuntimeError('Hello, world!')
>>> with MyPipe() as writable:
...     pass
Traceback (most recent call last):
...
RuntimeError: Hello, world!

More complicated, less illustrative tests ๐Ÿ™ˆ:

Same as above, but proving that handles are closed:

>>> x = os.dup(0); os.close(x)
>>> class MyPipe(WritablePipe):
...     def readFrom(self, readable):
...         raise RuntimeError('Hello, world!')
>>> with MyPipe() as writable:
...     pass
Traceback (most recent call last):
...
RuntimeError: Hello, world!
>>> y = os.dup(0); os.close(y); x == y
True

Exceptions in the body of the with statement aren't masked, and handles are closed ๐Ÿซถ:

>>> x = os.dup(0); os.close(x)
>>> class MyPipe(WritablePipe):
...     def readFrom(self, readable):
...         pass
>>> with MyPipe() as writable:
...     raise RuntimeError('Hello, world!')
Traceback (most recent call last):
...
RuntimeError: Hello, world!
>>> y = os.dup(0); os.close(y); x == y
True

Parameters

  • encoding (Optional[str]) โ€” the text encoding you want, if any ๐Ÿ’–
  • errors (Optional[str]) โ€” what to do when encoding goes wrong, if you want to set it ๐Ÿซถ
encoding: str | None = None
errors: str | None = None
readable_fh: int | None = None
writable: IO[Any] | None = None
thread: toil.lib.threading.ExceptionalThread | None = None
reader_done: bool = False

__enter__() โœจ

Return type: IO[Any] ๐Ÿฆ‹

__exit__(exc_type, exc_val, exc_tb) ๐Ÿ’…

Parameters:

  • exc_type (Optional[str]) ๐ŸŒธ
  • exc_val (Optional[str]) ๐ŸŒธ
  • exc_tb (Optional[str]) ๐ŸŒธ

Return type: None ๐Ÿ™ˆ

abstractmethod readFrom(readable) ๐Ÿ”ฅ

okay so this one is an abstract method, which means you have to write it yourself if you subclass ๐Ÿ˜ญ Its whole job is to pull data out of the pipe. It needs to handle both binary and text mode output, so no being picky about it ๐Ÿ’œ

Parameters:

  • readable (file) โ€” this is the file object for the readable end of the pipe. Do not call close() on it yourself ๐Ÿ™… It gets closed automatically, so let it go ๐Ÿซถ

Return type: None โœจ


โœจ class toil.lib.pipes.ReadablePipe(encoding=None, errors=None) โœจ

Bases: abc.ABC

Okay bestie, ReadablePipe is an object-oriented wrapper around os.pipe ๐ŸŒˆ The vibe is: you subclass it, write a writeTo() method that puts data into the writable end of the pipe, and then use the class as a context manager to get the writable end back ๐Ÿ’… Here's a lil example so you can see it in action ๐Ÿฆ‹

>>> import sys, shutil, codecs
>>> class MyPipe(ReadablePipe):
...     def writeTo(self, writable: IO[Any]) -> None:
...         writable.write('Hello, world!\n'.encode('utf-8'))
>>> with MyPipe() as readable:
...     shutil.copyfileobj(codecs.getreader('utf-8')(readable), sys.stdout)
Hello, world!

Every instance spins up its own thread and runs writeTo() inside it ๐Ÿงต On a normal exit from the context manager (aka the body of the with statement), that thread gets join()ed, so it's all tidy ๐Ÿ’– If an exception happens instead, the thread does not get joined, but a well-behaved writeTo() should wrap up pretty quickly anyway, since the pipe has been closed ๐Ÿ™ˆ

Now, the main thread will get any exceptions that happen in the reader thread and re-raise them. Literally iconic ๐Ÿ‘‘

>>> class MyPipe(ReadablePipe):
...     def writeTo(self, writable):
...         raise RuntimeError('Hello, world!')
>>> with MyPipe() as readable:
...     pass
Traceback (most recent call last):
...
RuntimeError: Hello, world!

Next up are some more complicated, less illustrative tests ๐Ÿง Same as the one above, but this one proves that the handles get closed ๐Ÿ”’

>>> x = os.dup(0); os.close(x)
>>> class MyPipe(ReadablePipe):
...     def writeTo(self, writable: IO[Any]) -> None:
...         raise RuntimeError('Hello, world!')
>>> with MyPipe() as readable:
...     pass
Traceback (most recent call last):
...
RuntimeError: Hello, world!
>>> y = os.dup(0); os.close(y); x == y
True

Exceptions raised in the body of the with statement aren't masked, and the handles still get closed ๐Ÿซถ

>>> x = os.dup(0); os.close(x)
>>> class MyPipe(ReadablePipe):
...     def writeTo(self, writable):
...         pass
>>> with MyPipe() as readable:
...     raise RuntimeError('Hello, world!')
Traceback (most recent call last):
...
RuntimeError: Hello, world!
>>> y = os.dup(0); os.close(y); x == y
True

Parameters:

  • encoding (Optional[str]) ๐Ÿ“
  • errors (Optional[str]) ๐Ÿ“

abstractmethod writeTo(writable) ๐Ÿ’œ

This one is also abstract, so you gotta implement it ๐Ÿ”ฅ Its job is to write data into the pipe, and it needs to support both binary and text mode input ๐Ÿฆ‹

Parameters:

  • writable (file) โ€” the file object for the writable end of the pipe. Do not explicitly call close() on it, because that happens automatically ๐Ÿ™…

Return type: None ๐Ÿ’…

encoding: str | None = None
errors: str | None = None
writable_fh: int | None = None
readable: IO[Any] | None = None
thread: toil.lib.threading.ExceptionalThread | None = None

__enter__() ๐ŸŒธ

Return type: IO[Any] โœจ

__exit__(exc_type, exc_val, exc_tb) ๐ŸŒˆ

Parameters:

  • exc_type (Optional[str]) ๐ŸŒธ
  • exc_val (Optional[str]) ๐ŸŒธ
  • exc_tb (Optional[str]) ๐ŸŒธ

Return type: None ๐Ÿ™ˆ


โœจ class toil.lib.pipes.ReadableTransformingPipe(source, encoding=None, errors=None) โœจ

Bases: ReadablePipe

This is a pipe that gets built around a readable stream, and it gives you a context manager that hands back a readable stream ๐Ÿฆ‹ It's super useful as a base class for pipes that need to transform or visit the bytes flowing through them, instead of just consuming or producing data ๐Ÿ’–

Clients should subclass it and implement transform(), like this:

>>> import sys, shutil, codecs
>>> class MyPipe(ReadableTransformingPipe):
...     def transform(self, readable, writable):
...         writable.write(readable.read().decode('utf-8').upper().encode('utf-8'))
>>> class SourcePipe(ReadablePipe):
...     def writeTo(self, writable):
...         writable.write('Hello, world!\n'.encode('utf-8'))
>>> with SourcePipe() as source:
...     with MyPipe(source) as transformed:
...         shutil.copyfileobj(codecs.getreader('utf-8')(transformed), sys.stdout)
HELLO, WORLD!

The transform() method runs in its own thread ๐Ÿงต It should move data chunk by chunk instead of grabbing everything all at once, bestie ๐Ÿ™ It should finish normally if it hits either an EOF on the readable side, or a BrokenPipeError on the writable side ๐Ÿ’…

Make sure you actually catch a BrokenPipeError when you're writing! If you don't, your transform() won't wrap up cleanly ๐Ÿ˜ญ

See also: toil.lib.misc.WriteWatchingStream. ๐Ÿ‘€

Parameters:

  • source (IO[Any]) ๐ŸŒท
  • encoding (Optional[str]) ๐Ÿ“
  • errors (Optional[str]) ๐Ÿ“

source ๐Ÿซง

abstractmethod transform(readable, writable) ๐Ÿ”ฅ

You have to implement this one to actually ship data through the pipe ๐Ÿšข

Parameters:

  • readable (file) โ€” the input stream file object you want to transform ๐ŸŒŠ
  • writable (file) โ€” the file object for the writable end of the pipe. Do not explicitly call close() on it, since that happens automatically ๐Ÿ™…

Return type: None ๐Ÿ’œ

writeTo(writable) ๐Ÿฆ‹

Implement this method to write data from the pipe ๐Ÿ’… It should support both binary and text mode input.

Parameters:

  • writable (file) โ€” the file object for the writable end of the pipe. Do not explicitly call close() on it, because that happens automatically ๐Ÿ™…

Return type: None โœจ


โœจ class toil.lib.pipes.HashingPipe(source, encoding=None, errors=None, checksum_to_verify=None) โœจ

Bases: ReadableTransformingPipe

This class checksums all the data that gets read through it ๐Ÿ” If it reaches EOF and the checksum isn't correct, it raises ChecksumError ๐Ÿ˜ฌ Heads up: it assumes info actually has a checksum ๐Ÿซถ

Parameters:

  • source (IO[Any]) ๐ŸŒท
  • encoding (Optional[str]) ๐Ÿ“
  • errors (Optional[str]) ๐Ÿ“
  • checksum_to_verify (Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿงพ this one can be None, so you don't have to bring a checksum if you don't want to ๐Ÿซถ
checksum_to_verify = None

transform(readable, writable)

Okay so this is the method YOU write, bestie ๐Ÿšฐโœจ Implement it to ship data through the pipe, and it's giving main character energy.

  • readable (file) โ€” the input stream file object you're transforming ๐Ÿ“ฅ
  • writable (file) โ€” the file object for the writable end of the pipe ๐Ÿ–Š๏ธ
๐Ÿ™… Do not explicitly invoke the close() method of the object. It gets closed automatically, so don't even try ๐Ÿ’€

Return type: None ๐Ÿ’–


toil.lib.plugins

Generic plugin system for Toil plugins ๐Ÿงš Plugins come in Python packages named like this:

toil_{PLUGIN_TYPE}_{WHATEVER}

When Toil goes looking for plugins, it lists every Python package with the right name prefix for the given type of plugin, then loads them. The plugin modules then get the chance to import register_plugin() and register themselves ๐Ÿฆ‹

Attributes

  • PluginType ๐ŸŽ€
  • plugin_types ๐ŸŽ€

Functions

  • register_plugin(plugin_type, plugin_name, ...) โ€” adds a plugin to the registry for the given type of plugin ๐Ÿ“
  • remove_plugin(plugin_type, plugin_name) โ€” removes a plugin from the registry for the given type of plugin ๐Ÿ—‘๏ธ
  • get_plugin_names(plugin_type) โ€” gets the names of all the available plugins of the given type ๐Ÿ“‹
  • get_plugin(plugin_type, plugin_name) โ€” gets a plugin class factory function by name ๐Ÿ”

Module Contents

  • toil.lib.plugins.PluginType ๐ŸŽ€

The list of plugin types is literally this, so iconic ๐Ÿ‘‘

toil.lib.plugins.plugin_types: list[PluginType] = ['batch_system', 'url_access']

Here list refers to the one in /usr/share/doc/python3/html/library/stdtypes.html#list ๐Ÿ“š

toil.lib.plugins.register_plugin(plugin_type, plugin_name, plugin_being_registered)

Adds a plugin to the registry for the given type of plugin ๐Ÿ’…

Parameters:

  • plugin_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” For batch systems, this is the string the user types to pick the batch system on the command line with --batchSystem. For URL access plugins, this is the URL scheme the plugin implements ๐ŸŒˆ
  • plugin_being_registered (Any) โ€” a function that, when called, imports and returns a plugin-provided class type. For batch systems, that type must extend toil.batchSystems.abstractBatchSystem.AbstractBatchSystem. For URL access plugins, it must extend toil.lib.url.URLAccess. Note that this function should return the class itself. It should NOT construct an instance of the class ๐Ÿ™ˆ
  • plugin_type (PluginType) ๐ŸŽ€

Return type: None โœจ

toil.lib.plugins.remove_plugin(plugin_type, plugin_name)

Removes a plugin from the registry for the given type of plugin ๐Ÿงน

Parameters:

  • plugin_type (PluginType) ๐ŸŽ€
  • plugin_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€

Return type: None ๐Ÿ’œ

toil.lib.plugins.get_plugin_names(plugin_type)

Gets the names of all the available plugins of the given type ๐Ÿ“‹

Parameters:

  • plugin_type (PluginType) ๐ŸŽ€

Return type: list[str], where list is in /usr/share/doc/python3/html/library/stdtypes.html#list and str is in /usr/share/doc/python3/html/library/stdtypes.html#str ๐Ÿงพ

toil.lib.plugins.get_plugin(plugin_type, plugin_name)

Gets a plugin class factory function by name ๐Ÿ”

๐Ÿšจ Raises KeyError if plugin_name isn't the name of a plugin of the given type. Careful with your spelling, bestie ๐Ÿ˜ญ

Parameters:

  • plugin_type (PluginType) ๐ŸŽ€
  • plugin_name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€

Return type: Any ๐Ÿฆ‹


toil.lib.resources

Classes

  • ResourceMonitor โ€” global resource monitoring widget ๐Ÿ“Š

Functions

  • glob(glob_pattern, directoryname) โ€” walks through a directory and its subdirectories looking for files matching ๐Ÿ”Ž

Module Contents

class toil.lib.resources.ResourceMonitor

Global resource monitoring widget ๐Ÿ“Š It gives you class methods to check the resource usage of this process and its child processes. It also has other class methods to tweak the stats, so they can count resources used inside containers, or anything else that should be billable to the current process ๐Ÿ’–

classmethod record_extra_memory(peak_ki)

Become responsible for the given peak memory usage, in kibibytes ๐Ÿง  The memory gets treated as if a child process used it at the same time our real child processes were using their peak memory.

Parameters:

  • peak_ki (int, see /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ”ข

Return type: None ๐Ÿ’…

classmethod record_extra_cpu(seconds)

Become responsible for the given CPU time โฑ๏ธ The CPU time gets treated as if it had been used by a child process.

Parameters:

  • seconds (float, see /usr/share/doc/python3/html/library/functions.html#float) โฑ๏ธ

Return type: None ๐ŸŒธ

classmethod get_total_cpu_time_and_memory_usage()

Gives you the total CPU time of itself and all its children, plus the maximum RSS memory usage of itself and its single largest child (in kibibytes) ๐Ÿ“ˆ

Return type: tuple[float, int], where tuple is in /usr/share/doc/python3/html/library/stdtypes.html#tuple, float is in /usr/share/doc/python3/html/library/functions.html#float, and int is in /usr/share/doc/python3/html/library/functions.html#int ๐Ÿงพ

classmethod get_total_cpu_time()

Gives you the total CPU time, children included โฐ

Return type: float, see /usr/share/doc/python3/html/library/functions.html#float ๐Ÿ’œ

toil.lib.resources.glob(glob_pattern, directoryname)

Walks through a directory and its subdirectories looking for files that match the glob_pattern, then returns a list=[] ๐Ÿ—‚๏ธ

Parameters:

  • directoryname (toil.lib.misc.StrPath) โ€” any accessible folder name on the filesystem ๐Ÿ“
  • glob_pattern (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” a string like *.txt, which would find all the text files ๐Ÿ“

Returns: a list=[] of absolute filepaths matching the glob pattern ๐ŸŒŸ

Return type: list[str], where list is in /usr/share/doc/python3/html/library/stdtypes.html#list and str is in /usr/share/doc/python3/html/library/stdtypes.html#str โœจ


toil.lib.retry

This file holds the retry() decorator function and the RetryCondition object ๐Ÿ”

retry() can decorate any function based on the list of errors you want it to retry on. That list can hold normal Exception objects, and/or RetryCondition objects that wrap Exceptions to add extra conditions ๐ŸŽฏ

For example, retrying on one Exception (HTTPError):

from toil.lib.web import web_session
from requests.exceptions import HTTPError

@retry(errors=[HTTPError])
def update_my_wallpaper():
    return web_session.get('https://www.deviantart.com/')

Or:

from toil.lib.web import web_session
from requests.exceptions import HTTPError

@retry(errors=[HTTPError, ValueError])
def update_my_wallpaper():
    return web_session.get('https://www.deviantart.com/')

The examples above will retry for the default interval on any errors you list in the "errors=" arg list ๐ŸŒˆ

okay so, to retry on specifically 500/502/503/504 errors, you can swap in an ErrorCondition object instead, and it's giving precision ๐Ÿ’…

from toil.lib.web import web_session
from requests.exceptions import HTTPError

@retry(errors=[
    ErrorCondition(
               error=HTTPError,
               error_codes=[500, 502, 503, 504]
           )])
def update_my_wallpaper():
    return web_session.get('https://www.deviantart.com/')

bestie, if you only want to retry on errors containing the phrase "NotFound" ๐Ÿ™ˆ

from toil.lib.web import web_session
from requests.exceptions import HTTPError

@retry(errors=[
    ErrorCondition(
        error=HTTPError,
        error_message_must_include="NotFound"
    )])
def update_my_wallpaper():
    return web_session.get('https://www.deviantart.com/')

and for retrying on ALL HTTPError errors EXCEPT the ones containing "NotFound" ๐Ÿšซ, this is the one ๐Ÿ‘‘

from toil.lib.web import web_session
from requests.exceptions import HTTPError

@retry(errors=[
    HTTPError,
    ErrorCondition(
               error=HTTPError,
               error_message_must_include="NotFound",
               retry_on_this_condition=False
           )])
def update_my_wallpaper():
    return web_session.get('https://www.deviantart.com/')

and if you want to retry on boto3's specific status errors โ˜๏ธ it looks something like this:

import boto3
from botocore.exceptions import ClientError

@retry(errors=[
    ErrorCondition(
               error=ClientError,
               boto_error_codes=["BucketNotFound"]
           )])
def boto_bucket(bucket_name):
    boto_session = boto3.session.Session()
    s3_resource = boto_session.resource('s3')
    return s3_resource.Bucket(bucket_name)

Mix and match all you want ๐ŸŒˆ, just make sure each code is paired with the correct exception, bc a ValueError is never gonna hand you a 404, for example ๐Ÿ’€

the retry function as a decorator makes retrying functions way easier and clearer ๐Ÿฆ‹ It also pushes you toward smaller independent functions, instead of lumping a bunch of stuff that needs different retry conditions into one giant function ๐Ÿงฉ

the ErrorCondition object does the heavy lifting of writing specific retry conditions and boils it all down to an API that covers every common use-case, so you never have to write a bespoke function ๐Ÿซถ

Use-cases covered rn ๐Ÿ“‹

  1. Retrying on a normal error, like a KeyError.
  2. Retrying on HTTP error codes (use ErrorCondition).
  3. Retrying on boto 3's specific status errors, like "BucketNotFound" (use ErrorCondition).
  4. Retrying when an error message contains a certain phrase (use ErrorCondition).
  5. Explicitly NOT retrying on a condition (use ErrorCondition).
If you need new functionality, it's currently best practice in Toil to add it to the ErrorCondition itself rather than making a brand new custom retry method ๐Ÿ’–

โœจ Attributes โœจ

  • SUPPORTED_HTTP_ERRORS
  • kubernetes
  • botocore
  • logger
  • RT
  • DEFAULT_DELAYS
  • DEFAULT_TIMEOUT
  • E
  • retry_flaky_test

๐Ÿงš Classes ๐Ÿงš

  • ErrorCondition โ€” a wrapper describing an error condition ๐ŸŽ€

๐ŸŒธ Functions ๐ŸŒธ

  • retry([intervals, infinite_retries, errors, ...]) โ€” retry a function if it fails with any Exception defined in errors ๐Ÿ”
  • return_status_code(e)
  • get_error_code(e) โ€” get the error code name from a Boto 2 or 3 error, or compatible types ๐Ÿ”
  • get_error_message(e) โ€” get the error message string from a Boto 2 or 3 error, or compatible types ๐Ÿ’ฌ
  • get_error_status(e) โ€” get the HTTP status code from a compatible source ๐Ÿ”ข
  • get_error_body(e) โ€” get the body from a Boto 2 or 3 error, or compatible types ๐Ÿ“ฆ
  • meets_error_message_condition(e, error_message)
  • meets_error_code_condition(e, error_codes) โ€” these are expected to be normal HTTP error codes, like 404 or 500 ๐ŸŒก๏ธ
  • meets_boto_error_code_condition(e, boto_error_codes) โ€” these are expected to be AWS's custom error aliases, like 'BucketNotFound' or 'AccessDenied' โ˜๏ธ
  • error_meets_conditions(e, error_conditions)
  • old_retry([delays, timeout, predicate]) โ€” deprecated ๐Ÿ’€

๐Ÿฆ‹ Module Contents ๐Ÿฆ‹

  • toil.lib.retry.SUPPORTED_HTTP_ERRORS
  • toil.lib.retry.kubernetes = None
  • toil.lib.retry.botocore = None
  • toil.lib.retry.logger
class toil.lib.retry.ErrorCondition(error=None, error_codes=None, boto_error_codes=None, error_message_must_include=None, retry_on_this_condition=True)

A wrapper describing an error condition.

ErrorCondition events may be used to define errors in more detail, so you can decide whether to retry ๐ŸŒˆ

๐ŸŽ€ Parameters ๐ŸŽ€

  • error (Optional[type </usr/share/doc/python3/html/library/functions.html#type>[BaseException </usr/share/doc/python3/html/library/exceptions.html#BaseException>]])
  • error_codes (list </usr/share/doc/python3/html/library/stdtypes.html#list>[int </usr/share/doc/python3/html/library/functions.html#int>])
  • boto_error_codes (list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>])
  • error_message_must_include (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • retry_on_this_condition (bool, /usr/share/doc/python3/html/library/functions.html#bool)

Okay and the defaults for ErrorCondition are giving ๐Ÿ’…. Everything starts as None except the big one, retry_on_this_condition, which is True by default ๐Ÿซถ:

error = None
error_codes = None
boto_error_codes = None
error_message_must_include = None
retry_on_this_condition = True

toil.lib.retry.RT

This one is just listed with no extra notes ๐Ÿฆ‹.

toil.lib.retry.retry(intervals=None, infinite_retries=False, errors=None, log_message=None, prepare=None)

Okay this one is the main character ๐Ÿ‘‘. It retries a function if it fails with any Exception defined in errors. It does this every x seconds, where x comes from a list of numbers (ints or floats) in intervals. It also accepts ErrorCondition events for more detailed retry attempts ๐Ÿ’–.

Parameters ๐ŸŽ€

  • intervals (Optional[list], /usr/share/doc/python3/html/library/stdtypes.html#list) โ€” A list of times in seconds where we keep retrying until we return a failure. By default it uses exponential back-off before failing: 1s, 1s, 2s, 4s, 8s, 16s ๐Ÿ“
  • infinite_retries (bool, /usr/share/doc/python3/html/library/functions.html#bool) โ€” If this is True, the intervals reset once they run out. Defaults to False ๐ŸŒธ
  • errors (Optional[collections.abc.Sequence[Union[ErrorCondition, type[Exception]]]], /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Sequence, /usr/share/doc/python3/html/library/functions.html#type, /usr/share/doc/python3/html/library/exceptions.html#Exception) โ€” A list of exceptions OR ErrorCondition objects to catch and retry on. ErrorCondition objects describe more detailed error event conditions than a plain error. An ErrorCondition specifies:
    • Exception (required)
    • Error codes that must match to be retried (optional; defaults to not checking)
    • A string that must be in the error message to be retried (optional; defaults to not checking)
    • A bool that can be set to False to always error on this condition.

If not specified, this will default to a generic Exception ๐Ÿงš

  • log_message (Optional[tuple[Callable, str]], /usr/share/doc/python3/html/library/stdtypes.html#tuple, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” Optional tuple of ("log/print function()", "message string") that will print before each attempt ๐Ÿ“
  • prepare (Optional[list[Callable]], /usr/share/doc/python3/html/library/stdtypes.html#list) โ€” Optional list of functions to call, with the function's arguments, between retries to reset state ๐Ÿ”„

Returns

The result of the wrapped function, or it raises โœจ

Return type

Callable[[Callable[Ellipsis, RT]], Callable[Ellipsis, RT]]

toil.lib.retry.return_status_code(e)

Just the name and signature here, no extra deets ๐ŸŒธ.

toil.lib.retry.get_error_code(e)

Okay so this one grabs the error code name from a Boto 2 or 3 error, or compatible types ๐Ÿ”. For any other errors, it gives back an empty string ๐Ÿซฅ.

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)

Return type

str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.retry.get_error_message(e)

This one pulls the error message string from a Boto 2 or 3 error, or compatible types ๐Ÿ’ฌ.

Heads up, bestie: error message conditions check more than this. This function does not fall back to the traceback for incompatible types ๐Ÿ™ˆ

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)

Return type

str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.retry.get_error_status(e)

This one gets the HTTP status code from a compatible source ๐ŸŒ. That includes things like a Boto 2 or 3 error, kubernetes.client.rest.ApiException, http.client.HTTPException, urllib3.exceptions.HTTPError, requests.exceptions.HTTPError, urllib.error.HTTPError, or a compatible type ๐Ÿ’œ. For other errors, it returns 0 0๏ธโƒฃ.

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)

Return type

int (/usr/share/doc/python3/html/library/functions.html#int)

toil.lib.retry.get_error_body(e)

Grabs the body from a Boto 2 or 3 error, or compatible types ๐Ÿ“ฆ. If the error doesn't have a body, it returns the code and message instead ๐Ÿซถ.

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)

Return type

str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.retry.meets_error_message_condition(e, error_message)

No description here, just the parameters ๐ŸŒท.

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)
  • error_message (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.retry.meets_error_code_condition(e, error_codes)

These are expected to be normal HTTP error codes, like 404 or 500 ๐Ÿ”ข.

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)
  • error_codes (Optional[list[int]], /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/functions.html#int)

toil.lib.retry.meets_boto_error_code_condition(e, boto_error_codes)

These are expected to be AWS's custom error aliases, like 'BucketNotFound' or 'AccessDenied' โ˜๏ธ.

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)
  • boto_error_codes (Optional[list[str]], /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.lib.retry.error_meets_conditions(e, error_conditions)

Just the signature, no notes ๐Ÿฆ‹.

toil.lib.retry.DEFAULT_DELAYS = (0, 1, 1, 4, 16, 64)

A constant with the default delays, it's cute ๐ŸŒˆ.

toil.lib.retry.DEFAULT_TIMEOUT = 300

A constant with the default timeout, 300 ๐Ÿ•’.

toil.lib.retry.E

Just listed here, no extra notes โœจ.

toil.lib.retry.old_retry(delays=DEFAULT_DELAYS, timeout=DEFAULT_TIMEOUT, predicate=lambda e: ...)

Deprecated. This one's on its way out, so be careful using it ๐Ÿ’€

Okay so this retries an operation while the failure matches a given predicate. It keeps going until a given timeout expires, waiting a set amount of time between attempts. It's a generator that yields context managers. The doctests below show example usage ๐ŸŽ€.

Parameters

  • delays (Iterable[float], /usr/share/doc/python3/html/library/functions.html#float) โ€” An iterable yielding the time in seconds to wait before each retried attempt. The last element of the iterable will be repeated ๐Ÿ”
  • timeout (float, /usr/share/doc/python3/html/library/functions.html#float) โ€” An overall timeout that should not be exceeded for all attempts together. This is a best-effort mechanism only. It won't abort an ongoing attempt, even if the timeout expires during that attempt โณ
  • predicate (Callable[[Exception],bool], /usr/share/doc/python3/html/library/exceptions.html#Exception, /usr/share/doc/python3/html/library/functions.html#bool) โ€” A unary callable that returns True if another attempt should be made to recover from the given exception. The default value for this parameter will prevent any retries! ๐Ÿšซ

Returns

A generator yielding context managers, one per attempt โœจ

Return type

Iterator

Retry for a limited amount of time ๐Ÿ•ฐ๏ธ:

>>> true = lambda _:True
>>> false = lambda _:False
>>> i = 0
>>> for attempt in old_retry( delays=[0], timeout=.1, predicate=true ):
...     with attempt:
...         i += 1
...         raise RuntimeError('foo')
Traceback (most recent call last):
...
RuntimeError: foo
>>> i > 1
True

If timeout is 0, you get exactly one attempt 1๏ธโƒฃ:

>>> i = 0
>>> for attempt in old_retry( timeout=0 ):
...     with attempt:
...         i += 1
...         raise RuntimeError( 'foo' )
Traceback (most recent call last):
...
RuntimeError: foo
>>> i
1

Don't retry on success ๐Ÿ™…โ€โ™€๏ธ:

>>> i = 0
>>> for attempt in old_retry( delays=[0], timeout=.1, predicate=true ):
...     with attempt:
...         i += 1
>>> i
1

Don't retry unless the predicate returns True ๐Ÿ’…:

>>> i = 0
>>> for attempt in old_retry( delays=[0], timeout=.1, predicate=false):
...     with attempt:
...         i += 1
...         raise RuntimeError( 'foo' )
Traceback (most recent call last):
...
RuntimeError: foo
>>> i
1

toil.lib.retry.retry_flaky_test

Just listed here, no extra notes ๐Ÿฆ‹.


toil.lib.threading

Attributes

  • logger ๐Ÿ“ฃ
  • current_process_name_lock ๐Ÿ”’
  • current_process_name_for ๐Ÿงต

โœจ Classes โœจ

okay so this module has two classes and both are main character material ๐Ÿฆ‹

  • ExceptionalThread โ€” a thread whose join() method re-raises exceptions raised during run(). While join() is ๐ŸŒธ
  • LastProcessStandingArena โ€” a class that lets a whole crew of processes detect each other and elect a last process standing ๐Ÿ‘‘

โœจ Functions โœจ

bestie these are the helper functions and they're giving organized ๐Ÿ’…

  • ensure_filesystem_lockable(path[, timeout, hint]) โ€” checks that the filesystem at the given path is one where locks are actually safe to use ๐Ÿ”’
  • safe_lock(fd[, block, shared]) โ€” grabs an fcntl lock and keeps retrying on IO errors so it doesn't give up on you ๐Ÿ’–
  • safe_unlock_and_close(fd) โ€” releases an fcntl lock and closes the file descriptor, handling fcntl IO errors while it's at it ๐Ÿงน
  • cpu_count() โ€” gets the rounded-up integer number of whole CPUs available โญ
  • collect_process_name_garbage() โ€” deletes all the process names that point to files that don't exist anymore ๐Ÿ—‘๏ธ
  • destroy_all_process_names() โ€” deletes all of our process name files because our process is about to leave the chat ๐Ÿซถ
  • get_process_name(base_dir) โ€” returns the name of the current process. Like a PID, but visible between ๐Ÿงš
  • process_name_exists(base_dir, name) โ€” returns true if the process named by the given name (from process_name) exists, and false otherwise ๐Ÿ”
  • global_mutex(base_dir, mutex) โ€” a context manager that locks a mutex. The mutex is identified by the given ๐ŸŽ€

โœจ Module Contents โœจ

okay the full tea is here, let's go ๐Ÿ“

  • toil.lib.threading.logger โ€” the logger for this module ๐ŸŒˆ

๐Ÿ”’ ensure_filesystem_lockable

toil.lib.threading.ensure_filesystem_lockable(path, timeout=30, hint=None)

bestie, this one is the gatekeeper ๐Ÿšช It makes sure the filesystem at the given path is one where locks are safe to use.

File locks are not safe on Ceph. ๐Ÿ’€ See https://github.com/DataBiosphere/toil/issues/4972.

It raises an exception if the filesystem is detected as one where using locks is known to trigger bugs in the filesystem implementation. It also raises if the given path does not exist, or if figuring out the filesystem type takes longer than the timeout (in seconds). ๐Ÿ˜ญ

If the filesystem type can't be determined, it does nothing. no drama ๐ŸŒธ

Parameters

  • hint (Optional[str], </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” extra text to include in an error, if one is raised, telling the user how to change the offending path ๐Ÿ’Œ
  • path (toil.lib.misc.StrPath) ๐Ÿ›ค๏ธ
  • timeout (float, </usr/share/doc/python3/html/library/functions.html#float>) โฑ๏ธ

Return type: None

๐Ÿ”’ safe_lock

toil.lib.threading.safe_lock(fd, block=True, shared=False)

Gets an fcntl lock and retries on IO errors, so it's super persistent ๐Ÿ’ช

It raises OSError with EACCES or EAGAIN when a nonblocking lock is not immediately available. ๐Ÿšจ

Parameters

  • fd (int, </usr/share/doc/python3/html/library/functions.html#int>) ๐Ÿ”ข
  • block (bool, </usr/share/doc/python3/html/library/functions.html#bool>) ๐Ÿšง
  • shared (bool, </usr/share/doc/python3/html/library/functions.html#bool>) ๐Ÿค

Return type: None

๐Ÿ”“ safe_unlock_and_close

toil.lib.threading.safe_unlock_and_close(fd)

Releases an fcntl lock and closes the file descriptor, and handles fcntl IO errors while doing it. clean exit only โœจ

Parameters

  • fd (int, </usr/share/doc/python3/html/library/functions.html#int>) ๐Ÿ”ข

Return type: None

๐Ÿงต class ExceptionalThread

class toil.lib.threading.ExceptionalThread(group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None, context=None)

Bases: threading.Thread (</usr/share/doc/python3/html/library/threading.html#threading.Thread>)

okay this is the one I'm obsessed with ๐Ÿ˜ญ A thread whose join() method re-raises exceptions raised during run(). While join() is idempotent, the exception only comes up during the first call to join() that successfully joins the thread. If join() times out, no exception gets re-raised, even if one already happened inside run(). ๐Ÿ’…

When you subclass this thread, override tryRun() instead of run(). โœจ

Here's the example in the docs, verbatim:

>>> def f():
...     assert 0
>>> t = ExceptionalThread(target=f)
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

>>> class MyThread(ExceptionalThread):
...     def tryRun( self ):
...         assert 0
>>> t = MyThread()
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

Attributes

  • exc_info = None ๐Ÿงพ

Methods

  • run() โ€” "Method representing the thread's activity." You can override this in a subclass. The standard run() invokes the callable object passed to the object's constructor as the target argument (if any), with sequential (positional) and keyword arguments taken from the args and kwargs arguments, respectively. ๐Ÿƒโ€โ™€๏ธ
    • Return type: None
  • tryRun() ๐Ÿซง
    • Return type: None
  • join(*args, **kwargs) โ€” waits until the thread terminates. This blocks the calling thread until the thread whose join() is called terminates, either normally, through an unhandled exception, or until the optional timeout occurs. โณ
    • When the timeout argument is present and not None, it should be a floating-point number of seconds (or fractions of one). Since join() always returns None, you must call is_alive() after join() to tell whether a timeout happened. If the thread is still alive, the join() call timed out. ๐Ÿซ 
    • When timeout is missing or None, it blocks until the thread terminates. ๐Ÿงฑ
    • A thread can be join()ed many times. ๐Ÿ”
    • join() raises a RuntimeError if you try to join the current thread, because that would cause a deadlock. ๐Ÿ’€ It's also an error to join() a thread before it has been started, and trying that raises the same exception. ๐Ÿšซ
    • Parameters
      • args (Optional[float], </usr/share/doc/python3/html/library/functions.html#float>) ๐ŸŽˆ
      • kwargs (Optional[float], </usr/share/doc/python3/html/library/functions.html#float>) ๐ŸŽˆ
    • Return type: None

๐Ÿงฎ cpu_count

toil.lib.threading.cpu_count()

Gets the rounded-up integer number of whole CPUs available. โญ

Hyperthreads count as CPUs here, no cap ๐Ÿง 

It uses the system's actual CPU count, or the current v1 cgroup's quota per period if the quota is set. ๐ŸŽ€

Okay so this one ignores the cgroup's cpu shares value ๐Ÿ™ˆ because it's extremely difficult to interpret (same, bestie). If you want the drama, see https://github.com/kubernetes/kubernetes/issues/81021 ๐ŸŒธ

It also stashes the result so it's not redoing the work every time ๐Ÿง โœจ

Returns: an integer count of available CPUs, minimum 1 ๐Ÿ’–

Return type: int


๐Ÿ”’ toil.lib.threading.current_process_name_lock

Just a name on the list, no extra notes here ๐Ÿซถ

๐Ÿ“‡ toil.lib.threading.current_process_name_for

Type: dict[str, str]

๐Ÿ—‘๏ธ toil.lib.threading.collect_process_name_garbage()

This one deletes every process name that points to a file that doesn't exist anymore, bc the work directory was temporary and got cleaned up ๐Ÿงน. It's known to happen during the tests, which get their own temp directories, so it's very much a real thing ๐Ÿ’…

๐Ÿšจ Caller must hold current_process_name_lock.

Return type: None

๐Ÿ‘‹ toil.lib.threading.destroy_all_process_names()

Okay this one deletes all our process name files because our process is going away ๐Ÿ˜ญ. We let all our FDs get closed by the process death, which is honestly so iconic of it. We assume there is nobody else using the system during exit to race with ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

Return type: None

๐Ÿงš toil.lib.threading.get_process_name(base_dir)

Returns the name of the current process. It's like a PID, but it's visible between containers on what Toil thinks is a node ๐Ÿ‘‘

Parameters

  • base_dir (str) โ€” Base directory to work in. Defines the shared namespace.

Returns: Process's assigned name

Return type: str

๐Ÿ‘€ toil.lib.threading.process_name_exists(base_dir, name)

Returns True if the process named by the given name (from process_name) exists, and False otherwise. It can see across container boundaries using the given node workflow directory, which is so main character energy ๐ŸŽ€

Parameters

  • base_dir (str) โ€” Base directory to work in. Defines the shared namespace.
  • name (str) โ€” Process's name to poll.

Returns: True if the named process is still alive, and False otherwise.

Return type: bool

๐Ÿ” toil.lib.threading.global_mutex(base_dir, mutex)

A context manager that locks a mutex ๐Ÿ”. The mutex is identified by the given name and scoped to the given directory. It works across all containers that have access to the given directory, and mutexes held by dead processes are automatically released ๐Ÿซ 

โš ๏ธ Only works between processes, NOT between threads.

Parameters

  • base_dir (toil.lib.misc.StrPath) โ€” Base directory to work in. Defines the shared namespace.
  • mutex (str) โ€” Mutex to lock. Must be a permissible path component.

Return type: collections.abc.Iterator[None]

๐Ÿ† class toil.lib.threading.LastProcessStandingArena(base_dir, name)

This class lets a bunch of processes detect and elect a last process standing ๐Ÿ‘‘. Processes enter and leave, sometimes due to sudden existence failure ๐Ÿ’€. We guarantee that the last process to leave, if it leaves properly, gets a chance to do some cleanup. If new processes try to enter during the cleanup, they get delayed until after the cleanup has happened and the previous "last" process has finished leaving. Very patient of them ๐Ÿซถ

๐Ÿšจ The user is responsible for making sure you always leave if you enter! Consider using a try/finally; this class is not a context manager.

Parameters

  • base_dir (toil.lib.misc.StrPath)
  • name (str)

Attributes

  • base_dir = ''
  • mutex
  • lockfileDir
  • lockfileFD = None
  • lockfileName = None

Methods

enter()

This process is entering the arena. If cleanup is in progress, it blocks until the cleanup is finished ๐Ÿšช. You may not enter the arena again before leaving it.

Return type: None

leave()

This process is leaving the arena. If this process happens to be the last process standing, it yields something, and other processes are blocked from joining the arena until the loop body completes and the process has finished leaving. Otherwise, it doesn't yield anything ๐ŸŒˆ

It should be used in a loop, like this:

for _ in arena.leave():
    # If we get here, we were the last process. Do the cleanup pass

Return type: collections.abc.Iterator[bool]


๐Ÿฆ‹ toil.lib.throttle

Classes

  • LocalThrottle โ€” A thread-safe rate limiter that throttles each thread independently. Can be used as a
  • throttle โ€” A context manager for ensuring that the execution of its body takes at least a given amount

Module Contents

๐Ÿข class toil.lib.throttle.LocalThrottle(min_interval)

A thread-safe rate limiter that throttles each thread independently ๐Ÿงต. It can be used as a function or method decorator, or as a simple object via its .throttle() method โœจ

๐Ÿšจ The use as a decorator is deprecated in favor of throttle().

Parameters

  • min_interval (int)

Attributes

  • min_interval
  • per_thread

Methods

throttle(wait=True)

If the wait parameter is True, this method returns True after suspending the current thread as necessary to ensure that no less than the configured minimum interval has passed since the last invocation of this method in the current thread returned True ๐Ÿ•ฐ๏ธ.

If the wait parameter is False, this method immediately returns True (if at least the configured minimum interval has passed since the last time this method returned True in the current thread) or False otherwise.

Parameters

  • wait (bool)

Return type: bool

__call__(function)

๐Ÿฆ‹ class toil.lib.throttle.throttle(min_interval)

A context manager for ensuring that the execution of its body takes at least a given amount of time, sleeping if necessary ๐Ÿ˜ด. It's a simpler version of LocalThrottle if used as a decorator ๐Ÿ’…

It ensures that the body takes at least the given amount of time.

>>> start = time.time()
>>> with throttle(1):
...     pass
>>> 1 <= time.time() - start <= 1.1
True

Ditto when used as a decorator.

>>> @throttle(1)
... def f():
...     pass
>>> start = time.time()
>>> f()
>>> 1 <= time.time() - start <= 1.1
True

If the body takes longer by itself, don't throttle ๐Ÿ™…โ€โ™€๏ธ.

>>> start = time.time()
>>> with throttle(1):
...     time.sleep(2)
>>> 2 <= time.time() - start <= 2.1
True

Ditto when used as a decorator.

>>> @throttle(1)
... def f():
...     time.sleep(2)
>>> start = time.time()
>>> f()
>>> 2 <= time.time() - start <= 2.1
True

If an exception occurs, don't throttle ๐Ÿ’€.

>>> start = time.time()
>>> try:
...     with throttle(1):
...         raise ValueError('foo')
... except ValueError:
...     end = time.time()
...     raise
Traceback (most recent call last):
...
ValueError: foo
>>> 0 <= end - start <= 0.1
True

Ditto when used as a decorator.

>>> @throttle(1)
... def f():
...     raise ValueError('foo')
>>> start = time.time()
>>> try:
...     f()
... except ValueError:
...     end = time.time()
...     raise
Traceback (most recent call last):
...
ValueError: foo
>>> 0 <= end - start <= 0.1
True

Parameters

  • min_interval (Union[int, float])

Attributes

  • min_interval

Methods

__enter__()

__exit__(exc_type, exc_val, exc_tb)

__call__(function)

โœจ toil.lib.trs โœจ

okay bestie, this module is all about TRS ๐Ÿฆ‹ It's how Toil hooks into GA4GH Tool Registry Service servers so you can go fetch workflows straight from them. literally main character energy ๐Ÿ’…

๐Ÿ’– Attributes

  • logger
  • TRS_ROOT

๐Ÿงš Functions

  • is_trs_workflow(workflow) โ€” checks if a workflow string smells like TRS ๐Ÿ‘ƒ
  • extract_trs_spec(workflow) โ€” turns a Dockstore workflow URL or TSR ID into a string that is definitely a TRS ID ๐ŸŽ€
  • parse_trs_spec(trs_spec) โ€” splits a TRS ID into a workflow and an optional version ๐ŸŒธ
  • compose_trs_spec(trs_workflow_id, trs_version) โ€” builds a TRS ID from a workflow ID and a version ID ๐Ÿซถ
  • find_workflow(workflow[, supported_languages]) โ€” given a Dockstore URL or TRS identifier, gets the root WDL or CWL URL for the workflow, along with the TRS workflow ID and version ๐Ÿ”ฅ
  • fetch_workflow(trs_workflow_id, trs_version, language) โ€” returns a URL or local path to a workflow's primary descriptor file ๐Ÿ‘‘
  • resolve_workflow(workflow[, supported_languages]) โ€” finds the real workflow URL or filename from a command line argument โญ

๐ŸŒˆ Module Contents

toil.lib.trs.logger

toil.lib.trs.TRS_ROOT = 'https://dockstore.org'

toil.lib.trs.is_trs_workflow(workflow)

Returns True if a workflow string smells like TRS. It detects Dockstore page URLs and strings that could be Dockstore TRS IDs ๐Ÿ‘€

  • Parameters
    • workflow (str)
  • Return type
    • bool

toil.lib.trs.extract_trs_spec(workflow)

Parses a Dockstore workflow URL or TSR ID into a string that is definitely a TRS ID โœจ

  • Parameters
    • workflow (str)
  • Return type
    • str

toil.lib.trs.parse_trs_spec(trs_spec)

Parses a TRS ID into a workflow and an optional version ๐ŸŒท

  • Parameters
    • trs_spec (str)
  • Return type
    • tuple[str, Optional[str]]

toil.lib.trs.compose_trs_spec(trs_workflow_id, trs_version)

Composes a TRS ID from a workflow ID and a version ID ๐Ÿงฉ

  • Parameters
    • trs_workflow_id (str)
    • trs_version (str)
  • Return type
    • str

toil.lib.trs.find_workflow(workflow, supported_languages=None)

Given a Dockstore URL or TRS identifier, this gets the root WDL or CWL URL for the workflow, plus the TRS workflow ID and version ๐Ÿ•ต๏ธโ€โ™€๏ธ

Accepts inputs like:

It assumes the input is actually one of the supported formats. Check out is_trs_workflow() for that ๐Ÿซถ

๐Ÿ“ TODO: Needs to handle multi-workflow files if Dockstore can.
  • Raises
    • FileNotFoundError: if the workflow or version doesn't exist.
    • ValueError: if the version is not specified but cannot be automatically determined.
  • Parameters
    • workflow (str)
    • supported_languages (Optional[set[str]])
  • Return type
    • tuple[str, str, str]

toil.lib.trs.fetch_workflow(trs_workflow_id, trs_version, language)

Returns a URL or local path to a workflow's primary descriptor file. The file comes with its required files, so it can actually run ๐Ÿƒโ€โ™€๏ธ

  • Raises
    • FileNotFoundError: if the workflow or version doesn't exist.
  • Parameters
    • trs_workflow_id (str)
    • trs_version (str)
    • language (str)
  • Return type
    • str

toil.lib.trs.resolve_workflow(workflow, supported_languages=None)

Finds the real workflow URL or filename from a command line argument. It transforms a workflow URL or path (which might secretly be a Dockstore page URL or TRS specifier) into an actual URL or path to a workflow document, plus an optional TRS specifier ๐Ÿ’ซ

Accepts inputs like:


โœจ toil.lib.url โœจ

๐ŸŒธ Attributes

  • logger

๐Ÿ’ฅ Exceptions

  • ProxyConnectionError โ€” a dummy class ๐Ÿซฅ

๐Ÿฆ‹ Classes

  • URLAccess โ€” a widget for accessing external storage (URLs) ๐Ÿ”Œ

โœจ Functions โœจ

okay bestie, these four factory functions are all part of the toil.lib.url era ๐Ÿ’…

  • file_job_store_factory()
  • google_job_store_factory()
  • aws_job_store_factory()
  • job_store_support_factory()

๐Ÿงš Module Contents ๐Ÿงš

  • exception toil.lib.url.ProxyConnectionError: bases BaseException (/usr/share/doc/python3/html/library/exceptions.html#BaseException). It's a dummy class, so it's basically a placeholder rn ๐Ÿ™ˆ
  • toil.lib.url.logger ๐Ÿชต
  • class toil.lib.url.URLAccess: a little widget for accessing external storage (URLs) ๐Ÿ”ฅ
    • classmethod url_exists(src_uri): returns True if the file at the given URI exists and False otherwise. ngl it might raise an error if existence can't be figured out ๐Ÿ’€
      • Parameters: src_uri (str, /usr/share/doc/python3/html/library/stdtypes.html#str): URL pointing to a file or object in the storage mechanism of a supported URL scheme, e.g. a blob in an AWS s3 bucket.
      • Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)
    • classmethod get_size(src_uri): gets the size in bytes of the file at the given URL, or None if it can't be obtained ๐Ÿ“
      • Parameters: src_uri (str, /usr/share/doc/python3/html/library/stdtypes.html#str): URL pointing to a file or object in the storage mechanism of a supported URL scheme, e.g. a blob in an AWS s3 bucket.
      • Return type: Optional[int] (/usr/share/doc/python3/html/library/functions.html#int)
    • classmethod get_is_directory(src_uri): returns True if the thing at the given URL is a directory and False if it's a file. The URL may or may not end in '/'.
      • Parameters: src_uri (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
      • Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)
    • classmethod list_url(src_uri): lists the directory at the given URL ๐Ÿ“‚. Returned path components can be joined with '/' onto the passed URL to form new URLs, and the ones that end in '/' are directories. The provided URL may or may not end with '/'.
      • Currently supported schemes are:
        • 's3' for objects in Amazon S3, e.g. s3://bucket/prefix/
        • 'file' for local files, e.g. file:///local/dir/path/
      • Parameters: src_uri (str, /usr/share/doc/python3/html/library/stdtypes.html#str): URL pointing to a directory or prefix in the storage mechanism of a supported URL scheme, e.g. a prefix in an AWS s3 bucket.
      • Returns: a list of URL components in the given directory, already URL-encoded.
      • Return type: list[str] (/usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str)
    • classmethod read_from_url(src_uri, writable): reads the given URL and writes its content into the given writable stream ๐Ÿ“. Raises FileNotFoundError if the URL doesn't exist.
      • Returns: the size of the file in bytes and whether the executable permission bit is set.
      • Parameters:
        • src_uri (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
        • writable (IO[bytes], /usr/share/doc/python3/html/library/stdtypes.html#bytes)
      • Return type: tuple[int, bool] (/usr/share/doc/python3/html/library/stdtypes.html#tuple, /usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/functions.html#bool)
    • classmethod open_url(src_uri): reads from the given URI ๐Ÿ“–. Raises FileNotFoundError if the URL doesn't exist. It has a readable stream interface, unlike read_from_url(), which takes a writable stream.
      • Parameters: src_uri (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
      • Return type: IO[bytes] (/usr/share/doc/python3/html/library/stdtypes.html#bytes)
  • toil.lib.url.file_job_store_factory(): return type type[URLAccess <#toil.lib.url.URLAccess>] (/usr/share/doc/python3/html/library/functions.html#type)
  • toil.lib.url.google_job_store_factory(): return type type[URLAccess <#toil.lib.url.URLAccess>] (/usr/share/doc/python3/html/library/functions.html#type)
  • toil.lib.url.aws_job_store_factory(): return type type[URLAccess <#toil.lib.url.URLAccess>] (/usr/share/doc/python3/html/library/functions.html#type)
  • toil.lib.url.job_store_support_factory(): return type type[URLAccess <#toil.lib.url.URLAccess>] (/usr/share/doc/python3/html/library/functions.html#type)

๐ŸŒˆ toil.lib.web ๐ŸŒˆ

Contains functions for making web requests with Toil ๐ŸŒ. All web requests should go through this module, so they all use the right user agent. Here's the example:

>>> httpserver = getfixture("httpserver")
>>> handler = httpserver.expect_request("/path").respond_with_json({})
>>> from toil.lib.web import web_session
>>> web_session.get(httpserver.url_for("/path"))
<Response [200]>

โœจ Attributes โœจ

  • web_session

๐Ÿงš Module Contents ๐Ÿงš

  • toil.lib.web.web_session

๐Ÿฆ‹ toil.options ๐Ÿฆ‹

๐ŸŒธ Submodules ๐ŸŒธ

  • toil.options.common

๐Ÿ’œ toil.options.common: Attributes ๐Ÿ’œ

  • logger
  • defaultTargetTime
  • SYS_MAX_SIZE
  • JOBSTORE_HELP

โœจ Functions โœจ

okay so this is the cute little cheat sheet for every helper in toil.options.common ๐Ÿซถ here's the lineup:

  • parse_set_env(l) โ€” parses a list of strings like "NAME=VALUE" (or just "NAME") into a dictionary ๐Ÿ’–
  • parse_str_list(s) โ€” no description written for this one ๐Ÿ™ˆ
  • parse_int_list(s) โ€” no description written for this one either ๐ŸŒธ
  • iC(min_value[, max_value]) โ€” hands you back a function that checks if an int is in the half-open interval ๐ŸŽ€
  • fC(minValue[, maxValue]) โ€” same energy as iC, but for floats โœจ
  • parse_accelerator_list(specs) โ€” parses a string description of one or more accelerator requirements ๐Ÿ”ฅ
  • parseBool(val) โ€” no description written for this one ๐Ÿ’…
  • make_open_interval_action(min[, max]) โ€” gives you an argparse action class that checks the input is within the half-open interval ๐Ÿฆ‹
  • parse_jobstore(jobstore_uri) โ€” turns the jobstore string into its matching URI ๐Ÿงš
  • add_base_toil_options(parser[, jobstore_as_flag, cwl]) โ€” adds the base Toil command line options to your parser ๐Ÿ‘‘

โœจ Module Contents โœจ

toil.options.common.logger

No description given for this one ๐Ÿชต

toil.options.common.defaultTargetTime

toil.options.common.defaultTargetTime = 1800

toil.options.common.SYS_MAX_SIZE

toil.options.common.SYS_MAX_SIZE = 9223372036854775807

toil.options.common.parse_set_env(l)

okay this one is literally so useful ๐Ÿ’– it takes a list of strings shaped like NAME=VALUE (or just NAME) and turns them into a dictionary. names that show up with no = at all get a value of None, so they don't just vanish ๐Ÿ™ˆ

>>> parse_set_env([])
{}
>>> parse_set_env(['a'])
{'a': None}
>>> parse_set_env(['a='])
{'a': ''}
>>> parse_set_env(['a=b'])
{'a': 'b'}
>>> parse_set_env(['a=a', 'a=b'])
{'a': 'b'}
>>> parse_set_env(['a=b', 'c=d'])
{'a': 'b', 'c': 'd'}
>>> parse_set_env(['a=b=c'])
{'a': 'b=c'}
>>> parse_set_env([''])
Traceback (most recent call last):
...
ValueError: Empty name
>>> parse_set_env(['=1'])
Traceback (most recent call last):
...
ValueError: Empty name

Parameters

  • l (list[str])

Return type

dict[str, Optional[str]]

toil.options.common.parse_str_list(s)

Parameters

  • s (str)

Return type

list[str]

toil.options.common.parse_int_list(s)

Parameters

  • s (str)

Return type

list[int]

toil.options.common.iC(min_value, max_value=None)

returns a function that checks if a given int is in the given half-open interval ๐ŸŽ€

Parameters

  • min_value (int)
  • max_value (Optional[int])

Return type

Callable[[int], bool]

toil.options.common.fC(minValue, maxValue=None)

same vibe as iC but for floats โœจ returns a function that checks if a given float is in the given half-open interval

Parameters

  • minValue (float)
  • maxValue (Optional[float])

Return type

Callable[[float], bool]

toil.options.common.parse_accelerator_list(specs)

parses a string description of one or more accelerator requirements ๐Ÿ”ฅ

Parameters

  • specs (Optional[str])

Return type

list[toil.job.AcceleratorRequirement]

toil.options.common.parseBool(val)

Parameters

  • val (str)

Return type

bool

toil.options.common.make_open_interval_action(min, max=None)

returns an argparse action class to check if the input is within the given half-open interval ๐Ÿฆ‹ for example, the value given to argparse has to be within the interval [min, max). the types of min and max must match (and max can be None) ๐Ÿ’…

Parameters

  • min (Union[int, float]) โ€” float/int
  • max (Optional[Union[int, float]]) โ€” optional float/int

Returns

argparse action class

Return type

type[argparse.Action]

toil.options.common.parse_jobstore(jobstore_uri)

turns the jobstore string into its corresponding URI ๐Ÿงš for example, /path/to/jobstore -> <file:/path/to/jobstore>

if the jobstore string is already a URI, it gets returned as-is. for example, aws:/path/to/jobstore -> aws:/path/to/jobstore

:param jobstore_uri: string of the jobstore :return: URI of the jobstore

Parameters

  • jobstore_uri (str)

Return type

str

toil.options.common.JOBSTORE_HELP

Multiline-String ๐Ÿ’œ this is the help text for the job store location, and it's a whole thing:

The location of the job store for the workflow. A job store holds persistent information about the jobs, stats, and files in a workflow. If the workflow is run with a distributed batch system, the job store must be accessible by all worker nodes. Depending on the desired job store implementation, the location should be formatted according to one of the following schemes:

  • file:<path> where <path> points to a directory on the file system
  • aws:<region>:<prefix> where <region> is the name of an AWS region like us-west-2 and <prefix> will be prepended to the names of any top-level AWS resources in use by job store, e.g. S3 buckets.
  • google:<project_id>:<prefix> TODO: explain

For backwards compatibility, you may also specify ./foo (equivalent to file:./foo or just file:foo) or /bar (equivalent to file:/bar).

toil.options.common.add_base_toil_options(parser,
jobstore_as_flag=False, cwl=False)

okay bestie, this one is the base options helper ๐Ÿ’– It slaps the basic Toil command line flags onto your parser โœจ Basically add_base_toil_options is the one that makes sure every Toil command has the same core setup. no cap, it's giving consistency ๐Ÿ’…

  • parser is the argparse.ArgumentParser you want the options added to (docs: /usr/share/doc/python3/html/library/argparse.html#argparse.ArgumentParser) ๐Ÿงš
  • jobstore_as_flag is a bool (docs: /usr/share/doc/python3/html/library/functions.html#bool). If it's True, the job store option becomes a --jobStore flag instead of a required jobStore positional argument. Lowkey a big deal, so pay attention ๐Ÿ‘€
  • cwl is a bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) that controls whether CWL should be included or not ๐ŸŒˆ

It returns None. Nothing to see there, just vibes ๐Ÿซถ


toil.options.cwl

Functions

  • add_cwl_options(parser[, suppress]) โ€” adds CWL options to the parser. It only adds nonpositional CWL arguments โœจ

Module Contents

toil.options.cwl.add_cwl_options(parser, suppress=True)

Okay so this one is the CWL version of the same idea ๐Ÿฆ‹ It adds CWL options to the parser, but only the nonpositional ones, so no positional arguments sneaking in ๐Ÿ™ˆ

  • parser is an argparse.ArgumentParser (docs: /usr/share/doc/python3/html/library/argparse.html#argparse.ArgumentParser) and it's the parser you want the options added to ๐ŸŽ€
  • suppress is a bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) that suppresses the help output. Default is True ๐Ÿ’œ

It returns None. Same energy as before ๐Ÿ’…


toil.options.runner

Functions

  • add_runner_options(parser[, cwl, wdl]) โ€” adds options to the WDL or CWL runners that are shared or the same between runners. The main character of the shared-options world ๐Ÿ‘‘

Module Contents

toil.options.runner.add_runner_options(parser, cwl=False, wdl=False)

This is the one that handles the stuff both runners have in common, so you don't have to copy-paste it twice (iconic, honestly) ๐ŸŒธ It adds to the WDL or CWL runners options that are shared or the same between runners.

  • parser is the parser you want the arguments added to ๐Ÿงš
  • cwl is a bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) โญ
  • wdl is a bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ“

It returns None ๐Ÿซถ


toil.options.wdl

Functions

  • add_wdl_options(parser[, suppress]) โ€” adds WDL options to a parser. This only adds nonpositional WDL arguments. WDL's own little lane, periodt โœจ

Module Contents

toil.options.wdl.add_wdl_options(parser, suppress=True)

Same vibe as the CWL one, just for WDL ๐Ÿฆ‹ It adds WDL options to a parser, and again only the nonpositional arguments.

  • parser is the parser you want the options added to ๐ŸŽ€
  • suppress is a bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) that suppresses the help output. Default is True ๐Ÿ’œ

It returns None ๐Ÿ’…


toil.provisioners

Submodules

  • toil.provisioners.abstractProvisioner ๐ŸŒˆ

toil.provisioners.abstractProvisioner

Attributes

  • a_short_time
  • logger

Exceptions

  • ManagedNodesNotSupportedException โ€” raised when attempting to add managed nodes (which autoscale up and down by themselves, without the provisioner doing the work) to a provisioner that does not support them ๐Ÿ™ˆ

Classes

  • Shape โ€” represents a job or a node's "shape", in terms of the dimensions of memory, cores, disk and wall-time allocation ๐Ÿงš
  • AbstractProvisioner โ€” the interface for provisioning worker nodes to use in a Toil cluster ๐Ÿ‘‘

Module Contents

toil.provisioners.abstractProvisioner.a_short_time = 5
toil.provisioners.abstractProvisioner.logger

exception toil.provisioners.abstractProvisioner.ManagedNodesNotSupportedException ๐Ÿ’€

Bases: RuntimeError (docs: /usr/share/doc/python3/html/library/exceptions.html#RuntimeError)

Okay, this is the error you get when you try to add managed nodes to a provisioner that can't handle them. Managed nodes autoscale up and down by themselves, without the provisioner doing the work for them, so it's a whole different situation ๐Ÿ˜ญ

Polling with this and try/except is the Right Way to check if managed nodes are available from a provisioner. Use try/except, not vibes ๐Ÿ’…

class toil.provisioners.abstractProvisioner.Shape(wallTime, memory, cores, disk, preemptible) ๐Ÿฆ‹

Bases: none listed. This is the class that describes a job's or a node's "shape" ๐ŸŒธ It's all about the dimensions: memory, cores, disk and wall-time allocation.

The wallTime attribute stores the number of seconds of a node allocation, e.g. 3600 for AWS. FIXME: and for jobs? (yep, the original page is still wondering about that one ๐Ÿ™ˆ)

The memory and disk attributes store the number of bytes required by a job (or provided by a node) in RAM or on disk (SSD or HDD), respectively ๐Ÿ’œ

Parameters

  • wallTime (Union[int, float])
  • memory (int)
  • cores (Union[int, float])
  • disk (int)
  • preemptible (bool, docs: /usr/share/doc/python3/html/library/functions.html#bool)

Attributes

  • wallTime
  • memory
  • cores
  • disk
  • preemptible

Methods

  • __eq__(other) โ€” takes other (Any) and returns bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿซถ
  • greater_than(other) โ€” takes other (Any) and returns bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ”ฅ
  • __gt__(other) โ€” takes other (Any) and returns bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) โญ
  • __repr__() โ€” returns str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŽ€
  • __str__() โ€” returns str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐ŸŒˆ
  • __hash__() โ€” returns int (docs: /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ“

class toil.provisioners.abstractProvisioner.AbstractProvisioner(clusterName=None, clusterType='mesos', zone=None, nodeStorage=50, nodeStorageOverrides=None, enable_fuse=False) โœจ

Bases: abc.ABC (docs: /usr/share/doc/python3/html/library/abc.html#abc.ABC)

This is the interface for provisioning worker nodes to use in a Toil cluster. It's the blueprint, bestie, so anything that wants to be a provisioner has to follow it ๐Ÿ‘‘

Parameters

  • clusterName (Optional[str], docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • clusterType (Optional[str], docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • zone (Optional[str], docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • nodeStorage (int, docs: /usr/share/doc/python3/html/library/functions.html#int)
  • nodeStorageOverrides (Optional[list[str]]) โ€” an optional list of strings, so you can skip it if you don't need it ๐Ÿ“ฆ
  • enable_fuse (bool) โ€” a true-or-false switch โœจ

These are the class-level defaults, so you get these vibes unless you override them ๐ŸŒธ

LEADER_HOME_DIR = '/root/'
cloud: str = None
clusterName = None
clusterType = 'mesos'
enable_fuse = False

๐Ÿ’… abstractmethod supportedClusterTypes()

Get all the cluster types this provisioner implementation supports. Think of it as the menu of what's on offer ๐Ÿ“

Return type โ€” set[str]

โœจ abstractmethod createClusterSettings()

Initialize the class for a brand-new cluster that's about to get deployed, when you're running outside the cloud ๐ŸŒˆ

๐Ÿ‘‘ abstractmethod readClusterSettings()

Initialize the class from an existing cluster. This one assumes the instance you're on is the leader, so it's giving leader energy ๐Ÿ‘‘. Implementations must call _setLeaderWorkerAuthentication(). Not optional, periodt ๐Ÿ’€.

๐ŸŒธ setAutoscaledNodeTypes(nodeTypes)

Set the node types, shapes and spot bids for Toil-managed autoscaling ๐Ÿ“ˆ

Parameters

  • nodeTypes (list[tuple[set[str], Optional[float]]]) โ€” a list of node types, as parsed with parse_node_types.

๐Ÿงš hasAutoscaledNodeTypes()

Checks whether node types have already been configured on the provisioner, via setAutoscaledNodeTypes. Quick vibe check โœ…

Returns โ€” True if node types are configured for autoscaling, and false otherwise.

Return type โ€” bool

๐Ÿ“ getAutoscaledInstanceShapes()

Gets all the node shapes and their named instance types that the Toil autoscaler should manage ๐Ÿ“

Return type โ€” dict[Shape, str]

๐Ÿ™ˆ static retryPredicate(e)

Returns true if the exception e should be retried by the cluster scaler. For example, it should return true if the exception came from hitting an API rate limit. The error gets retried with exponential backoff โณ

Parameters

  • e โ€” the exception raised during execution of setNodeCount.

Returns โ€” a boolean indicating whether the exception e should be retried.

๐Ÿซถ abstractmethod launchCluster(*args, **kwargs)

Initialize a cluster and create a leader node ๐Ÿš€. Implementations must call _setLeaderWorkerAuthentication() with the leader so that workers can actually get launched.

Parameters

  • leaderNodeType โ€” the leader instance.
  • leaderStorage โ€” the amount of disk to allocate to the leader, in gigabytes.
  • owner โ€” tag identifying the owner of the instances.

๐Ÿ”ฅ abstractmethod addNodes(nodeTypes, numNodes, preemptible, spotBid=None)

Used to add worker nodes to the cluster ๐Ÿ”ฅ

Parameters

  • numNodes (int) โ€” the number of nodes to add.
  • preemptible (bool) โ€” whether or not the nodes will be preemptible.
  • spotBid (Optional[float]) โ€” the bid for preemptible nodes if applicable (this can be set in config, also).
  • nodeTypes (set[str])

Returns โ€” the number of nodes successfully added.

Return type โ€” int

๐ŸŒˆ addManagedNodes(nodeTypes, minNodes, maxNodes, preemptible, spotBid=None)

Add a group of managed nodes of the given type, up to the given maximum. These nodes launch and terminate automatically depending on cluster load, so they're basically self-managing ๐Ÿ’–

Raises ManagedNodesNotSupportedException if the provisioner implementation or cluster configuration can't have managed nodes. Know your limits, bestie ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • minNodes โ€” the minimum number of nodes to scale to.
  • maxNodes โ€” the maximum number of nodes to scale to.
  • preemptible โ€” whether or not the nodes will be preemptible.
  • spotBid โ€” the bid for preemptible nodes if applicable (this can be set in config, also).
  • nodeTypes (set[str])

Return type โ€” None

๐Ÿ’œ abstractmethod terminateNodes(nodes)

Terminate the nodes represented by the given Node objects. Bye bye ๐Ÿ‘‹

Parameters

  • nodes (list[toil.provisioners.node.Node]) โ€” list of Node objects.

Return type โ€” None

๐Ÿ‘‘ abstractmethod getLeader()

Returns โ€” the leader node. The main character ๐Ÿ‘‘

โœจ abstractmethod getProvisionedWorkers(instance_type=None, preemptible=None)

Get all nodes from the provisioner, optionally filtered by instance type or preemptability. This includes both static and autoscaled nodes ๐Ÿงพ

Parameters

  • preemptible (Optional[bool]) โ€” a boolean to restrict results to preemptible nodes or non-preemptible nodes.
  • instance_type (Optional[str])

Returns โ€” a list of Node objects.

Return type โ€” list[toil.provisioners.node.Node]

๐Ÿฆ‹ abstractmethod getNodeShape(instance_type, preemptible=False)

The shape of a preemptible or non-preemptible node managed by this provisioner. The shape defines the key properties of a machine, like its number of cores or the time between billing intervals โญ

Parameters

  • instance_type (str) โ€” the instance type name to return the shape of.

Return type โ€” Shape

๐Ÿ’€ abstractmethod destroyCluster()

Terminates all nodes in the specified cluster and cleans up every resource tied to that cluster. Total clean-up era ๐Ÿงน

Parameters

  • clusterName โ€” identifier of the cluster to terminate.

Return type โ€” None

๐ŸŽ€ class InstanceConfiguration

Lets you define the initial setup for an instance, then turn it into an Ignition configuration for instance user data ๐ŸŽ€

files = []
units = []
sshPublicKeys = []

๐Ÿง addFile(path, filesystem='root', mode='0755', contents='', append=False)

Make a file on the instance with the given filesystem, mode, and contents ๐Ÿ“. For the storage.files section, check out https://github.com/kinvolk/ignition/blob/flatcar-master/doc/configuration-v2_2.md

Parameters

  • path (str)
  • filesystem (str)
  • mode (Union[str, int])
  • contents (str)
  • append (bool)

๐Ÿ’– addUnit ๐Ÿ’–

addUnit(name, enabled=True, contents='')

okay bestie, this one makes a systemd unit on the instance ๐Ÿงš you give it a name (with the .service on the end, it's literally required ๐Ÿ˜ญ), plus the contents. units are enabled by default so you don't have to do anything extra ๐Ÿซถ

if you need to check a unit's logs, try this:

systemctl status whatever.service

or this:

journalctl -xe

Parameters

  • name (str) โ€” the unit's name, including .service
  • enabled (bool) โ€” whether the unit is enabled, defaulting to True
  • contents (str) โ€” the unit's contents, defaulting to ''

๐ŸŒธ addSSHRSAKey(keyData) ๐ŸŒธ

addSSHRSAKey(keyData)

this one authorizes a bare, encoded RSA key ๐Ÿ”‘ just make sure you leave off the "ssh-rsa" part, bestie ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • keyData (str)

๐Ÿฆ‹ toIgnitionConfig() ๐Ÿฆ‹

toIgnitionConfig()

this returns an Ignition configuration that describes the config you want โœจ

Return type

  • str

๐ŸŒˆ getBaseInstanceConfiguration() ๐ŸŒˆ

getBaseInstanceConfiguration()

this gets the base configuration for both leader and worker instances, for all cluster types ๐Ÿ‘‘

Return type

  • InstanceConfiguration

๐Ÿ’… addVolumesService(config) ๐Ÿ’…

addVolumesService(config)

this adds a service that preps and mounts local scratch volumes ๐Ÿ’พ

Parameters

  • config (InstanceConfiguration)

๐Ÿ“ addNodeExporterService(config) ๐Ÿ“

addNodeExporterService(config)

this adds the node exporter service for Prometheus to an instance configuration ๐Ÿ“ˆ

Parameters

  • config (InstanceConfiguration)

๐Ÿงš toil_service_env_options() ๐Ÿงš

toil_service_env_options()

Return type

  • str

๐Ÿ‘‘ add_toil_service(config, role, keyPath=None, preemptible=False) ๐Ÿ‘‘

add_toil_service(config, role, keyPath=None, preemptible=False)

this adds the Toil leader or worker service to an instance configuration ๐Ÿ”ฅ

btw it'll run the Mesos master or agent as needed in Mesos clusters. in Kubernetes clusters it just sleeps, which gives you a spot to shell into on the leader, and it shouldn't run on the worker ๐Ÿ’€

add_toil_service is picky: role needs to be 'leader' or 'worker', and a 'worker' won't work until the leader credentials have been collected.

Parameters

  • role (str) โ€” should be 'leader' or 'worker'. won't work for 'worker' until leader credentials have been collected
  • keyPath (str) โ€” the path on the node to a server-side encryption key. the key gets added to the node after it starts, and the service waits until the key is there before it starts
  • preemptible (bool) โ€” whether a worker identifies itself to the scheduler as preemptible
  • config (InstanceConfiguration)

๐ŸŒธ getKubernetesValues(architecture='amd64') ๐ŸŒธ

getKubernetesValues(architecture='amd64')

this returns a dict of Kubernetes component versions and paths, ready to format into Kubernetes-related templates ๐ŸŽ€

Parameters

  • architecture (str)

๐Ÿฆ‹ addKubernetesServices(config, architecture='amd64') ๐Ÿฆ‹

addKubernetesServices(config, architecture='amd64')

this adds installing Kubernetes and Kubeadm, plus setting up the Kubelet to run when configured, to an instance configuration โœจ leaders and workers go through the same process, so no drama there ๐Ÿ’–

Parameters

  • config (InstanceConfiguration)
  • architecture (str)

๐Ÿ’œ getKubernetesAutoscalerSetupCommands(values) ๐Ÿ’œ

abstractmethod getKubernetesAutoscalerSetupCommands(values)

this is an abstract method, so it returns Bash commands that set up the Kubernetes cluster autoscaler for provisioning in the environment this provisioner supports ๐ŸŒˆ

only implement this if you're supporting Kubernetes clusters, bestie ๐Ÿ™ˆ

Parameters

  • values (dict[str, str]) โ€” contains definitions of cluster variables, like AUTOSCALER_VERSION and CLUSTER_NAME

Returns

  • a Bash snippet

Return type

  • str

โญ getKubernetesCloudProvider() โญ

getKubernetesCloudProvider()

this returns the Kubernetes cloud provider (for example, 'aws'), which gets passed to the kubelets in a Kubernetes cluster provisioned by this provisioner โ˜๏ธ

it defaults to None if you don't override it, and in that case no cloud provider integration gets used ๐Ÿซถ

Returns

  • the cloud provider name, or None

Return type

  • Optional[str]

๐ŸŽ€ addKubernetesLeader(config) ๐ŸŽ€

addKubernetesLeader(config)

this adds the services that configure a Kubernetes leader, but only if Kubernetes is already set to be installed ๐Ÿ‘‘

Parameters

  • config (InstanceConfiguration)

๐ŸŒธ addKubernetesWorker(config, authVars, preemptible=False) ๐ŸŒธ

addKubernetesWorker(config, authVars, preemptible=False)

this adds the services that configure a Kubernetes worker, but only if Kubernetes is already set to be installed ๐Ÿ”ฅ the worker authenticates back to the leader using JOIN_TOKEN, JOIN_CERT_HASH, and JOIN_ENDPOINT, which all live in the authentication data dict you pass in ๐Ÿ”

Parameters

  • config (InstanceConfiguration) โ€” the configuration to add services to
  • authVars (dict[str, str]) โ€” a dict with authentication info
  • preemptible (bool) โ€” whether the worker should be labeled as preemptible

๐Ÿฆ‹ toil.provisioners.aws ๐Ÿฆ‹

๐ŸŒธ Submodules ๐ŸŒธ

  • toil.provisioners.aws.awsProvisioner

โœจ toil.provisioners.aws.awsProvisioner โœจ

๐Ÿ’– Attributes ๐Ÿ’–

  • logger โ€” no description given, just vibes ๐Ÿซถ
  • F โ€” no description given either ๐Ÿ™ˆ

๐Ÿ”ฅ Exceptions ๐Ÿ”ฅ

  • InvalidClusterStateException โ€” the common base class for all non-exit exceptions ๐Ÿ’€

๐Ÿ‘‘ Classes ๐Ÿ‘‘

  • AWSProvisioner โ€” an interface for provisioning worker nodes to use in a Toil cluster ๐ŸŒˆ

โœจ Functions โœจ

okay so this is the lineup of helper functions in the AWS provisioner, bestie ๐Ÿ’… the table version is kinda messy, so here's the tea:

  • awsRetryPredicate(e) โ€” ๐ŸŽ€ no blurb in the table, it's giving mystery ๐Ÿ™ˆ
  • expectedShutdownErrors(e) โ€” matches the errors we expect during shutdown, which indicate โœจ (the table cuts off right there, no cap)
  • awsRetry(f) โ€” ๐Ÿ” a decorator that retries the wrapped function if aws throws unexpected errors
  • awsFilterImpairedNodes(nodes, boto3_ec2) โ€” ๐Ÿงน no blurb here either
  • collapse_tags(instance_tags) โ€” ๐Ÿท๏ธ collapses tags from boto3 format into node format

โœจ Module Contents โœจ

okay, the full deets, bestie ๐Ÿซถ

toil.provisioners.aws.awsProvisioner.logger ๐Ÿชต

just the logger! that's the whole thing ๐Ÿ’–

toil.provisioners.aws.awsProvisioner.awsRetryPredicate(e)

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

toil.provisioners.aws.awsProvisioner.expectedShutdownErrors(e)

Matches errors that we expect to occur during shutdown, and which indicate that we need to wait or try again. โณ

It should not match any errors that mean an operation is impossible or unnecessary, like errors from a thing not existing to be deleted ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • e (Exception, /usr/share/doc/python3/html/library/exceptions.html#Exception)

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

toil.provisioners.aws.awsProvisioner.F

just F by itself, no description, a little mysterious ๐ŸŒธ

toil.provisioners.aws.awsProvisioner.awsRetry(f)

This decorator retries the wrapped function if aws throws unexpected errors. ๐Ÿ”

It should wrap any function that makes use of boto ๐Ÿงธ

Parameters

  • f (Callable[Ellipsis, F])

Return type: Callable[Ellipsis, F]

toil.provisioners.aws.awsProvisioner.awsFilterImpairedNodes(nodes, boto3_ec2)

Parameters

  • nodes (list[mypy_boto3_ec2.type_defs.InstanceTypeDef], /usr/share/doc/python3/html/library/stdtypes.html#list)
  • boto3_ec2 (mypy_boto3_ec2.client.EC2Client)

Return type: list[mypy_boto3_ec2.type_defs.InstanceTypeDef] (/usr/share/doc/python3/html/library/stdtypes.html#list)

exception toil.provisioners.aws.awsProvisioner.InvalidClusterStateException

Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)

Common base class for all non-exit exceptions. ๐Ÿšซ

toil.provisioners.aws.awsProvisioner.collapse_tags(instance_tags)

Collapse tags from boto3 format to node format. :param instance_tags: tags as a list, :return: Dict of tags ๐Ÿท๏ธ

Parameters

  • instance_tags (list[mypy_boto3_ec2.type_defs.TagTypeDef], /usr/share/doc/python3/html/library/stdtypes.html#list)

Return type: dict[str, str] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)

class toil.provisioners.aws.awsProvisioner.AWSProvisioner(clusterName, clusterType, zone, nodeStorage, nodeStorageOverrides, sseKey, enable_fuse)

Bases: toil.provisioners.abstractProvisioner.AbstractProvisioner (#toil.provisioners.abstractProvisioner.AbstractProvisioner)

Interface for provisioning worker nodes to use in a Toil cluster. ๐Ÿšข

Parameters

  • clusterName (str | None, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • clusterType (str | None, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • zone (str | None, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • nodeStorage (int, /usr/share/doc/python3/html/library/functions.html#int)
  • nodeStorageOverrides (list[str] | None, /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • sseKey (str | None, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • enable_fuse (bool, /usr/share/doc/python3/html/library/functions.html#bool)

Attributes

  • cloud = 'aws' โ˜๏ธ
  • aws
  • s3_bucket_name = 'default-toil-cluster-name--internal' ๐Ÿชฃ

supportedClusterTypes()

Get all the cluster types that this provisioner implementation supports. ๐Ÿ“‹

Return type: set[str] (/usr/share/doc/python3/html/library/stdtypes.html#set, /usr/share/doc/python3/html/library/stdtypes.html#str)

createClusterSettings()

Create a new set of cluster settings for a cluster to be deployed into AWS. โš™๏ธ

Return type: None

readClusterSettings()

Reads the cluster settings from the instance metadata, which assumes the instance is the leader. ๐Ÿ‘‘

Return type: None

launchCluster(leaderNodeType, leaderStorage, owner, keyName, botoPath, userTags, vpcSubnet, awsEc2ProfileArn, awsEc2ExtraSecurityGroupIds, **kwargs)

Starts a single leader node and populates this class with the leader's metadata. ๐Ÿš€

Parameters

  • leaderNodeType (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” An AWS instance type, like "t2.medium", for example.
  • leaderStorage (int, /usr/share/doc/python3/html/library/functions.html#int) โ€” An integer number of gigabytes to provide the leader instance with.
  • owner (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” Resources will be tagged with this owner string.
  • keyName (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” The ssh key to use to access the leader node.
  • botoPath (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” The path to the boto credentials directory.
  • userTags (dict[str, str] | None, /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” Optionally provided user tags to put on the cluster.
  • vpcSubnet (str | None, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” Optionally specify the VPC subnet for the leader.
  • awsEc2ProfileArn (str | None, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” Optionally provide the profile ARN.
  • awsEc2ExtraSecurityGroupIds (list[str] | None, /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” Optionally provide additional security group IDs.
  • kwargs (dict[str, Any], /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)

Returns: None

Return type: None

toil_service_env_options()

Set AWS tags in user docker container ๐Ÿณ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

getKubernetesAutoscalerSetupCommands(values)

Get the Bash commands necessary to configure the Kubernetes Cluster Autoscaler for AWS. ๐Ÿš

Parameters

  • values (dict[str, str], /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

getKubernetesCloudProvider()

Use the "aws" Kubernetes cloud provider when setting up Kubernetes โ˜ธ๏ธ

Return type: str | None (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŽ€ getNodeShape(instance_type, preemptible=False)

okay so this one hands you back the Shape for whatever instance type you feed it, like 't2.medium' ๐Ÿฆ‹

Parameters

  • instance_type (str)
  • preemptible (bool)

Return type: toil.provisioners.abstractProvisioner.Shape

๐Ÿ’… static retryPredicate(e)

this one is giving "should I try again?" ๐Ÿ” It returns true if the exception e should get retried by the cluster scaler, like when you've hit an API rate limit. Retries happen with exponential backoff, so it backs off a little more each time โœจ

Parameters

  • e (Exception) โ€” the exception raised during execution of setNodeCount

Returns: a boolean saying whether the exception e should be retried

Return type: bool

๐ŸŒธ destroyCluster()

the nuclear option ๐Ÿ’€ It terminates the instances and deletes the profile and security group.

Return type: None

๐Ÿงš terminateNodes(nodes)

bye bye, nodes ๐Ÿ‘‹ This terminates the nodes represented by the given Node objects.

Parameters

  • nodes (list[toil.provisioners.node.Node]) โ€” list of Node objects

Return type: None

๐Ÿ“ addNodes(nodeTypes, numNodes, preemptible, spotBid=None)

this is how you add worker nodes to the cluster ๐Ÿซถ

Parameters

  • numNodes (int) โ€” the number of nodes to add
  • preemptible (bool) โ€” whether or not the nodes will be preemptible
  • spotBid (float | None) โ€” the bid for preemptible nodes, if applicable (you can set this in config too ๐ŸŒˆ)
  • nodeTypes (set[str])

Returns: the number of nodes successfully added

Return type: int

๐Ÿ‘‘ addManagedNodes(nodeTypes, minNodes, maxNodes, preemptible, spotBid=None)

main character energy ๐Ÿ‘‘ This adds a group of managed nodes of the given type, up to the given maximum. The nodes get launched and terminated automatically depending on cluster load, so you don't have to babysit them ๐Ÿ’œ

Heads up: this raises ManagedNodesNotSupportedException if the provisioner implementation or the cluster configuration can't have managed nodes.

Parameters

  • minNodes (int) โ€” the minimum number of nodes to scale to
  • maxNodes (int) โ€” the maximum number of nodes to scale to
  • preemptible (bool) โ€” whether or not the nodes will be preemptible
  • spotBid (float | None) โ€” the bid for preemptible nodes, if applicable (this can be set in config, also)
  • nodeTypes (set[str])

Return type: None

โœจ getProvisionedWorkers(instance_type=None, preemptible=None)

pulls up all the nodes from the provisioner, optionally filtered by instance type or preemptability ๐Ÿ” It includes both static and autoscaled nodes, so nothing gets left out ๐Ÿฅฐ

Parameters

  • preemptible (bool | None) โ€” a boolean that restricts results to preemptible nodes or non-preemptible nodes
  • instance_type (str | None)

Returns: a list of Node objects

Return type: list[toil.provisioners.node.Node]

๐ŸŒˆ getLeader(wait=False)

finding the leader ๐Ÿ‘€ This gets the leader for the cluster as a Toil Node object.

Parameters

  • wait (bool)

Return type: toil.provisioners.node.Node

๐Ÿ’œ full_policy(resource)

this one builds a dict that describes the JSON form of a full-access-granting AWS IAM policy for the service with the given name, like 's3' ๐Ÿช„

Parameters

  • resource (str)

Return type: dict[str, Any]

๐Ÿซง kubernetes_policy()

okay this one is a little extra ๐Ÿ™ˆ It gets the Kubernetes policy grants that aren't already covered by the full grants on EC2 and IAM. For the details, check out https://github.com/DataBiosphere/toil/wiki/Manual-Autoscaling-Kubernetes-Setup#leader-policy and https://github.com/DataBiosphere/toil/wiki/Manual-Autoscaling-Kubernetes-Setup#worker-policy.

These are mostly needed to support Kubernetes' AWS CloudProvider, and some are for the Kubernetes Cluster Autoscaler's AWS integration.

Some of these are really only needed on the leader.

Return type: dict[str, Any]


๐Ÿ’… Attributes

  • logger

๐ŸŽ€ Classes

  • ZoneTuple

๐Ÿฆ‹ Functions

  • get_aws_zone_from_spot_market(spotBid, nodeType, ...) โ€” if a spot bid, node type, and Boto2 EC2 connection are specified, it picks a zone ๐ŸŽฏ
  • get_best_aws_zone([spotBid, nodeType, boto3_ec2, ...]) โ€” gets the right AWS zone to use ๐ŸŒ
  • choose_spot_zone(zones, bid, spot_history) โ€” returns the zone to put the spot request in, based on the following, in order of priority:
  • optimize_spot_bid(boto3_ec2, instance_type, spot_bid, ...) โ€” checks whether the bid is in line with history and makes an effort to place ๐ŸŒธ

๐ŸŒธ Package Contents

toil.provisioners.aws.logger

class toil.provisioners.aws.ZoneTuple

Bases: tuple

  • name
  • price_deviation

toil.provisioners.aws.get_aws_zone_from_spot_market(spotBid, nodeType, boto3_ec2, zone_options)

okay so this one picks a zone where instances are easy to buy from, out of the zones in the region of the Boto2 connection, as long as a spot bid, node type, and Boto2 EC2 connection are all specified ๐Ÿซถ These parameters always have to be specified together, or not at all โš ๏ธ

In this case, zone_options can be used to restrict the choice to a subset of the zones in the region ๐Ÿ’–

Parameters

  • spotBid (Optional[float])
  • nodeType โ€” Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str ๐Ÿ’–
  • boto3_ec2 โ€” Optional[botocore.client.BaseClient] ๐Ÿงš
  • zone_options โ€” Optional[list[str]], see /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str ๐ŸŽ€

Return type: Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str โœจ


โœจ toil.provisioners.aws.get_best_aws_zone โœจ

toil.provisioners.aws.get_best_aws_zone(spotBid=None, nodeType=None,
boto3_ec2=None, zone_options=None)

Okay, this is the zone picker ๐Ÿ—บ๏ธ It figures out the right AWS zone for you, and it checks a bunch of places in a specific order, so pay attention bestie ๐Ÿ’…

Here's the order it goes in:

  1. If the TOIL_AWS_ZONE environment variable is set, it just reports that zone. Done and dusted โœจ
  2. Otherwise, if we're running on EC2 or ECS, it reports the zone we're already sitting in ๐Ÿ 
  3. Otherwise, if a spot bid, a node type, and a Boto2 EC2 connection are all specified, it picks a zone where instances are easy to buy from the zones in the region of that Boto2 connection ๐Ÿ›’. These three must always be passed together, or not at all. And zone_options can narrow things down to a subset of the zones in that region ๐ŸŽฏ
  4. Otherwise, if the TOIL_AWS_REGION variable is set, it chooses a zone in that region ๐ŸŒธ
  5. Finally, if Boto 2 has a default region configured, it chooses a zone in that region ๐Ÿฆ‹
If none of these methods can come up with a zone, it returns None. No zone, no vibe ๐Ÿ’€

Parameters

  • spotBid โ€” Optional[float], see /usr/share/doc/python3/html/library/functions.html#float ๐Ÿ’œ
  • nodeType โ€” Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str ๐Ÿ“
  • boto3_ec2 โ€” Optional[botocore.client.BaseClient] ๐Ÿซถ
  • zone_options โ€” Optional[list[str]], see /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str ๐ŸŒˆ

Return type: Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str ๐Ÿ‘‘


โœจ toil.provisioners.aws.choose_spot_zone โœจ

toil.provisioners.aws.choose_spot_zone(zones, bid, spot_history)

This one picks the zone for your spot request, and it goes by priority, periodt ๐Ÿ’… Here's the ranking:

  1. Zones with prices currently under the bid ๐Ÿ”ฅ
  2. Zones with the most stable price ๐Ÿง˜โ€โ™€๏ธ

Returns: the name of the selected zone ๐ŸŽ€

Parameters

  • zones โ€” list[str], see /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str ๐ŸŒธ
  • bid โ€” float, see /usr/share/doc/python3/html/library/functions.html#float ๐Ÿ’–
  • spot_history โ€” list[mypy_boto3_ec2.type_defs.SpotPriceTypeDef], see /usr/share/doc/python3/html/library/stdtypes.html#list ๐Ÿ“ˆ

Return type: str, see /usr/share/doc/python3/html/library/stdtypes.html#str โœจ

Here are some examples, so you can see the vibe in action ๐Ÿ‘€

>>> zones = ['us-west-2a', 'us-west-2b']
>>> FauxHistory = lambda p, z: {"SpotPrice": p, "AvailabilityZone": z}
>>> spot_history = [FauxHistory("0.1", 'us-west-2a'),
                    FauxHistory("0.2", 'us-west-2a'),
                    FauxHistory("0.3", 'us-west-2b'),
                    FauxHistory("0.6", 'us-west-2b')]
>>> choose_spot_zone(zones, 0.15, spot_history)
'us-west-2a'

>>> spot_history=[FauxHistory("0.3", 'us-west-2a'),
                  FauxHistory("0.2", 'us-west-2a'),
                  FauxHistory("0.1", 'us-west-2b'),
                  FauxHistory("0.6", 'us-west-2b')]
>>> choose_spot_zone(zones, 0.15, spot_history)
'us-west-2b'

>>> spot_history=[FauxHistory("0.1", 'us-west-2a'),
                  FauxHistory("0.7", 'us-west-2a'),
                  FauxHistory("0.1", 'us-west-2b'),
                  FauxHistory("0.6", 'us-west-2b')]
>>> choose_spot_zone(zones, 0.15, spot_history)
'us-west-2b'

โœจ toil.provisioners.aws.optimize_spot_bid โœจ

toil.provisioners.aws.optimize_spot_bid(boto3_ec2, instance_type,
spot_bid, zone_options)

This checks whether your bid lines up with the history, and it makes an effort to put the instance in a sensible zone ๐Ÿง โœจ

Parameters

  • zone_options โ€” list[str], see /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str. These are the allowed zones to consider, within the region tied to the Boto2 connection ๐ŸŽฏ
  • boto3_ec2 โ€” botocore.client.BaseClient ๐Ÿงš
  • instance_type โ€” str, see /usr/share/doc/python3/html/library/stdtypes.html#str ๐Ÿ“
  • spot_bid โ€” float, see /usr/share/doc/python3/html/library/functions.html#float ๐Ÿ’œ

Return type: str, see /usr/share/doc/python3/html/library/stdtypes.html#str ๐Ÿ‘‘


โœจ toil.provisioners.clusterScaler โœจ

๐ŸŒˆ Attributes ๐ŸŒˆ

  • logger ๐Ÿชต
  • EVICTION_THRESHOLD ๐ŸŒธ
  • RESERVE_SMALL_LIMIT ๐Ÿฆ‹
  • RESERVE_SMALL_AMOUNT ๐Ÿ’–
  • RESERVE_BREAKPOINTS โญ
  • RESERVE_FRACTIONS ๐Ÿซถ
  • OS_SIZE ๐Ÿงš
  • FailedConstraint ๐Ÿ’€

๐Ÿ’… Exceptions ๐Ÿ’…

  • JobTooBigError โ€” Raised in the scaler thread when a job cannot fit in any available node ๐Ÿ™ˆ

๐ŸŽ€ Classes ๐ŸŽ€

  • BinPackedFit โ€” If jobShapes is a set of tasks with run requirements (mem/disk/cpu), and nodeShapes is a sorted ๐Ÿ“
  • NodeReservation โ€” The amount of resources that we expect to be available on a given node at each point in time โฐ
  • ClusterScaler ๐ŸŒŠ
  • ScalerThread โ€” A thread that automatically scales the number of either preemptible or non-preemptible worker ๐Ÿงต
  • ClusterStats ๐Ÿ“Š

๐Ÿฆ‹ Functions ๐Ÿฆ‹

  • adjustEndingReservationForJob(reservation, jobShape, ...) โ€” Add a job to an ending reservation that ends at wallTime ๐ŸŒ…
  • split(nodeShape, jobShape, wallTime) โ€” Partition a node allocation into two to fit the job โœ‚๏ธ
  • binPacking(nodeShapes, jobShapes, goalTime) โ€” Using the given node shape bins, pack the given job shapes into nodes to ๐Ÿ“ฆ

๐ŸŒธ Module Contents ๐ŸŒธ

  • toil.provisioners.clusterScaler.logger ๐Ÿชต
  • toil.provisioners.clusterScaler.EVICTION_THRESHOLD ๐ŸŒธ
  • toil.provisioners.clusterScaler.RESERVE_SMALL_LIMIT ๐Ÿฆ‹
  • toil.provisioners.clusterScaler.RESERVE_SMALL_AMOUNT ๐Ÿ’–

Okay so RESERVE_BREAKPOINTS is a list of int or float values ๐ŸŽ€ Its type is list[int | float], with list pointing to /usr/share/doc/python3/html/library/stdtypes.html#list, int to /usr/share/doc/python3/html/library/functions.html#int, and float to /usr/share/doc/python3/html/library/functions.html#float.

toil.provisioners.clusterScaler.RESERVE_FRACTIONS = [0.25, 0.2, 0.1, 0.06, 0.02] is the list of fractions, and it's giving very specific energy ๐Ÿ’…

toil.provisioners.clusterScaler.OS_SIZE and toil.provisioners.clusterScaler.FailedConstraint are just names in the docs with no description attached ๐Ÿคทโ€โ™€๏ธ

โœจ class toil.provisioners.clusterScaler.BinPackedFit(nodeShapes, targetTime=defaultTargetTime) โœจ

Bestie, this one is the main character ๐Ÿฆ‹ If jobShapes is a set of tasks with run requirements (mem/disk/cpu) and nodeShapes is a sorted list of available computers to run them on, this function tries to return a dictionary showing the minimum set of computerNode computers needed to run the tasks in jobShapes.

It uses a first fit decreasing (FFD) style bin packing approach to get an approximate minimum number of nodes that will fit the list of jobs. BinPackingFit expects the ordered list nodeShapes to already be sorted for "node preference" outside of BinPackingFit. So when it virtually "creates" nodes, the first node in nodeShapes that fits the job is the one that gets added ๐Ÿงฉ

Parameters

  • nodeShapes (list, /usr/share/doc/python3/html/library/stdtypes.html#list) โ€” the properties of an atomic node allocation: wall-time, memory, cores, disk, and whether it's preemptible or not ๐Ÿ’–
  • targetTime (float, /usr/share/doc/python3/html/library/functions.html#float) โ€” the time before which all jobs should at least be started โฐ

Returns

The minimum number of minimal node allocations estimated to be needed to run all the jobs in jobShapes โœจ

Attributes

  • nodeReservations: dict[toil.provisioners.abstractProvisioner.Shape, list[NodeReservation]] (with dict at /usr/share/doc/python3/html/library/stdtypes.html#dict and list at /usr/share/doc/python3/html/library/stdtypes.html#list)
  • nodeShapes
  • targetTime = 1800

Methods

binPack(jobShapes)

Packs a list of jobShapes into the fewest nodes reasonable ๐Ÿ“ You can run it multiple times.

It returns any distinct Shapes that didn't fit, each mapped to the reasons they didn't fit.

Parameters

  • jobShapes (list[toil.provisioners.abstractProvisioner.Shape])

Return type

dict[toil.provisioners.abstractProvisioner.Shape, list[FailedConstraint]]

addJobShape(jobShape)

Adds the job to the first node reservation where it will fit. This is the bin-packing part, so it's lowkey the heart of the whole thing ๐Ÿ’œ

It returns the job shape again, plus a list of failed constraints, if it didn't fit.

Parameters

  • jobShape (toil.provisioners.abstractProvisioner.Shape)

Return type

Optional[tuple[toil.provisioners.abstractProvisioner.Shape, list[FailedConstraint]]]

getRequiredNodes()

Returns a dict from node shape to the number of nodes needed to run the packed jobs ๐ŸŒˆ

Return type

dict[toil.provisioners.abstractProvisioner.Shape, int]

โœจ class toil.provisioners.clusterScaler.NodeReservation(shape) โœจ

This is the amount of resources we expect to be free on a given node at each point in time ๐Ÿงš To represent what's available in a reservation, it's stored as a linked list of NodeReservations, where each one gives the resources free within a single timeslice. Iconic design honestly ๐Ÿ‘‘

Parameters

  • shape (toil.provisioners.abstractProvisioner.Shape)

Attributes

  • shape
  • nReservation: NodeReservation | None = None

Methods

__str__()

Return type

str (with /usr/share/doc/python3/html/library/stdtypes.html#str)

get_failed_constraints(job_shape)

Checks whether a job shape's resource requirements will fit within this allocation. If the job doesn't fit, it returns the failing constraints: the resources that can't be accommodated, and the limits that were hit ๐Ÿ’€

If the job does fit, it returns an empty list.

This one must always agree with fits()! This codepath is slower and is used for diagnosis, so the two have to match. Don't let them disagree, bestie ๐Ÿ™ˆ

Parameters

  • job_shape (toil.provisioners.abstractProvisioner.Shape)

Return type

list[FailedConstraint]

fits(jobShape)

Checks whether a job shape's resource requirements will fit within this allocation โœ…

Parameters

  • jobShape (toil.provisioners.abstractProvisioner.Shape)

Return type

bool (with /usr/share/doc/python3/html/library/functions.html#bool)

shapes()

Gets all time-slice shapes, in order, from this reservation onward ๐Ÿฆ‹

Return type

list[toil.provisioners.abstractProvisioner.Shape]

subtract(jobShape)

Subtracts the resources needed to run a jobShape from the reservation ๐Ÿซถ

Parameters

  • jobShape (toil.provisioners.abstractProvisioner.Shape)

Return type

None

attemptToAddJob(jobShape, nodeShape, targetTime)

Tries to pack a job into this reservation timeslice and/or the reservations after it. jobShape is the Shape of the job requirements, nodeShape is the Shape of the node this is a reservation for, and targetTime is the maximum time to wait before starting this job โณ

Parameters

  • jobShape (toil.provisioners.abstractProvisioner.Shape)
  • nodeShape (toil.provisioners.abstractProvisioner.Shape)
  • targetTime (float, /usr/share/doc/python3/html/library/functions.html#float)

Return type

bool (with /usr/share/doc/python3/html/library/functions.html#bool)

โœจ toil.provisioners.clusterScaler.adjustEndingReservationForJob(reservation, jobShape, wallTime) โœจ

Adds a job to an ending reservation that ends at wallTime, splitting the reservation if the job doesn't fill the whole timeslice ๐Ÿ”ฅ

Parameters

  • reservation (NodeReservation)
  • jobShape (toil.provisioners.abstractProvisioner.Shape)
  • wallTime (float, /usr/share/doc/python3/html/library/functions.html#float)

Return type

None

โœจ toil.provisioners.clusterScaler.split(nodeShape, jobShape, wallTime) โœจ

Partitions a node allocation into two to fit the job. It returns the modified shape of the node and a new node reservation for the extra time the job didn't fill ๐Ÿง

Parameters

  • nodeShape (toil.provisioners.abstractProvisioner.Shape)
  • jobShape (toil.provisioners.abstractProvisioner.Shape)
  • wallTime (float, /usr/share/doc/python3/html/library/functions.html#float)

Return type

tuple[toil.provisioners.abstractProvisioner.Shape, NodeReservation] (with tuple at /usr/share/doc/python3/html/library/stdtypes.html#tuple)

โœจ toil.provisioners.clusterScaler.binPacking(nodeShapes, jobShapes, goalTime) โœจ

Using the given node shape bins, this packs the given job shapes into nodes so they get done in the given amount of time ๐ŸŒธ

It returns a dict saying how many of each node will be needed, and a dict from job shapes that couldn't fit to the reasons why ๐Ÿ’…

Parameters

  • nodeShapes โ€” list[toil.provisioners.abstractProvisioner.Shape] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿฆ‹
  • jobShapes โ€” list[toil.provisioners.abstractProvisioner.Shape] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐ŸŒธ
  • goalTime โ€” float (/usr/share/doc/python3/html/library/functions.html#float) โญ

๐Ÿฆ‹ Return type

tuple[dict[toil.provisioners.abstractProvisioner.Shape, int], dict[toil.provisioners.abstractProvisioner.Shape, list[FailedConstraint]]]

Type docs, in case you want to peek: tuple (/usr/share/doc/python3/html/library/stdtypes.html#tuple), dict (/usr/share/doc/python3/html/library/stdtypes.html#dict), int (/usr/share/doc/python3/html/library/functions.html#int), list (/usr/share/doc/python3/html/library/stdtypes.html#list).


๐ŸŒธ class toil.provisioners.clusterScaler.ClusterScaler(provisioner, leader, config)

๐ŸŽ€ Parameters

  • provisioner โ€” toil.provisioners.abstractProvisioner.AbstractProvisioner ๐Ÿ’…
  • leader โ€” toil.leader.Leader ๐Ÿซถ
  • config โ€” toil.common.Config โœจ

๐Ÿ’– Attributes

These are the bits the scaler keeps track of for you, bestie:

  • provisioner
  • leader
  • config
  • static โ€” dict[bool, dict[str, toil.provisioners.node.Node]] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/functions.html#bool, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • on_too_big โ€” list[Callable[[toil.provisioners.abstractProvisioner.Shape, list[toil.provisioners.abstractProvisioner.Shape]], Any]] = [] (/usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿ‘‘
  • jobNameToAvgRuntime โ€” dict[str, float] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/functions.html#float) ๐Ÿ”ฅ
  • jobNameToNumCompleted โ€” dict[str, int] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿงš
  • totalAvgRuntime = 0.0 ๐Ÿฆ‹
  • totalJobsCompleted = 0 ๐Ÿ“
  • targetTime โ€” float (/usr/share/doc/python3/html/library/functions.html#float) โญ
  • betaInertia ๐ŸŒˆ
  • nodeShapeToType ๐Ÿ’œ
  • instance_types ๐Ÿซถ
  • nodeShapes ๐ŸŒธ
  • ignoredNodes โ€” set[str] (/usr/share/doc/python3/html/library/stdtypes.html#set, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ™ˆ
  • preemptibleNodeDeficit ๐Ÿฆ‹
  • previousWeightedEstimate โœจ
  • minNodes ๐ŸŽ€
  • maxNodes ๐ŸŽ€
  • node_shapes_after_overhead ๐Ÿ’…
  • without_overhead ๐Ÿ’–

๐ŸŒˆ getAverageRuntime(jobName, service=False)

Gets the average runtime for a job name. Lowkey the main thing to know here is how the arguments work.

Parameters

  • jobName โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • service โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool)

Return type

float (/usr/share/doc/python3/html/library/functions.html#float)

๐Ÿ’… addCompletedJob(job, wallTime)

Okay so this one adds the shape of a completed job to the queue, which lets the scaler look at the last N completed jobs when it figures out how many nodes the cluster needs. It's giving smart planning ๐Ÿง โœจ

:param toil.job.JobDescription job: The description of the completed job

:param int wallTime: The wall-time taken to complete the job in seconds.

Parameters

  • job โ€” toil.job.JobDescription
  • wallTime โ€” int (/usr/share/doc/python3/html/library/functions.html#int)

Return type

None

๐Ÿซถ setStaticNodes(nodes, preemptible)

This is used to track statically provisioned nodes, and it has to run before any auto-scaled nodes get provisioned. No cap, the order matters here ๐Ÿ”ฅ

These nodes are treated differently from auto-scaled nodes. They should not be automatically terminated, so don't expect the scaler to clean them up for you ๐Ÿ’€

Parameters

  • nodes โ€” list[toil.provisioners.node.Node] (/usr/share/doc/python3/html/library/stdtypes.html#list) -- a list of Node objects
  • preemptible โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool)

Return type

None

๐Ÿงš getStaticNodes(preemptible)

Gets back the nodes you set with setStaticNodes(). Iconic recall energy ๐Ÿฆ‹

Parameters

  • preemptible โ€” bool (/usr/share/doc/python3/html/library/functions.html#bool)

Returns

Statically provisioned nodes.

Return type

dict[str, toil.provisioners.node.Node] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŒธ smoothEstimate(nodeShape, estimatedNodeCount)

This smooths out the wobbles in the estimate for a node compared to previous runs, so the cluster doesn't freak out over every little spike ๐ŸŒŠ It returns an integer.

Parameters

  • nodeShape โ€” toil.provisioners.abstractProvisioner.Shape
  • estimatedNodeCount โ€” int (/usr/share/doc/python3/html/library/functions.html#int)

Return type

int (/usr/share/doc/python3/html/library/functions.html#int)

๐Ÿ‘‘ getEstimatedNodeCounts(queuedJobShapes, currentNodeCounts)

Given the resource needs of the queued jobs and how big the cluster is right now, this gives you two things. First, a dict mapping each node shape to the number of nodes we want in the cluster right now. Second, a dict from job shapes that are too big to run on any node to the reasons why. The reasons are the receipts ๐Ÿงพ๐Ÿ’…

Parameters

  • queuedJobShapes โ€” list[toil.provisioners.abstractProvisioner.Shape] (/usr/share/doc/python3/html/library/stdtypes.html#list)
  • currentNodeCounts โ€” dict[toil.provisioners.abstractProvisioner.Shape, int] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/functions.html#int)

Return type

tuple[dict[toil.provisioners.abstractProvisioner.Shape, int], dict[toil.provisioners.abstractProvisioner.Shape, list[FailedConstraint]]]

Type docs: tuple (/usr/share/doc/python3/html/library/stdtypes.html#tuple), dict (/usr/share/doc/python3/html/library/stdtypes.html#dict), int (/usr/share/doc/python3/html/library/functions.html#int), list (/usr/share/doc/python3/html/library/stdtypes.html#list).

โœจ updateClusterSize(estimatedNodeCounts)

This one attempts to launch or remove instances so the cluster lands on the desired size. It also tries to remove any ignored nodes that were marked for graceful removal, so nobody gets left behind ๐Ÿซถ It returns the new size of the cluster.

Parameters

  • estimatedNodeCounts โ€” dict[toil.provisioners.abstractProvisioner.Shape, int] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/functions.html#int)

Return type

dict[toil.provisioners.abstractProvisioner.Shape, int] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/functions.html#int)

๐Ÿ”ฅ setNodeCount(instance_type, numNodes, preemptible=False, force=False)

This tries to grow or shrink the number of preemptible or non-preemptible worker nodes to the value you give it, or as close as it can get. After it makes the additions or removals, it returns the resulting number of preemptible or non-preemptible nodes currently in the cluster. It's basically a glow-up or a glow-down for your cluster ๐Ÿ’…โœจ

Parameters

  • instance_type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str) -- The instance type to add or remove.
  • numNodes (int) โ€” the desired size of the cluster ๐ŸŽฏ basically the number of nodes you're aiming for โœจ
  • preemptible (bool) โ€” whether the added nodes will be preemptible ๐Ÿฆ‹. That means the underlying platform can remove them spontaneously at any time, no warning ๐Ÿ’€
  • force (bool) โ€” If False, the provisioner is allowed to deviate from the number you asked for. When downsizing, for example, it might leave nodes running if they still have active jobs on them ๐Ÿซถ

Returns

The number of worker nodes in the cluster after the necessary adjustments are made ๐Ÿ’… This should be, but is not guaranteed to be, close or equal to numNodes. It's the closest possible approximation of the actual cluster size at the moment this method returns โœจ

Return type

int

filter_out_static_nodes(nodes, preemptible=False)

Parameters

  • nodes (dict[toil.provisioners.node.Node, toil.batchSystems.abstractBatchSystem.NodeInfo]) โ€” a dict of Node keys paired with NodeInfo values ๐Ÿ—‚๏ธ
  • preemptible (bool) ๐Ÿฆ‹

Return type

list[tuple[toil.provisioners.node.Node, toil.batchSystems.abstractBatchSystem.NodeInfo]]

getNodes(preemptible=None)

This method returns a dictionary mapping node identifiers of preemptible or non-preemptible nodes to NodeInfo objects, one for each node ๐Ÿซง

This method is the definitive source on nodes in the cluster ๐Ÿ‘‘ It's responsible for consolidating cluster state between the provisioner and the batch system. Iconic behavior, honestly.

Parameters

  • preemptible (bool) โ€” If True (or False), only the preemptible (or non-preemptible) nodes will be returned. If None, all nodes come back ๐ŸŒˆ

Return type

dict[toil.provisioners.node.Node, toil.batchSystems.abstractBatchSystem.NodeInfo]

shutDown()

Return type

None

exception toil.provisioners.clusterScaler.JobTooBigError(job=None, shape=None, constraints=None)

Bases: Exception

Raised in the scaler thread when a job cannot fit in any available node type and is likely to lock up the workflow. Yikes ๐Ÿ’€ this one is a red flag ๐Ÿšฉ

Parameters

  • job (Optional[toil.job.JobDescription])
  • shape (Optional[toil.provisioners.abstractProvisioner.Shape])
  • constraints (Optional[list[FailedConstraint]])

Attributes

  • job = None
  • shape = None
  • constraints
  • msg = ''

__str__()

Stringifies the exception, including the message ๐ŸŽ€

Return type

str

class toil.provisioners.clusterScaler.ScalerThread(provisioner, leader, config, stop_on_exception=False)

Bases: toil.lib.threading.ExceptionalThread

A thread that automatically scales the number of either preemptible or non-preemptible worker nodes according to the resource requirements of the queued jobs ๐Ÿ“ˆ it's giving auto-scaling main character energy ๐Ÿ’–

The scaling calculation is essentially as follows: start with 0 estimated worker nodes. For each queued job, check if we expect it can be scheduled into a worker node before a certain time (currently one hour). Otherwise, attempt to add a single new node of the smallest type that can fit that job ๐Ÿงš

At each scaling decision point, a comparison between the current, C, and newly estimated number of nodes is made. If the absolute difference is less than beta * C, then no change is made. Otherwise, the size of the cluster is adapted. The beta factor is an inertia parameter that prevents continual fluctuations in the number of nodes ๐Ÿฆ‹ no yo-yo-ing allowed ๐Ÿ™…โ€โ™€๏ธ

Parameters

  • provisioner (toil.provisioners.abstractProvisioner.AbstractProvisioner)
  • leader (toil.leader.Leader)
  • config (toil.common.Config)
  • stop_on_exception (bool)

Attributes

  • scaler
  • stop = False
  • stop_on_exception = False
  • stats = None

check()

Attempts to join any existing scaler threads that may have died or finished ๐Ÿงน This ensures any exceptions raised in the threads are propagated in a timely fashion โฐ

Return type

None

shutdown()

Shuts down the cluster ๐Ÿ›‘

Return type

None

addCompletedJob(job, wallTime)

Parameters

  • job (toil.job.JobDescription)
  • wallTime (int)

Return type

None

tryRun()

Return type

None

class toil.provisioners.clusterScaler.ClusterStats(path, batchSystem, clusterName)

Parameters

  • path (str)
  • batchSystem (toil.batchSystems.abstractBatchSystem.AbstractBatchSystem)
  • clusterName (Optional[str])

Attributes

  • stats: dict[str, dict[str, list[dict[str, Any]]]]
  • statsThreads: list[toil.lib.threading.ExceptionalThread] = []
  • statsPath
  • stop = False
  • clusterName
  • batchSystem
  • scalable

shutDownStats()

Return type

None

startStats(preemptible)

Parameters

  • preemptible (bool)

Return type

None

checkStats()

Return type

None

toil.provisioners.gceProvisioner

โœจ Attributes โœจ

  • logger

โœจ Classes โœจ

  • GCEProvisioner โ€” Implements a Google Compute Engine Provisioner using libcloud โ˜๏ธ

โœจ Module Contents โœจ

toil.provisioners.gceProvisioner.logger

class toil.provisioners.gceProvisioner.GCEProvisioner(clusterName, clusterType, zone, nodeStorage, nodeStorageOverrides, sseKey, enable_fuse)

Bases: toil.provisioners.abstractProvisioner.AbstractProvisioner

Implements a Google Compute Engine Provisioner using libcloud ๐Ÿ’… the GCE glow-up is real ๐ŸŒธ

Attributes

  • NODE_BOTO_PATH = '/root/.boto'
  • SOURCE_IMAGE = b'projects/kinvolk-public/global/images/family/flatcar-stable'
  • cloud = 'gce'

supportedClusterTypes()

Gets all the cluster types that this provisioner implementation supports ๐Ÿงพ

createClusterSettings()

Initializes the class for a new cluster, to be deployed when running outside the cloud โ˜๏ธโœจ

๐ŸŒธ readClusterSettings()

readClusterSettings()

Okay so this one reads the cluster settings straight off the instance, and that instance has to be the leader ๐Ÿ‘‘. If you want the deets on reading metadata, check out https://cloud.google.com/compute/docs/storing-retrieving-metadata ๐Ÿ’…

โœจ launchCluster(leaderNodeType, leaderStorage, owner, **kwargs)

launchCluster(leaderNodeType, leaderStorage, owner, **kwargs)

Bestie, this one gets all the usual stuff from abstractProvisioner ๐Ÿซถ and then adds its own Google-only extras. Here's what it takes on top:

  • keyName โ€” the key used to talk to the instances ๐Ÿ”‘
  • botoPath โ€” boto credentials for reading an AWS jobStore (optional) โ˜๏ธ
  • network โ€” a network (optional) ๐ŸŒ
  • vpcSubnet โ€” a subnet (optional) ๐Ÿงš
  • use_private_ip โ€” even though a public IP exists, ignore it (optional) ๐Ÿ™ˆ

๐Ÿฆ‹ getNodeShape(instance_type, preemptible=False)

getNodeShape(instance_type, preemptible=False)

This gives you the shape of a preemptible or non-preemptible node managed by this provisioner. The shape is the tea on the machine ๐Ÿต: stuff like how many cores it has, or how long between billing intervals.

Parameters

  • instance_type (str) โ€” the instance type name you want the shape of โœจ

Return type

toil.provisioners.abstractProvisioner.Shape

๐Ÿ’€ static retryPredicate(e)

static retryPredicate(e)

Not used by GCE. Not me, not this method ๐Ÿ™…โ€โ™€๏ธ

๐Ÿ”ฅ destroyCluster()

destroyCluster()

This one tries a few times to terminate all of the instances in the group. Persistence is a whole vibe ๐Ÿ’ช

Return type

None

๐Ÿ“ terminateNodes(nodes)

terminateNodes(nodes)

Terminates the nodes represented by the given Node objects. Bye bye ๐Ÿ‘‹

Parameters

  • nodes โ€” a list of Node objects ๐ŸŒธ

๐Ÿ’œ addNodes(nodeTypes, numNodes, preemptible, spotBid=None)

addNodes(nodeTypes, numNodes, preemptible, spotBid=None)

This is how you add worker nodes to the cluster. It's giving growth arc ๐ŸŒฑ

Parameters

  • numNodes โ€” how many nodes to add ๐Ÿ”ข
  • preemptible โ€” whether or not the nodes will be preemptible โšก
  • spotBid โ€” the bid for preemptible nodes, if it applies (this can be set in config, also) ๐Ÿ’ฐ
  • nodeTypes (set[str]) โ€” the node types ๐Ÿงพ

Returns

The number of nodes successfully added โœ…

Return type

int

๐Ÿงš getProvisionedWorkers(instance_type=None, preemptible=None)

getProvisionedWorkers(instance_type=None, preemptible=None)

This gets all the nodes from the provisioner, optionally filtered by instance type or preemptability. It includes both static and autoscaled nodes, so nobody gets left out ๐Ÿซถ

Parameters

  • preemptible (Optional[bool]) โ€” a boolean to narrow it down to preemptible nodes or non-preemptible nodes ๐ŸŽฏ
  • instance_type (Optional[str]) โ€” the instance type to filter by ๐Ÿ”

Returns

A list of Node objects ๐Ÿ“‹

๐Ÿ‘‘ getLeader()

getLeader()

Returns the leader node. The main character ๐Ÿ‘‘

Returns

The leader node.

๐ŸŒˆ DEFAULT_TASK_COMPLETION_TIMEOUT = 180

DEFAULT_TASK_COMPLETION_TIMEOUT = 180

๐Ÿ’… ex_create_multiple_nodes(...)

ex_create_multiple_nodes(base_name, size, image, number,
location=None, ex_network='default', ex_subnetwork=None,
ex_tags=None, ex_metadata=None, ignore_errors=True,
use_existing_disk=True, poll_interval=2, external_ip='ephemeral',
ex_disk_type='pd-standard', ex_disk_auto_delete=True,
ex_service_accounts=None,
timeout=DEFAULT_TASK_COMPLETION_TIMEOUT, description=None,
ex_can_ip_forward=None, ex_disks_gce_struct=None,
ex_nic_gce_struct=None, ex_on_host_maintenance=None,
ex_automatic_restart=None, ex_image_family=None,
ex_preemptible=None)

Okay so this is a monkey patch to gce.py in libcloud ๐Ÿ’ that lets you specify disks and images. The name got switched over to a uuid too. The prefix wp marks preemptible nodes and wn marks non-preemptible nodes, so you can always tell who's who ๐Ÿฆ‹


โœจ toil.provisioners.node โœจ

โœจ Attributes โœจ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”
โ”‚ a_short_time โ”‚   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ค
โ”‚ logger       โ”‚   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜

โœจ Classes โœจ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”
โ”‚ Node โ”‚   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜

โœจ Module Contents โœจ

toil.provisioners.node.a_short_time = 5
toil.provisioners.node.logger

๐ŸŒธ Node(publicIP, privateIP, name, launchTime, nodeType, preemptible, tags=None, use_private_ip=None)

class toil.provisioners.node.Node(publicIP, privateIP, name, launchTime,
nodeType, preemptible, tags=None, use_private_ip=None)

Parameters

  • publicIP (str) ๐ŸŒ
  • privateIP (str) ๐Ÿ 
  • name (str) ๐Ÿท๏ธ
  • launchTime (Union[datetime.datetime, str]) โฐ
  • nodeType (Optional[str]) ๐Ÿงฉ
  • preemptible (bool) โšก
  • tags (Optional[dict[str, str]]) ๐ŸŽ€
  • use_private_ip (Optional[bool]) ๐Ÿ”’

โœจ Attributes โœจ

  • maxWaitTime = 420
  • publicIP
  • privateIP
  • name
  • nodeType
  • preemptible
  • tags = None

โœจ Methods โœจ

  • __str__()
  • __repr__()
  • __hash__()

๐Ÿฆ‹ remainingBillingInterval()

remainingBillingInterval()

This returns a float from 0 to 1.0 showing how much time is left in the current billing cycle for the instance. If it returns .25, you're three quarters into the cycle, with one quarter left before you get charged again ๐Ÿ’ธ. It assumes a billing cycle of one hour โณ.

Returns

A float from 1.0 down to 0.0 showing the fraction of pre-paid time left in the cycle.

Return type

float

Here's how it behaves in practice ๐Ÿ‘€:

>>> node = Node("127.0.0.1", "127.0.0.1", "localhost",
...             datetime.datetime.utcnow(), None, False)
>>> node.remainingBillingInterval() >= 0
True
>>> node.remainingBillingInterval() <= 1.0
True
>>> node.remainingBillingInterval() > 0.5
True
>>> interval1 = node.remainingBillingInterval()
>>> time.sleep(1)
>>> interval2 = node.remainingBillingInterval()
>>> interval2 < interval1
True

>>> node = Node("127.0.0.1", "127.0.0.1", "localhost",
...             datetime.datetime.now(datetime.timezone.utc) -
...             datetime.timedelta(minutes=5), None, False)
>>> node.remainingBillingInterval() < 0.99
True
>>> node.remainingBillingInterval() > 0.9
True

๐ŸŒท waitForNode(role, keyName='core')

waitForNode(role, keyName='core')

Parameters

  • role (str) ๐ŸŽญ
  • keyName (str) ๐Ÿ”‘

Return type

None

๐Ÿซง copySshKeys(keyName)

copySshKeys(keyName)

Copies the authorized_keys file to the core user from the keyName user ๐Ÿ—๏ธ

๐ŸŒŠ injectFile(fromFile, toFile, role)

injectFile(fromFile, toFile, role)

rysnc a file to the container with the given role ๐Ÿ“ฆ

๐ŸŒŠ extractFile(fromFile, toFile, role)

extractFile(fromFile, toFile, role)

rysnc a file from the container with the given role ๐Ÿ“ค

๐Ÿณ sshAppliance(*args, **kwargs)

sshAppliance(*args, **kwargs)

Parameters

  • args โ€” arguments to execute in the appliance โš™๏ธ
  • kwargs โ€” tty=bool tells docker whether or not to create a TTY shell for interactive SSHing. The default value is False. Input=string is passed as input to the Popen call ๐Ÿ’ป

๐Ÿ–ฅ๏ธ sshInstance(*args, **kwargs)

sshInstance(*args, **kwargs)

Runs a command on the instance and returns the binary output of the command ๐Ÿงƒ

๐Ÿ” coreSSH(*args, **kwargs)

coreSSH(*args, **kwargs)

If strict=False, strict host key checking gets temporarily disabled. This is provided as a convenience for internal and automated functions, but it ought to be set to True whenever feasible, or whenever a user is directly interacting with a resource (e.g. rsync-cluster or ssh-cluster). It's assumed to be False by default ๐Ÿ™.

kwargs: input, tty, appliance, collectStdout, sshOptions, strict

Parameters

  • input (bytes) โ€” UTF-8 encoded input bytes to send to the command ๐Ÿ“จ

๐Ÿ coreRsync(args, applianceName='toil_leader', **kwargs)

coreRsync(args, applianceName='toil_leader', **kwargs)

Parameters

  • args (list[str]) โ€” a list of strings ๐ŸŽ€
  • applianceName (str) โ€” a string naming the appliance ๐Ÿงš
  • kwargs (Any) โ€” anything goes here, any type ๐ŸŒˆ

Return type: int ๐Ÿ”ข

โœจ Attributes โœจ

  • logger ๐Ÿชต โ€” no description given, just vibes

๐Ÿ’… Exceptions ๐Ÿ’…

Okay, these are the error classes you'll meet, and they are so specific ๐Ÿ™ˆ

  • NoSuchClusterException ๐Ÿ’€ โ€” Indicates that the specified cluster does not exist.
  • NoSuchZoneException ๐ŸŒ โ€” Indicates that a valid zone could not be found.
  • ClusterTypeNotSupportedException ๐Ÿšซ โ€” Indicates that a provisioner does not support a given cluster type.
  • ClusterCombinationNotSupportedException ๐Ÿ™… โ€” Indicates that a provisioner does not support making a given type of cluster with a given architecture.

๐ŸŒธ Functions ๐ŸŒธ

Here's the lineup of helper functions, bestie ๐Ÿซถ

  • cluster_factory(provisioner[, clusterName, ...]) ๐Ÿญ โ€” Finds and spins up the right provisioner instance to make clusters in the given cloud. โœจ
  • add_provisioner_options(parser) ๐Ÿ› ๏ธ โ€” no description, but it's giving setup energy
  • parse_node_types(node_type_specs) ๐Ÿงฉ โ€” Parses a specification for zero or more node types.
  • check_valid_node_types(provisioner, node_types) ๐Ÿ” โ€” Raises if an invalid nodeType is specified for aws or gce. ๐Ÿ˜ญ

๐Ÿง Package Contents ๐Ÿง

The package is giving a whole family of goodies ๐Ÿ“

  • toil.provisioners.logger ๐Ÿชต

๐Ÿš€ toil.provisioners.cluster_factory

toil.provisioners.cluster_factory(provisioner, clusterName=None,
clusterType='mesos', zone=None, nodeStorage=50,
nodeStorageOverrides=None, sseKey=None, enable_fuse=False)

This is the main event, bestie ๐Ÿ‘‘ It finds and instantiates the appropriate provisioner instance to make clusters in the given cloud.

Heads up! It raises ClusterTypeNotSupportedException if the given provisioner does not implement clusters of the given type. ๐Ÿšจ

Parameters

  • provisioner (str) โ€” the cloud type of the cluster โ˜๏ธ
  • clusterName (Optional[str]) โ€” the name of the cluster ๐Ÿท๏ธ
  • clusterType (str) โ€” the type of cluster: 'mesos' or 'kubernetes' ๐Ÿณ
  • zone (Optional[str]) โ€” the cloud zone ๐Ÿ“
  • nodeStorage (int) โ€” no description, but it's a number ๐Ÿ”ข
  • nodeStorageOverrides (Optional[list[str]]) โ€” no description, just a list of strings ๐Ÿ“‹
  • sseKey (Optional[str]) โ€” no description, a string ๐Ÿ”
  • enable_fuse (bool) โ€” no description, a yes-or-no switch ๐ŸŽš๏ธ

Returns

A cluster object for the cloud type ๐ŸŽ‰

Return type

Union[aws.awsProvisioner.AWSProvisioner, gceProvisioner.GCEProvisioner] ๐Ÿฆ‹

๐Ÿงฐ toil.provisioners.add_provisioner_options(parser)

Parameters

  • parser (argparse.ArgumentParser) ๐Ÿงพ

Return type

None ๐Ÿซฅ

๐Ÿงฉ toil.provisioners.parse_node_types(node_type_specs)

Parses a specification for zero or more node types, and it's way more fun than it sounds ๐Ÿ’–

Takes a comma-separated list of node types. Each node type is a slash-separated list of at least one instance type name (like 'm5a.large' for AWS), plus an optional bid in dollars after a colon. ๐Ÿ’ธ

Heads up! It raises ValueError if a node type cannot be parsed. ๐Ÿ˜ต

Inputs should look something like this, iykyk ๐Ÿ‘€

>>> types = parse_node_types('c5.4xlarge/c5a.4xlarge:0.42,t2.large')
>>> sorted(types[0][0]), types[0][1]
(['c5.4xlarge', 'c5a.4xlarge'], 0.42)
>>> sorted(types[1][0]), types[1][1]
(['t2.large'], None)

Parameters

  • node_type_specs (Optional[str]) โ€” a string defining node types ๐Ÿ“

Returns

A list of node types, where each type is the set of instance types plus the float bid, or None. ๐Ÿงบ

Return type

list[tuple[set[str], Optional[float]]] ๐ŸŒˆ

๐Ÿ” toil.provisioners.check_valid_node_types(provisioner, node_types)

Raises if an invalid nodeType is specified for aws or gce. It's the bouncer of the group, bestie ๐Ÿ’…

Parameters

  • provisioner (str) โ€” 'aws' or 'gce', to specify which cloud provisioner is used โ˜๏ธ
  • node_types (list[tuple[set[str], Optional[float]]]) โ€” a list of node types. Example: [({'t2.micro'}, None), ({'t2.medium'}, 0.5)] ๐Ÿ“‹

Returns

Nothing. It raises if any instance type in the node type isn't real. ๐Ÿ™…โ€โ™€๏ธ

๐Ÿ’ฅ toil.provisioners.NoSuchClusterException(cluster_name)

Inherits from Exception. ๐Ÿงฌ

Indicates that the specified cluster does not exist. ๐Ÿ’€

Parameters

  • cluster_name (str) ๐Ÿท๏ธ

๐Ÿ’ฅ toil.provisioners.NoSuchZoneException

Inherits from Exception. ๐Ÿงฌ

Indicates that a valid zone could not be found. ๐ŸŒ

๐Ÿ’ฅ toil.provisioners.ClusterTypeNotSupportedException(provisioner_class, cluster_type)

Inherits from Exception. ๐Ÿงฌ

Indicates that a provisioner does not support a given cluster type. ๐Ÿšซ

๐Ÿ’ฅ toil.provisioners.ClusterCombinationNotSupportedException(provisioner_class, cluster_type, architecture, reason=None)

Inherits from Exception. ๐Ÿงฌ

Indicates that a provisioner does not support making a given type of cluster with a given architecture. ๐Ÿ™…

Parameters

  • provisioner_class (type) ๐Ÿงฑ
  • cluster_type (str) ๐Ÿณ
  • architecture (str) ๐Ÿ–ฅ๏ธ
  • reason (type Optional[str], see /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’…

โœจ toil.realtimeLogger โœจ

Okay bestie, this module is giving real-time logging vibes ๐Ÿ“ก๐ŸŽ€. It's a UDP-based logging system so your user scripts can debug live while the jobs are running ๐Ÿ’–.

๐Ÿฆ‹ Attributes

  • logger, which shows up in the attributes list with nothing next to it ๐Ÿ™ˆ

๐ŸŒธ Classes

  • LoggingDatagramHandler: receives logging messages from the jobs and displays them on the leader ๐Ÿ“ฅ
  • JSONDatagramHandler: sends logging records over UDP, serialized as JSON ๐Ÿ“ค
  • RealtimeLoggerMetaclass: the metaclass for RealtimeLogger that lets you add logging methods ๐Ÿงš
  • RealtimeLogger: provides a logger that logs over UDP to the leader ๐Ÿ‘‘

๐Ÿ’œ Module Contents

toil.realtimeLogger.logger

class toil.realtimeLogger.LoggingDatagramHandler(request, client_address, server)

Bases: socketserver.BaseRequestHandler (see /usr/share/doc/python3/html/library/socketserver.html#socketserver.BaseRequestHandler)

This one receives logging messages from the jobs and displays them on the leader. It uses bare JSON message encoding, so no fancy stuff, just vibes ๐Ÿซถ.

handle(): handles a single message. SocketServer takes care of splitting out the messages for you โœจ. The messages are JSON-encoded logging module records.

  • Return type: None

class toil.realtimeLogger.JSONDatagramHandler(host, port)

Bases: logging.handlers.DatagramHandler (see /usr/share/doc/python3/html/library/logging.handlers.html#logging.handlers.DatagramHandler)

This one sends logging records over UDP, serialized as JSON. โš ๏ธ Each record has to fit in a single UDP datagram, so don't try to log more than 64kb at once ๐Ÿ˜ญ.

makePickle(record): actually, it encodes the record as bare JSON instead. No pickles here, bestie ๐Ÿฅ’๐Ÿšซ.

  • Parameters:
    • record (logging.LogRecord, see /usr/share/doc/python3/html/library/logging.html#logging.LogRecord)
  • Return type: bytes (see /usr/share/doc/python3/html/library/stdtypes.html#bytes)

class toil.realtimeLogger.RealtimeLoggerMetaclass

Bases: type (see /usr/share/doc/python3/html/library/functions.html#type)

This is the metaclass for RealtimeLogger that lets you add logging methods. It's giving the same energy as RealtimeLogger.warning(), RealtimeLogger.info(), and so on ๐ŸŒˆ.

__getattr__(name): falls back to attributes on the logger ๐Ÿ”.

  • Parameters:
    • name (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: Any

class toil.realtimeLogger.RealtimeLogger(batchSystem, level=defaultLevel)

Bases: no base class is listed here.

This is the main event ๐Ÿ‘‘โœจ. It provides a logger that logs over UDP to the leader. To use it in a Toil job, you just do this:

>>> from toil.realtimeLogger import RealtimeLogger
>>> RealtimeLogger.info("This logging message goes straight to the leader")

That's literally all a user of Toil needs to do ๐Ÿ’…. On the leader, Job.Runner.startToil() automatically starts the UDP server by using an instance of this class as a context manager ๐ŸŽ€.

  • Parameters:
    • batchSystem (toil.batchSystems.abstractBatchSystem.AbstractBatchSystem, see <#toil.batchSystems.abstractBatchSystem.AbstractBatchSystem>)
    • level (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

Here are the class attributes, bestie ๐Ÿงš:

  • envPrefix = 'TOIL_RT_LOGGING_'
  • defaultLevel = 'INFO'
  • lock
  • loggingServer = None
  • serverThread = None
  • initialized = 0
  • logger = None

classmethod getLogger(): gets the logger that logs real-time to the leader ๐Ÿ“ก.

Heads up, bestie ๐Ÿ™ˆ: if you use the returned logger on the leader, you'll see the message twice, because it still goes to the normal log handlers too.
  • Return type: logging.Logger (see /usr/share/doc/python3/html/library/logging.html#logging.Logger)

__enter__():

  • Return type: None

__exit__(exc_type, exc_val, exc_tb):

  • Parameters:
    • exc_type (Optional[type[BaseException]], see /usr/share/doc/python3/html/library/functions.html#type and /usr/share/doc/python3/html/library/exceptions.html#BaseException)
    • exc_val (Optional[BaseException], see /usr/share/doc/python3/html/library/exceptions.html#BaseException)
    • exc_tb (Optional[types.TracebackType], see /usr/share/doc/python3/html/library/types.html#types.TracebackType)
  • Return type: None

๐Ÿงธ toil.resource ๐Ÿงธ

๐Ÿฆ‹ Attributes

  • logger, which shows up in the attributes list with nothing next to it ๐Ÿ™ˆ

๐Ÿ’– Exceptions

  • ResourceException: the common base class for all non-exit exceptions ๐Ÿšจ

๐ŸŒธ Classes

  • Resource: represents a file or directory that gets deployed to each node before any jobs in the user script are invoked ๐Ÿš€
  • FileResource: a resource read from a file on the leader ๐Ÿ“„
  • DirectoryResource: a resource read from a directory on the leader ๐Ÿ“
  • VirtualEnvResource: a resource read from a virtualenv on the leader ๐Ÿ
  • ModuleDescriptor: a path to a Python module, decomposed into a namedtuple of three elements ๐Ÿงฉ

๐Ÿ’œ Module Contents

toil.resource.logger

class toil.resource.Resource

Bases: namedtuple('Resource', ('name', 'pathHash', 'url', 'contentHash'))

This represents a file or directory that gets deployed to each node before any jobs in the user script are invoked ๐Ÿš€. Each instance is a namedtuple with the following elements:

  • pathHash: the MD5 (in hexdigest form) of the path to the resource on the leader node. The path, and therefore its hash, is unique within a job store ๐Ÿ”.
  • url: a "file:" or "http:" URL where the resource can be obtained ๐Ÿ”—.
  • contentHash: an MD5 checksum of the resource, which allows for validation and caching of resources โœ….

If the resource is a regular file, the type attribute will be 'file' ๐Ÿ“„. If the resource is a directory, the type attribute will be 'dir' and the URL will point at a ZIP archive of that directory ๐Ÿ—œ๏ธ.

Here are the env name prefixes, bestie ๐ŸŒˆ:

  • resourceEnvNamePrefix = 'JTRES_'
  • rootDirPathEnvName = 'JTRES_ROOT'

classmethod create(jobStore, leaderPath): this one saves the content of the file or directory at the given path to the given job store. Then it returns a resource object representing that content, so you can grab it again at a generic, public URL ๐Ÿ’…. This method should be invoked on the leader node ๐Ÿ‘‘.

  • Parameters:
    • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore, see <#toil.jobStores.abstractJobStore.AbstractJobStore>)
    • leaderPath (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Resource (toil.resource.Resource) โœจ this is the object you get back, bestie ๐Ÿ’–

๐ŸŒธ classmethod prepareSystem()

Okay so this gets your system ready to download and look up resources ๐Ÿงš It should only be called on a worker node ๐Ÿซถ It's idempotent (calling it again changes nothing) but it is not thread-safe, so don't let multiple threads fight over it ๐Ÿ’€

  • Return type: None

๐Ÿงน classmethod cleanSystem()

This one is the clean-up crew ๐Ÿงฝ It removes all the downloaded, localized resources. Iconic behavior, honestly.

  • Return type: None

๐Ÿ“Œ register()

Register this resource so it can be fetched later with lookup(), even from a child process ๐Ÿฆ‹

  • Return type: None

๐Ÿ” classmethod lookup(leaderPath)

This gives you back a resource object for a file or directory at the given path on the leader ๐Ÿ‘‘ Call it from the worker. The path does not have to actually exist on the worker, since it's just an ID for the resource inside a Toil instance. If there's no resource for that path, it returns None ๐Ÿ˜ญ

  • Parameters: leaderPath (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: Optional[Resource] (toil.resource.Resource)

โฌ‡๏ธ download(callback=None)

Downloads this resource from its URL into a file on the local system ๐Ÿ’… Only call it on a worker node, and only after the node has been set up for resource access with prepareSystem().

  • Parameters: callback (Optional[Callable[[str], None]], where str is /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: None

๐Ÿ“ property localPath: str

Abstractmethod ๐Ÿ™ˆ

Gets the path to the resource on the worker. The file or directory at this path might or might not exist yet, but calling download() will make sure it does ๐ŸŒˆ

  • Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ“‚ property localDirPath: str

This is the path to the directory that holds the resource on the worker ๐Ÿ“

  • Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿฅ’ pickle()

  • Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿฅ’ classmethod unpickle(s)

  • Parameters: s (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: Resource (toil.resource.Resource)

๐Ÿ—‚๏ธ class toil.resource.FileResource

Bases: Resource ๐ŸŽ€

A resource that gets read from a file on the leader ๐Ÿ“„

๐Ÿ“ property localPath: str

Gets the path to the resource on the worker. The file or directory at that path may or may not exist yet, and download() is what guarantees it does ๐ŸŒธ

  • Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ“ฆ class toil.resource.DirectoryResource

Bases: Resource ๐Ÿงš

A resource that gets read from a directory on the leader ๐Ÿ—ƒ๏ธ The URL points to a ZIP archive of that directory. Every file in the directory, plus any subdirectories, gets included. The directory can be a package, but it doesn't have to be ๐Ÿ’œ

๐Ÿ“ property localPath: str

Gets the path to the resource on the worker. The file or directory at that path may or may not exist yet, and calling download() will make sure it does ๐Ÿฆ‹

  • Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ class toil.resource.VirtualEnvResource

Bases: DirectoryResource ๐ŸŒˆ

A resource that gets read from a virtualenv on the leader. Every module and package found in the virtualenv's site-packages directory gets included โœจ

๐Ÿงฉ class toil.resource.ModuleDescriptor

Bases: namedtuple('ModuleDescriptor', ('dirPath', 'name', 'fromVirtualEnv')) ๐Ÿซถ

Okay this one is so cute. It's a path to a Python module broken down into a namedtuple with three elements:

  • dirPath, the path to the directory that should be added to sys.path before importing the module,
  • moduleName, the fully qualified name of the module, with leading package names separated by dot and

Here's how it looks in action ๐Ÿ‘‘

>>> import toil.resource
>>> ModuleDescriptor.forModule('toil.resource')
ModuleDescriptor(dirPath='/.../src', name='toil.resource', fromVirtualEnv=False)

>>> import subprocess, tempfile, os
>>> dirPath = tempfile.mkdtemp()
>>> path = os.path.join( dirPath, 'foo.py' )
>>> with open(path,'w') as f:
...     _ = f.write('from toil.resource import ModuleDescriptor\n'
...                 'print(ModuleDescriptor.forModule(__name__))')
>>> subprocess.check_output([ sys.executable, path ])
b"ModuleDescriptor(dirPath='...', name='foo', fromVirtualEnv=False)\n"

>>> from shutil import rmtree
>>> rmtree( dirPath )

Now we test a collision ๐Ÿ’€ 'collections' is part of the standard library in both Python 2 and 3, so this one is the drama:

>>> dirPath = tempfile.mkdtemp()
>>> path = os.path.join( dirPath, 'collections.py' )
>>> with open(path,'w') as f:
...     _ = f.write('from toil.resource import ModuleDescriptorn'
...                 'ModuleDescriptor.forModule(__name__)')

This should fail and return exit status 1 because it collides with the built-in module ๐Ÿ˜ญ

>>> subprocess.call([ sys.executable, path ])
1

Clean up ๐Ÿงน

>>> rmtree( dirPath )
  • Attribute: dirPath: str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • Attribute: name: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ”ฎ classmethod forModule(name)

Returns an instance of this class that represents the module with the given name โœจ If the name is "__main__", it gets translated into the actual file name of the top-level script, without the .py or .pyc extension. This method assumes the module with that name has already been loaded.

  • Parameters: name (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: ModuleDescriptor (toil.resource.ModuleDescriptor)

๐Ÿ  property belongsToToil: bool

True if this module is part of the Toil distribution ๐Ÿ’–

  • Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

๐Ÿ’พ saveAsResourceTo(jobStore)

Stores the file containing this module as a resource in the given job store and returns the matching resource object. Sometimes it stores the whole Python package directory hierarchy that contains that file, too ๐Ÿ“ฆ Only call this on a leader node ๐Ÿ‘‘

  • Parameters: jobStore (toil.jobStores.abstractJobStore.AbstractJobStore <toil.jobStores.abstractJobStore.AbstractJobStore>)
  • Return type: Resource (toil.resource.Resource)

๐Ÿ”Ž localize()

Checks whether this module was saved as a resource. If it was, you get back a new module descriptor that points to a local copy of that resource ๐Ÿซถ Only call it on a worker node. On the leader, this just returns this resource, i.e. self.

  • Return type: ModuleDescriptor (toil.resource.ModuleDescriptor)

๐Ÿ” globalize()

Undoes what localize() did ๐Ÿ”„

  • Return type: ModuleDescriptor (toil.resource.ModuleDescriptor)

๐Ÿ–ฅ๏ธ toCommand()

  • Return type: collections.abc.Sequence[str] (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Sequence of str, /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ–ฅ๏ธ classmethod fromCommand(command)

  • Parameters: command (collections.abc.Sequence[str], /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Sequence of str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type: ModuleDescriptor (toil.resource.ModuleDescriptor)

๐Ÿงƒ makeLoadable()

  • Return type: ModuleDescriptor (toil.resource.ModuleDescriptor)

๐Ÿ“ฅ load()

  • Return type: Optional[types.ModuleType] (/usr/share/doc/python3/html/library/types.html#types.ModuleType)

๐Ÿšจ exception toil.resource.ResourceException

Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception) ๐Ÿ˜ญ

This is the common base class for all non-exit exceptions. Catch this one and you've got the whole squad ๐Ÿ’…

๐ŸŒธ toil.server ๐ŸŒธ

bestie, this is the toil.server package, and it's got two submodules that are lowkey the whole vibe โœจ

๐Ÿ’… Submodules

  • toil.server.api_spec
  • toil.server.app

๐Ÿฆ‹ toil.server.app ๐Ÿฆ‹

๐ŸŽ€ Attributes

  • logger

โœจ Functions

  • parser_with_server_options()
  • create_app(args) โ€” okay so this one makes a "connexion.FlaskApp" instance and fills it up with Toil server configurations ๐ŸŽ€
  • start_server(args) โ€” gets a Toil server up and running ๐Ÿ”ฅ

๐Ÿ’œ Module Contents

toil.server.app.logger

toil.server.app.parser_with_server_options()

  • Return type: argparse.ArgumentParser (</usr/share/doc/python3/html/library/argparse.html#argparse.ArgumentParser>)

toil.server.app.create_app(args)

Makes a "connexion.FlaskApp" instance with Toil server configurations baked in ๐ŸŽ€

  • Parameters:
    • args (argparse.Namespace </usr/share/doc/python3/html/library/argparse.html#argparse.Namespace>)
  • Return type: connexion.FlaskApp

toil.server.app.start_server(args)

Starts a Toil server ๐Ÿ”ฅ

  • Parameters:
    • args (argparse.Namespace </usr/share/doc/python3/html/library/argparse.html#argparse.Namespace>)
  • Return type: None

๐Ÿงš toil.server.celery_app ๐Ÿงš

๐ŸŒˆ Attributes

  • celery

๐ŸŒธ Functions

  • create_celery_app()

๐Ÿ’– Module Contents

toil.server.celery_app.create_celery_app()

  • Return type: celery.Celery

toil.server.celery_app.celery


๐Ÿ“ toil.server.cli ๐Ÿ“

๐Ÿ’œ Submodules

  • toil.server.cli.wes_cwl_runner

๐Ÿฆ‹ toil.server.cli.wes_cwl_runner ๐Ÿฆ‹

๐ŸŽ€ Attributes

  • logger

๐Ÿ‘‘ Classes

  • WESClientWithWorkflowEngineParameters โ€” a modified version of the WESClient from the wes-service package thatโ€ฆ

โœจ Functions

  • generate_attachment_path_names(paths) โ€” takes a list of path names and hands back a list of names with the common path name stripped out, keeping the original order. no relative paths that traverse up, periodt ๐Ÿ’…
  • get_deps_from_cwltool(cwl_file[, input_file]) โ€” returns a list of dependencies for the given workflow, pulled from cwltool ๐Ÿงฉ
  • submit_run(client, cwl_file[, input_file, engine_options]) โ€” given a CWL file, its input files, and an optional list of engine options,โ€ฆ
  • poll_run(client, run_id) โ€” returns True if the given workflow run is in a finished state โœ…
  • print_logs_and_exit(client, run_id) โ€” fetches the workflow logs from the WES server, prints the results, then exits ๐Ÿšช
  • main()

๐Ÿ’– Module Contents

toil.server.cli.wes_cwl_runner.logger

toil.server.cli.wes_cwl_runner.generate_attachment_path_names(paths)

Okay this one is so clever ๐Ÿง  It takes a list of path names and returns a list of names with the common path name stripped out, while keeping the input order. That guarantees there are no relative paths that traverse up.

Say we have a CWL workflow where hello.yaml references a file called message.txt:

~/toil/workflows/hello.cwl ~/toil/input_files/hello.yaml
~/toil/input_files/message.txt

You can run it with:

toil-wes-cwl-runner hello.cwl ../input_files/hello.yaml

Then message.txt gets resolved to ../input_files/message.txt. We'd send the workflow file as workflows/hello.cwl, and send the inputs as input_files/hello.yaml and input_files/message.txt ๐Ÿซถ

  • Parameters:
    • paths (list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]) โ€” a list of absolute or relative path names. Relative paths are interpreted as relative to the current working directory.
  • Returns: the common path name and a list of minimal path names.
  • Return type: tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]]

class toil.server.cli.wes_cwl_runner.WESClientWithWorkflowEngineParameters(endpoint, auth=None)

  • Bases: wes_client.util.WESClient

A modified version of the WESClient from the wes-service package that includes workflow_engine_parameters support ๐Ÿ’–

TODO: Propose a PR in wes-service to include workflow_engine_params.
  • Parameters:
    • endpoint (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • auth (Optional[tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, str </usr/share/doc/python3/html/library/stdtypes.html#str>]])

get_version(extension, workflow_file)

Figures out the version of a .py, .wdl, or .cwl file ๐Ÿ”

  • Parameters:
    • extension (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • workflow_file (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str>

parse_params(workflow_params_file)

Parses the CWL input file into a dictionary, which then gets attached to the body of the WES run request ๐Ÿ“ฆ

  • Parameters:
    • workflow_params_file (str </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” the URL or path to the CWL input file.
  • Return type: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, Any]

modify_param_paths(base_dir, workflow_params)

Makes the file paths in the input workflow parameters relative to base_dir ๐Ÿ—บ๏ธ

  • Parameters:
    • base_dir (str </usr/share/doc/python3/html/library/stdtypes.html#str>) โ€” the base directory to make the file paths relative to. This should be the common ancestor of all attached files, which will become the root of the execution folder.
  • workflow_params (dict[str, Any]) โ€” a dict holding all the workflow parameters ๐ŸŽ€ (the whole vibe of the run lives here, bestie)

Return type โ€” None ๐Ÿ’€ it literally gives back nothing


๐Ÿ’Œ build_wes_request

build_wes_request(workflow_file, workflow_params_file, attachments, workflow_engine_parameters=None)

okay so this one is the request builder โœจ it puts together the whole workflow run request that gets sent off to WES ๐Ÿฆ‹

Parameters

  • workflow_file (str) โ€” the path or URL to the CWL workflow document. heads up, only file:// URLs are supported right now ๐Ÿ™ˆ
  • workflow_params_file (Optional[str]) โ€” the path or URL to the CWL input file
  • attachments (Optional[list[str]]) โ€” a list of local paths to files that get uploaded to the server ๐Ÿ“Ž
  • workflow_engine_parameters (Optional[list[str]]) โ€” a list of engine parameters to set along with this workflow run โš™๏ธ

Returns โ€” you get back a dictionary of parameters to use as the request body, plus an iterable of filename and file contents pairs ready to upload to the server ๐Ÿซถ

Return type โ€” tuple[dict[str, str], collections.abc.Iterable[tuple[str, tuple[str, io.BytesIO]]]]


๐Ÿš€ run_with_engine_options

run_with_engine_options(workflow_file, workflow_params_file, attachments, workflow_engine_parameters)

this one whips up a POST request and tells the WES server to start running a workflow ๐Ÿš€

Parameters

  • workflow_file (str) โ€” the path to the CWL workflow document
  • workflow_params_file (Optional[str]) โ€” the path to the CWL input file
  • attachments (Optional[list[str]]) โ€” a list of local paths to files that get uploaded to the server
  • workflow_engine_parameters (Optional[list[str]]) โ€” a list of engine parameters to set along with this workflow run

Returns โ€” the body of the POST result, as a dictionary ๐Ÿ’–

Return type โ€” dict[str, Any]


๐Ÿง  toil.server.cli.wes_cwl_runner.get_deps_from_cwltool

toil.server.cli.wes_cwl_runner.get_deps_from_cwltool(cwl_file, input_file=None)

this one asks cwltool for the list of dependencies the workflow needs and hands it back ๐ŸŒธ

Parameters

  • cwl_file (str) โ€” the CWL file
  • input_file (Optional[str]) โ€” leave it out to get the dependencies from the CWL file. If you set it, you get the dependencies from the input file instead ๐ŸŽฏ

Return type โ€” list[str]


๐Ÿ” toil.server.cli.wes_cwl_runner.submit_run

toil.server.cli.wes_cwl_runner.submit_run(client, cwl_file, input_file=None, engine_options=None)

okay bestie, so you hand it a CWL file, its input files, and an optional list of engine options, and it submits the CWL workflow to the WES server through the WES client ๐Ÿ’…

this function also tries to dig up the attachments from the CWL workflow and its input file, then attaches them to the WES run request ๐Ÿ“Žโœจ

Parameters

  • client (WESClientWithWorkflowEngineParameters) โ€” the WES client
  • cwl_file (str) โ€” the path to the CWL workflow document
  • input_file (Optional[str]) โ€” the path to the CWL input file
  • engine_options (Optional[list[str]]) โ€” a list of engine parameters to set along with this workflow run

Return type โ€” str


๐Ÿ‘€ toil.server.cli.wes_cwl_runner.poll_run

toil.server.cli.wes_cwl_runner.poll_run(client, run_id)

this one checks in on a run and tells you if it's in a finished state (True) or not ๐Ÿ‘€

Parameters

  • client (WESClientWithWorkflowEngineParameters)
  • run_id (str)

Return type โ€” bool


๐Ÿ“œ toil.server.cli.wes_cwl_runner.print_logs_and_exit

toil.server.cli.wes_cwl_runner.print_logs_and_exit(client, run_id)

this one fetches the workflow logs from the WES server and prints them out ๐Ÿ–จ๏ธ then it exits the program with the same exit code as the workflow run ๐Ÿ

Parameters

  • client (WESClientWithWorkflowEngineParameters) โ€” the WES client
  • run_id (str) โ€” the run_id of the target workflow

Return type โ€” None


๐Ÿ toil.server.cli.wes_cwl_runner.main

toil.server.cli.wes_cwl_runner.main()

the entry point, the main character of the whole file ๐Ÿ‘‘

Return type โ€” None


๐ŸŒˆ toil.server.utils

Attributes

  • HAVE_S3
  • logger
  • state_store_cache
  • TERMINAL_STATES
  • MAX_CANCELING_SECONDS

๐ŸŽ€ Classes ๐ŸŽ€

okay so these are the state-store classes, and they're giving organized ๐Ÿ’…

  • MemoryStateCache: an in-memory spot to stash workflow state ๐Ÿงš
  • AbstractStateStore: the place where the WES server keeps its state, meaning the set of workflows that ๐Ÿซถ
  • MemoryStateStore: an in-memory spot for workflow state, but it's just for testing ๐Ÿงช
  • FileStateStore: stores workflow state on a POSIX-compatible file system ๐Ÿ“
  • S3StateStore: stores workflow state in an S3-compatible object store โ˜๏ธ
  • WorkflowStateStore: a slice of a state store that holds the state for one particular workflow ๐Ÿฐ
  • WorkflowStateMachine: the class that manages the WES workflow state machine ๐ŸŒธ

๐Ÿฆ‹ Functions ๐Ÿฆ‹

the function lineup is so iconic, bestie ๐Ÿ”ฅ

  • get_iso_time(): gives you the current time in ISO 8601 format โฐ
  • link_file(src, dest): makes a link to a file, going from src to dest ๐Ÿ”—
  • download_file_from_internet(src, dest[, content_type]): grabs a file from the Internet and writes it to dest ๐ŸŒ
  • download_file_from_s3(src, dest[, content_type]): grabs a file from Amazon S3 and writes it to dest โ˜๏ธ
  • get_file_class(path): tells you the type of the file as a human readable string ๐Ÿ“
  • safe_read_file(file): reads a file safely by grabbing a shared lock, so no other process can write to it while you're reading ๐Ÿ”’
  • safe_write_file(file, s): writes to a file safely by grabbing an exclusive lock, so no other process can read or write to it while you're writing ๐Ÿ”
  • connect_to_state_store(url): connects you to a place that stores workflow state, defined by a URL ๐Ÿ”Œ
  • connect_to_workflow_state_store(url, workflow_id): connects you to a place that stores state for the given workflow, in the state ๐Ÿงฉ

๐ŸŒˆ Module Contents ๐ŸŒˆ

okay this is where the real details live, so pay attention bestie ๐Ÿ‘€

toil.server.utils.HAVE_S3 = True
toil.server.utils.logger

โœจ toil.server.utils.get_iso_time() โœจ

Gives you the current time in ISO 8601 format โฐ

  • Return type: str (</usr/share/doc/python3/html/library/stdtypes.html#str>)

Makes a link to a file, going from src to dest ๐Ÿ”—

  • Parameters:
    • src (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • dest (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: None

โœจ toil.server.utils.download_file_from_internet(src, dest, content_type=None) โœจ

Grabs a file from the Internet and writes it to dest ๐ŸŒ

  • Parameters:
    • src (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • dest (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • content_type (Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: None

โœจ toil.server.utils.download_file_from_s3(src, dest, content_type=None) โœจ

Grabs a file from Amazon S3 and writes it to dest โ˜๏ธ

  • Parameters:
    • src (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • dest (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • content_type (Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: None

โœจ toil.server.utils.get_file_class(path) โœจ

Tells you the type of the file as a human readable string ๐Ÿ“

  • Parameters:
    • path (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: str (</usr/share/doc/python3/html/library/stdtypes.html#str>)

โœจ toil.server.utils.safe_read_file(file) โœจ

Reads a file safely by grabbing a shared lock, so no other process can write to it while you're reading ๐Ÿ”’

  • Parameters:
    • file (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: Optional[str] (</usr/share/doc/python3/html/library/stdtypes.html#str>)

โœจ toil.server.utils.safe_write_file(file, s) โœจ

Writes to a file safely by grabbing an exclusive lock, so no other process can read or write to it while you're writing ๐Ÿ”

  • Parameters:
    • file (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • s (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: None

โœจ class toil.server.utils.MemoryStateCache โœจ

An in-memory spot to store workflow state ๐Ÿงš

โœจ get(workflow_id, key) โœจ

Gets a key value from memory ๐Ÿ”‘

  • Parameters:
    • workflow_id (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • key (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: Optional[str] (</usr/share/doc/python3/html/library/stdtypes.html#str>)

โœจ set(workflow_id, key, value) โœจ

Sets or clears a key value in memory ๐Ÿงน

  • Parameters:
    • workflow_id (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • key (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • value (Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • Return type: None

๐ŸŒธ class toil.server.utils.AbstractStateStore

This is the WES server's memory bank ๐Ÿง โœจ. It keeps track of which workflows exist and whether they're done or not. It's a key-value store with keys namespaced by workflow ID, and concurrent access from multiple threads or processes is safe and globally consistent ๐Ÿ”’๐Ÿ’œ.

Keys and workflow IDs are restricted to [-a-zA-Z0-9_], because backends may use them as path or URL components ๐Ÿ™…โ€โ™€๏ธ.

Key values are either a string, or None if the key is not set.

Workflow existence isn't a thing ๐Ÿ’€. Nonexistent workflows just have None for all keys.

โš ๏ธ Note that we don't have a cleanup operation yet. Things are stored permanently, and even clearing all the keys may leave data behind ๐Ÿ˜ญ.

This store also handles storage for a local cache, with a separate key namespace. It is not a read/write-through cache ๐Ÿฆ‹.

TODO: Can we replace this with just using a JobStore eventually, when AWSJobStore no longer needs SimpleDB? ๐Ÿ‘€

abstractmethod get(workflow_id, key)

Get the value of the given key for the given workflow, or None if the key is not set for the workflow ๐Ÿซถ.

Parameters

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)

abstractmethod set(workflow_id, key, value)

Set the value of the given key for the given workflow. If the value is None, clear the key ๐Ÿงน.

Parameters

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • value (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None

read_cache(workflow_id, key)

Read a value from a local cache, without checking the actual backend ๐Ÿ‘€.

Parameters

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)

write_cache(workflow_id, key, value)

Write a value to a local cache, without modifying the actual backend ๐ŸŒˆ.

Parameters

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • value (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None


๐Ÿฆ‹ class toil.server.utils.MemoryStateStore

Bases: MemoryStateCache, AbstractStateStore

An in-memory place to store workflow state, meant for testing ๐Ÿงช. It inherits from MemoryStateCache first to provide implementations for AbstractStateStore.


๐Ÿ“ class toil.server.utils.FileStateStore(url)

Bases: AbstractStateStore

A place to store workflow state that uses a POSIX-compatible file system ๐Ÿ“.

Parameters

  • url (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

get(workflow_id, key)

Get a key value from the filesystem ๐Ÿ—‚๏ธ.

Parameters

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)

set(workflow_id, key, value)

Set or clear a key value on the filesystem ๐Ÿงผ.

Parameters

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • value (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None


โ˜๏ธ class toil.server.utils.S3StateStore(url)

Bases: AbstractStateStore

A place to store workflow state that uses an S3-compatible object store ๐Ÿชฃ๐Ÿ’–.

Parameters

  • url (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

get(workflow_id, key)

Get a key value from S3 โ˜๏ธ.

Parameters

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)

set(workflow_id, key, value)

Set or clear a key value on S3 ๐Ÿซง.

Parameters

  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • value (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None


๐Ÿงš toil.server.utils.state_store_cache

toil.server.utils.state_store_cache: dict[str, AbstractStateStore]

This is a dict (/usr/share/doc/python3/html/library/stdtypes.html#dict) keyed by str (/usr/share/doc/python3/html/library/stdtypes.html#str), with AbstractStateStore <#toil.server.utils.AbstractStateStore> values. It's the cache of state stores we've already connected to ๐Ÿ—ƒ๏ธ.


๐Ÿ”— toil.server.utils.connect_to_state_store(url)

Connect to a place to store state for workflows, defined by a URL ๐Ÿ”Œ. The URL may be a local file path or URL, or an S3 URL ๐ŸŒ.

Parameters

  • url (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: AbstractStateStore <#toil.server.utils.AbstractStateStore>


๐Ÿ’… class toil.server.utils.WorkflowStateStore(state_store, workflow_id)

This is a slice of a state store that holds the state for one particular workflow ๐ŸŽ€.

Parameters

  • state_store (AbstractStateStore <#toil.server.utils.AbstractStateStore>)
  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

get(key)

Get the given item of workflow state ๐Ÿ‘‘.

Parameters

  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)

set(key, value)

Set the given item of workflow state โœ๏ธ.

Parameters

  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • value (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None

read_cache(key)

Read a value from a local cache, without checking the actual backend ๐Ÿ‘€.

Parameters

  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str)

write_cache(key, value)

Write a value to a local cache, without modifying the actual backend ๐ŸŒธ.

Parameters

  • key (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • value (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None


๐Ÿ”Œ toil.server.utils.connect_to_workflow_state_store(url, workflow_id)

Connect to a place to store state for the given workflow, in the state store defined by the given URL ๐Ÿซถ.

Parameters

  • url (str, /usr/share/doc/python3/html/library/stdtypes.html#str): a URL that can be used for connect_to_state_store()
  • workflow_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: WorkflowStateStore <#toil.server.utils.WorkflowStateStore>


๐Ÿ toil.server.utils.TERMINAL_STATES

This is the set of states where a workflow is finished for good ๐Ÿ.

๐Ÿ•ฐ๏ธ toil.server.utils.MAX_CANCELING_SECONDS = 30

toil.server.utils.MAX_CANCELING_SECONDS = 30

๐Ÿšฆ class toil.server.utils.WorkflowStateMachine(store)

This is the class for managing the WES workflow state machine ๐Ÿšฆ. It's the authority on the WES "state" of a workflow, so you need one to read or change the state ๐Ÿ‘‘.

Guaranteeing that only certain transitions can be observed is possible, but not worth it ๐Ÿ™…โ€โ™€๏ธ. Instead, we just let updates clobber each other, and we grab and cache the first terminal state we see, forever ๐Ÿ”’. If it ever becomes important that clients never see things like CANCELED -> COMPLETE or COMPLETE -> SYSTEM_ERROR, we can implement a real distributed state machine here ๐Ÿ› ๏ธ.

We do handle making sure that tasks don't get stuck in CANCELING ๐Ÿซง.

Parameters

  • store (AbstractStateStore <#toil.server.utils.AbstractStateStore>)

The state can be any of these:

  • "UNKNOWN"
  • "QUEUED"
  • "INITIALIZING"
  • "RUNNING"
  • "PAUSED"
  • "COMPLETE"
  • "EXECUTOR_ERROR"
  • "SYSTEM_ERROR"
  • "CANCELED"
  • "CANCELING"

Uses the state store's local cache to prevent needing to read things we've already seen ๐Ÿง ๐Ÿ’–.

Parameters: store (WorkflowStateStore, #toil.server.utils.WorkflowStateStore) ๐Ÿ’–

Okay so these are the state-changing messages, bestie ๐Ÿ’… Each one nudges the workflow from one state to the next, and every send_* method returns None ๐Ÿ™ˆ

  • send_enqueue(): Sends an enqueue message that moves the workflow from UNKNOWN to QUEUED. Lowkey the very first step ๐ŸŒธ
    • Return type: None
  • send_initialize(): Sends an initialize message that moves the workflow from QUEUED to INITIALIZING ๐Ÿงš
    • Return type: None
  • send_run(): Sends a run message that moves the workflow from INITIALIZING to RUNNING ๐Ÿ”ฅ
    • Return type: None
  • send_cancel(): Sends a cancel message that moves the workflow to CANCELING from any non-terminal state. It's the "nope, stop" button ๐Ÿ›‘
    • Return type: None
  • send_canceled(): Sends a canceled message that moves the workflow to CANCELED from CANCELLING ๐Ÿฆ‹
    • Return type: None
  • send_complete(): Sends a complete message that moves the workflow from RUNNING to COMPLETE ๐Ÿ‘‘
    • Return type: None
  • send_executor_error(): Sends an executor_error message that moves the workflow from QUEUED, INITIALIZING, or RUNNING to EXECUTOR_ERROR ๐Ÿ’€
    • Return type: None
  • send_system_error(): Sends a system_error message that moves the workflow from QUEUED, INITIALIZING, or RUNNING to SYSTEM_ERROR ๐Ÿ˜ญ
    • Return type: None
  • get_current_state(): Gets the current state of the workflow. Main character energy ๐Ÿ‘‘
    • Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿงš toil.server.wes

Submodules

  • toil.server.wes.abstract_backend

toil.server.wes.abstract_backend

Attributes

  • logger: No description is given for this one ๐Ÿคท
  • TaskLog: No description is given for this one either ๐ŸŒˆ

Exceptions

  • VersionNotImplementedException: Raised when the requested workflow version is not implemented. โœจ
  • MalformedRequestException: Raised when the request is malformed. ๐Ÿ™ˆ
  • WorkflowNotFoundException: Raised when the requested run ID is not found. ๐Ÿ”
  • WorkflowConflictException: Raised when the requested workflow is not in the expected state. ๐Ÿ’…
  • OperationForbidden: Raised when the request is forbidden. ๐Ÿšซ
  • WorkflowExecutionException: Raised when an internal error occurred during the execution of the workflow. ๐Ÿ’”

Classes

  • WESBackend: A class to represent a GA4GH Workflow Execution Service (WES) API backend. ๐ŸŽ€

Functions

  • handle_errors(func): A decorator that catches errors from the wrapped function and returns a JSON formatted error message. The full story is in Module Contents below ๐Ÿ’œ

Module Contents

  • toil.server.wes.abstract_backend.logger: No description is given for this one ๐Ÿคท
  • toil.server.wes.abstract_backend.TaskLog: No description is given for this one either ๐ŸŒˆ
  • exception toil.server.wes.abstract_backend.VersionNotImplementedException(wf_type, version=None, supported_versions=None)
    • Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)
    • Raised when the requested workflow version is not implemented. โœจ
    • Parameters:
      • wf_type (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
      • version (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)
      • supported_versions (Optional[list[str]], /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • exception toil.server.wes.abstract_backend.MalformedRequestException(message)
    • Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)
    • Raised when the request is malformed. ๐Ÿ™ˆ
    • Parameters:
      • message (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • exception toil.server.wes.abstract_backend.WorkflowNotFoundException
    • Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)
    • Raised when the requested run ID is not found. ๐Ÿ”
  • exception toil.server.wes.abstract_backend.WorkflowConflictException(run_id)
    • Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)
    • Raised when the requested workflow is not in the expected state. ๐Ÿ’…
    • Parameters:
      • run_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • exception toil.server.wes.abstract_backend.OperationForbidden(message)
    • Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)
    • Raised when the request is forbidden. ๐Ÿšซ
    • Parameters:
      • message (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • exception toil.server.wes.abstract_backend.WorkflowExecutionException(message)
    • Bases: Exception (/usr/share/doc/python3/html/library/exceptions.html#Exception)
    • Raised when an internal error occurred during the execution of the workflow. ๐Ÿ’”
    • Parameters:
      • message (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • toil.server.wes.abstract_backend.handle_errors(func)
    • This decorator catches errors from the wrapped function and returns a JSON formatted error message with the appropriate status code defined by the GA4GH WES spec. It's giving error handling with a bow on top ๐ŸŽ€
    • Parameters:
      • func (Callable[Ellipsis, Any])
    • Return type: Callable[Ellipsis, Any]
  • class toil.server.wes.abstract_backend.WESBackend(options)
    • A class to represent a GA4GH Workflow Execution Service (WES) API backend. Intended to be inherited. Subclasses should implement all abstract methods to handle user requests when they hit different endpoints. ๐ŸŽ€
    • Parameters:
      • options (list[str], /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str)
    • options (attribute, no description given)
    • resolve_operation_id(operation_id): Maps an operationId defined in the OpenAPI or swagger yaml file to a function. Iykyk ๐Ÿ—๏ธ
      • Parameters:
        • operation_id (str, /usr/share/doc/python3/html/library/stdtypes.html#str): The operation ID defined in the specification.
      • Returns: A function that should be called when the given endpoint is reached.
      • Return type: Any
    • abstractmethod get_service_info(): Gets information about the Workflow Execution Service. GET /service-info ๐Ÿงš
      • Return type: dict[str, Any] (/usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)
    • abstractmethod list_runs(page_size=None, page_token=None): Lists the workflow runs. GET /runs ๐Ÿ“
      • Parameters:
        • page_size (Optional[int], /usr/share/doc/python3/html/library/functions.html#int)
        • page_token (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)

The stdtypes links point at the Python docs in /usr/share/doc/python3/html/library/stdtypes.html, with anchors #dict, #str, #tuple, #list, and #bytes. ๐Ÿ“š๐Ÿ’…


๐ŸŽ€ abstractmethod run_workflow()

Spin up a brand-new workflow run! โœจ This endpoint creates the run and hands back a RunId so you can keep tabs on how it's doing. ๐Ÿš€

  • Route: POST /runs
  • Return type: dict[str, str]

๐ŸŽ€ abstractmethod get_run_log(run_id)

Get the full tea on a workflow run. ๐Ÿต It's the detailed info, bestie.

  • Route: GET /runs/{run_id}
  • Parameters
    • run_id (str)
  • Return type: dict[str, Any]

๐ŸŽ€ abstractmethod cancel_run(run_id)

Cancel a running workflow. ๐Ÿ›‘ Hit the brakes, babe.

  • Route: POST /runs/{run_id}/cancel
  • Parameters
    • run_id (str)
  • Return type: dict[str, str]

๐ŸŽ€ abstractmethod get_run_status(run_id)

Need a quick vibe check? ๐Ÿ” This one gives you the overall state of a workflow run in a simple result, no deep dive required.

  • Route: GET /runs/{run_id}/status
  • Parameters
    • run_id (str)
  • Return type: dict[str, str]

๐ŸŽ€ static log_for_run(run_id, message)

Logs a message for a run. ๐Ÿ“

  • Parameters
    • run_id (Optional[str])
    • message (str)
  • Return type: None

๐ŸŽ€ static secure_path(path)

Takes a path and gives you back a secured version of it. ๐Ÿ”

  • Parameters
    • path (str)
  • Return type: str

๐ŸŽ€ collect_attachments(args, run_id, temp_dir)

Collect the attachments from the current request ๐Ÿ“Ž by staging the uploaded files into temp_dir. It hands back the temp_dir and the parsed body of the request, so you get both. ๐Ÿซถ

  • Parameters
    • run_id (Optional[str]), the run ID used for logging.
    • temp_dir (Optional[str]), the directory where uploaded files get staged. If it's None, a temporary directory is created for you. ๐Ÿ—‚๏ธ
    • args (dict[str, Any])
  • Return type: tuple[str, dict[str, Any]]

๐Ÿงš toil.server.wes.amazon_wes_utils

๐Ÿ’– Attributes

  • logger
  • NOTICE

๐ŸŒˆ Classes

  • WorkflowPlan: these functions pass around dicts of a certain type, with data and files keys. ๐Ÿง
  • DataDict: under data, there can be:
  • FilesDict: under files, there can be:

โœจ Functions

  • parse_workflow_zip_file(file, workflow_type): processes a workflow zip bundle ๐Ÿ“ฆ
  • parse_workflow_manifest_file(manifest_file): reads a MANIFEST.json file for a workflow zip bundle ๐Ÿ“œ
  • workflow_manifest_url_to_path(url[, parent_dir]): interprets a possibly-relative parsed URL, relative to the given parent directory. ๐Ÿงญ
  • task_filter(task, job_status): AGC requires task names to be annotated with an AWS Batch job ID that theyโ€ฆ (the rest of this one, bestie) ๐Ÿ™ˆ

๐Ÿ”ฅ Module Contents

  • toil.server.wes.amazon_wes_utils.logger
  • toil.server.wes.amazon_wes_utils.NOTICE = Multiline-String
"""
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
"""

๐Ÿ‘‘ class toil.server.wes.amazon_wes_utils.WorkflowPlan

Bases: TypedDict

These functions pass around dicts of a certain type, with data and files keys. ๐Ÿ’œ

  • data: DataDict (anchor #toil.server.wes.amazon_wes_utils.DataDict)
  • files: FilesDict (anchor #toil.server.wes.amazon_wes_utils.FilesDict)

๐ŸŒธ class toil.server.wes.amazon_wes_utils.DataDict

Bases: TypedDict

Under data, there can be:

  • workflowUrl (required if no workflowSource): URL to main workflow code. ๐Ÿ”—
  • workflowUrl: str

๐Ÿฆ‹ class toil.server.wes.amazon_wes_utils.FilesDict

Bases: TypedDict

Under files, there can be:

  • workflowSource (required if no workflowUrl): open binary-mode file for the main workflow code. ๐Ÿ“„
  • workflowInputFiles: list of open binary-mode files for input files. Expected to be JSONs. ๐Ÿงพ
  • workflowOptions: open binary-mode file for a JSON of options sent along with the workflow. โš™๏ธ
  • workflowDependencies: open binary-mode file for the zip the workflow came in, if any. ๐Ÿ—œ๏ธ
  • workflowSource: IO[bytes]
  • workflowInputFiles: list[IO[bytes]]
  • workflowOptions: IO[bytes]
  • workflowDependencies: IO[bytes]

๐Ÿ“ toil.server.wes.amazon_wes_utils.parse_workflow_zip_file(file, workflow_type)

Processes a workflow zip bundle. ๐ŸŽ

  • Parameters
    • file (str): a string or Path-like path to a workflow.zip file. ๐Ÿ“‚
    • workflow_type (str): a string, the extension of the workflow to expect (e.g. "wdl"). ๐Ÿท๏ธ
  • Return type: dict of data and files

If the zip only contains a single file, that file is set as workflowSource. ๐ŸŽฏ

If the zip contains multiple files with a MANIFEST.json file, the MANIFEST is used to determine the appropriate data and file arguments. (See: parse_workflow_manifest_file()) ๐Ÿ—บ๏ธ

If the zip contains multiple files without a MANIFEST.json file:

  • a main workflow file with an extension matching the workflow_type is expected and will be set as workflowSource. ๐Ÿ’…
  • ๐ŸŽ€ optional bonus: if inputs*.json files are chilling in the root level of the zip, they get set as workflowInputs(_d)*, in whatever order they're found ๐Ÿ“ฆ
  • โš™๏ธ optional settings: if an options.json file is in the root level of the zip, it becomes workflowOptions ๐Ÿงš

If the zip has multiple files, the original zip gets set as workflowDependencies ๐Ÿฆ‹

โœจ toil.server.wes.amazon_wes_utils.parse_workflow_manifest_file(manifest_file) โœจ

okay so this one reads a MANIFEST.json file for a workflow zip bundle ๐Ÿ“–

  • manifest_file (str (/usr/share/doc/python3/html/library/stdtypes.html#str)) โ€” a string or Path-like path to a MANIFEST.json file
  • Return type โ€” dict (/usr/share/doc/python3/html/library/stdtypes.html#dict) of data and files

Parameters ๐Ÿ’…

MANIFEST.json is expected to look like this ๐Ÿ‘€

{
    "mainWorkflowURL": "relpath/to/workflow",
    "inputFileURLs": [
        "relpath/to/input-file-1",
        "relpath/to/input-file-2",
        "relpath/to/input-file-3"
    ],
    "optionsFileURL": "relpath/to/option-file"
}
  • ๐ŸŒŸ mainWorkflowURL gives a relative file path in the zip to the workflow file, and that becomes workflowSource
  • ๐Ÿ“š inputFileURLs is optional and gives a list of relative file paths in the zip to input.json files. The list is assumed to be in the order the inputs should be applied, so a higher list index means higher priority. If it's there, it gets used to set workflowInputs(_d) arguments.
  • ๐Ÿง optionsFileURL is optional and gives a relative file path in the zip to an options.json file. If it's there, it gets used to set workflowOptions.

โœจ toil.server.wes.amazon_wes_utils.workflow_manifest_url_to_path(url, parent_dir=None) โœจ

Interpret a possibly-relative parsed URL, relative to the given parent directory. It's giving relative path energy ๐Ÿ—บ๏ธ

  • url (urllib.parse.ParseResult (/usr/share/doc/python3/html/library/urllib.parse.html#urllib.parse.ParseResult))
  • parent_dir (Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ toil.server.wes.amazon_wes_utils.task_filter(task, job_status) โœจ

ngl this one is a little dramatic ๐Ÿ˜ญ AGC requires task names to be annotated with the AWS Batch job ID they were run under. If it finds an un-annotated task name, it crashes. See https://github.com/aws/amazon-genomics-cli/issues/494 ๐Ÿ’€

This encodes the AWSBatchJobID annotation, from the AmazonBatchBatchSystem, into the task name of the given task, then returns the modified task. If there's no annotation available, the task gets censored and None is returned ๐Ÿ™ˆ

  • task (toil.server.wes.abstract_backend.TaskLog)
  • job_status (toil.bus.JobStatus (#toil.bus.JobStatus))
  • Return type โ€” Optional[toil.server.wes.abstract_backend.TaskLog]

๐ŸŒธ toil.server.wes.tasks

๐Ÿ’œ Attributes

  • logger
  • WAIT_FOR_DEATH_TIMEOUT
  • run_wes

๐Ÿฆ‹ Classes

  • ToilWorkflowRunner โ€” a class to represent a workflow runner to run the requested workflow.
  • TaskRunner โ€” abstraction over the Celery API. It runs our run_wes task and lets you cancel it. ๐Ÿ›‘
  • MultiprocessingTaskRunner โ€” a version of TaskRunner that just runs tasks with Multiprocessing. ๐Ÿงš

๐Ÿ”ฅ Functions

  • run_wes_task(base_scratch_dir, state_store_url, ...) โ€” run a requested workflow.
  • cancel_run(task_id) โ€” send a SIGTERM signal to the process that's running task_id.

๐ŸŒˆ Module Contents

  • toil.server.wes.tasks.logger
  • toil.server.wes.tasks.WAIT_FOR_DEATH_TIMEOUT = 20

๐ŸŽ€ class toil.server.wes.tasks.ToilWorkflowRunner(base_scratch_dir, state_store_url, workflow_id, request, engine_options)

A class to represent a workflow runner to run the requested workflow. It's the main character of this whole module ๐Ÿ‘‘

It's responsible for parsing the user request into a shell command, executing that command, and collecting the outputs of the resulting workflow run.

Parameters ๐Ÿ’–

  • base_scratch_dir (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • state_store_url (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • workflow_id (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • request (dict (/usr/share/doc/python3/html/library/stdtypes.html#dict)[str (/usr/share/doc/python3/html/library/stdtypes.html#str), Any])
  • engine_options (list (/usr/share/doc/python3/html/library/stdtypes.html#list)[str (/usr/share/doc/python3/html/library/stdtypes.html#str)])

Attributes ๐Ÿง

  • scratch_dir
  • store
  • state_machine
  • request
  • engine_options
  • wf_type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • version: str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • exec_dir
  • out_dir
  • default_job_store
  • job_store

โœจ write_scratch_file(filename, contents)

Write a file to the scratch directory. Lowkey the simplest method in the whole class ๐ŸŒท

  • filename (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • contents (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • Return type โ€” None

โœจ get_state()

  • Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ write_workflow(src_url)

Fetch the workflow file from its source and write it to a destination file. It's giving fetch-and-save vibes ๐Ÿ“ฅ

  • src_url (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

โœจ sort_options(workflow_engine_parameters=None)

Sort the command line arguments into the order the workflow execution engine can recognize. Order matters, bestie ๐ŸŽ€

  • workflow_engine_parameters (Optional[dict[str, Optional[str]]]) โ€” the user-specified parameters for this particular workflow. Keys are command-line options, and values are option arguments, or None for options that are flags. ๐Ÿšฉ
  • Return type โ€” list[str]

โœจ initialize_run()

Write the workflow and input files, then construct a list of shell commands to be executed. It returns that list of shell commands that should be run in order to complete this workflow run ๐Ÿ

  • Return type โ€” list[str]

โœจ call_cmd(cmd, cwd)

Calls a command with Popen. It writes stdout, stderr, and the command to separate files ๐Ÿ“

Parameters

  • cmd ๐Ÿ’– โ€” this one's a Union[list[str], str], so you can pass a list of strings or one plain string. Doc refs: /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str
  • cwd ๐ŸŒธ โ€” a str. Doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type ๐Ÿฆ‹ โ€” subprocess.Popen[bytes]. Doc refs: /usr/share/doc/python3/html/library/subprocess.html#subprocess.Popen and /usr/share/doc/python3/html/library/stdtypes.html#bytes

run() โœจ โ€” okay so this one builds a command to run the requested workflow with the options, runs it, and drops the outputs into the output directory. ๐Ÿ’…

Return type โ€” None

write_output_files() ๐Ÿงš โ€” fetches every file this workflow generated and writes info about each one out to outputs.json. ๐Ÿ“

Return type โ€” None


toil.server.wes.tasks.run_wes_task(base_scratch_dir, state_store_url, workflow_id, request, engine_options)

Run a requested workflow. It's giving main character energy. ๐Ÿ‘‘

Parameters

  • base_scratch_dir (str) ๐ŸŒˆ โ€” the directory where the workflow's scratch dir lives, under the workflow's ID. Doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str
  • state_store_url (str) ๐Ÿฆ‹ โ€” the URL or path where the server and the Celery task talk about workflow state. Doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str
  • workflow_id (str) ๐Ÿซถ โ€” the ID of the workflow run. Doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str
  • request (dict[str, Any]) ๐Ÿ’œ โ€” no description given, just the type. Doc refs: /usr/share/doc/python3/html/library/stdtypes.html#dict and /usr/share/doc/python3/html/library/stdtypes.html#str
  • engine_options (list[str]) ๐Ÿ”ฅ โ€” no description given, just the type. Doc refs: /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str

Returns โ€” the state of the workflow run. Return type โ€” str. Doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

toil.server.wes.tasks.run_wes ๐Ÿ™ˆ โ€” this one's just a name with no details listed under it, so that's all the tea I've got. ๐Ÿซ 


toil.server.wes.tasks.cancel_run(task_id)

Send a SIGTERM signal to the process that is running task_id. โญ

Parameters

  • task_id (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type โ€” None


class toil.server.wes.tasks.TaskRunner

Okay bestie, this is the abstraction over the Celery API. It runs our run_wes task and lets you cancel it. ๐ŸŽ€ We can swap it out in the server to allow testing without Celery, which is so smart. ๐Ÿง โœจ

๐Ÿฆ‹ static run(args, task_id)

Run the given task args with the given ID on Celery.

Parameters

  • args (tuple[str, str, str, dict[str, Any], list[str]]) โ€” doc refs: /usr/share/doc/python3/html/library/stdtypes.html#tuple, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#list
  • task_id (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type โ€” None

๐ŸŒธ static cancel(task_id)

Cancel the task with the given ID on Celery. ๐Ÿ’…

Parameters

  • task_id (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type โ€” None

๐Ÿงš static is_ok(task_id)

Make sure the task running system is working for the given task. If the task system has detected an internal failure, it returns False. ๐Ÿšจ

Parameters

  • task_id (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type โ€” bool. Doc ref: /usr/share/doc/python3/html/library/functions.html#bool


class toil.server.wes.tasks.MultiprocessingTaskRunner

Bases: TaskRunner ๐Ÿ”—

This is the version of TaskRunner that just runs tasks with multiprocessing. ๐ŸŒˆ

Can't use threading here, bestie. There's no way to send a cancel signal or exception to a Python thread if loops in the task (i.e. ToilWorkflowRunner) don't poll for it. ๐Ÿ’€

๐ŸŽ€ static set_up_and_run_task(output_path, args)

Set up logging for the process into the given file, and then call run_wes_task with the given arguments. ๐ŸŽ€

If the process finishes successfully, it cleans up the log. But if the process crashes, the caller has to clean up the log. ๐Ÿซถ

Parameters

  • output_path (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str
  • args (tuple[str, str, str, dict[str, Any], list[str]]) โ€” doc refs: /usr/share/doc/python3/html/library/stdtypes.html#tuple, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#list

Return type โ€” None

๐Ÿฆ‹ classmethod run(args, task_id)

Run the given task args with the given ID. ๐Ÿ”ฅ

Parameters

  • args (tuple[str, str, str, dict[str, Any], list[str]]) โ€” doc refs: /usr/share/doc/python3/html/library/stdtypes.html#tuple, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#list
  • task_id (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type โ€” None

๐ŸŒˆ classmethod cancel(task_id)

Cancel the task with the given ID. ๐Ÿ›‘

Parameters

  • task_id (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type โ€” None

๐Ÿ’œ classmethod is_ok(task_id)

Make sure the task running system is working for the given task. If the task system has detected an internal failure, it returns False. ๐Ÿšจ

Parameters

  • task_id (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type โ€” bool. Doc ref: /usr/share/doc/python3/html/library/functions.html#bool


โœจ toil.server.wes.toil_backend โœจ

๐ŸŽ€ Attributes

  • logger ๐Ÿช„

๐Ÿฆ‹ Classes

  • ToilWorkflow ๐ŸŒธ
  • ToilBackend ๐Ÿ’– โ€” WES backend implemented for Toil to run CWL, WDL, or Toil workflows. This

๐Ÿงš Module Contents

toil.server.wes.toil_backend.logger โ€” the logger attribute. โœจ


class toil.server.wes.toil_backend.ToilWorkflow(base_work_dir, state_store_url, run_id)

Parameters

  • base_work_dir (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str
  • state_store_url (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str
  • run_id (str) โ€” doc ref: /usr/share/doc/python3/html/library/stdtypes.html#str

Attributes ๐ŸŒท โ€” these are all just names, so take a peek:

  • base_scratch_dir
  • state_store_url
  • run_id
  • scratch_dir
  • exec_dir
  • store
  • state_machine

๐Ÿ’… fetch_state()

There are two signatures, bestie:

fetch_state(key: str, default: str) -> str
fetch_state(key: str, default: None = None) -> str | None

Doc refs: /usr/share/doc/python3/html/library/stdtypes.html#str and /usr/share/doc/python3/html/library/constants.html#None

Return the contents of the given key in the workflow's state store. ๐Ÿ”‘ If the key does not exist, the default value is returned. ๐Ÿซถ

fetch_scratch(filename) ๐Ÿ“‚

okay so this one is giving file retrieval ๐Ÿ’… It hands you a context manager for a stream of the given file from the workflow's scratch directory. If the file isn't there, you get None instead.

  • filename (str) โ€” the file you want

Return type: collections.abc.Generator[Optional[TextIO], None, None]

exists() โœจ

Returns True if the workflow run exists. Simple, but iconic ๐Ÿ™Œ

Return type: bool

get_state() ๐ŸŒธ

Returns the state of the current run. Check the vibe of your run ๐Ÿ‘€

Return type: str

check_on_run(task_runner) ๐Ÿšจ

bestie, this is the vibe check ๐Ÿซถ It makes sure nothing has gone wrong in the task runner for this workflow. If something has, it logs the problem and fails the workflow with an error. Not the best moment, but at least you know what happened ๐Ÿ’€

  • task_runner (type[toil.server.wes.tasks.TaskRunner])

Return type: None

set_up_run() ๐Ÿงš

Sets up the directories this run needs. Think of it as getting the stage ready before the show ๐ŸŽ€

Return type: None

clean_up() ๐Ÿงน

Cleans up the directory and files related to the run. Tidy girl era activated โœจ

Return type: None

queue_run(task_runner, request, options) ๐Ÿฆ‹

This workflow is ready to run, so you hand it off to the task system. Let's gooo ๐Ÿ”ฅ

  • task_runner (type[toil.server.wes.tasks.TaskRunner])
  • request (dict[str, Any])
  • options (list[str])

Return type: None

get_output_files() ๐Ÿ“

Returns a collection of the output files this workflow generated. The receipts ๐Ÿงพ

Return type: Any

get_stdout_path() ๐Ÿ“œ

Returns the path to the standard output log, relative to the run's scratch_dir, or None if it doesn't exist.

Return type: Optional[str]

get_stderr_path() ๐Ÿ™ˆ

Returns the path to the standard output log, relative to the run's scratch_dir, or None if it doesn't exist.

โš ๏ธ Heads up: the original docs literally say standard output log for this method too, even though it's the stderr one. I'm keeping the wording exactly as written, so just be aware of that mismatch ๐Ÿซถ

Return type: Optional[str]

get_messages_path() ๐Ÿ’Œ

Returns the path to the bus message log, relative to the run's scratch_dir, or None if it doesn't exist. Those bus messages are giving secret diary ๐Ÿคซ

Return type: Optional[str]

get_task_logs(filter_function=None) ๐Ÿ‘‘

Returns all the task log objects for the individual tasks in the workflow. Lowkey the main character list ๐Ÿ’œ

The task names come from the job_type values in issued, completed, and failed messages. If JobAnnotationMessage messages are available, their annotations get added to the names too.

  • filter_function (Optional[Callable[[toil.server.wes.abstract_backend.TaskLog, toil.bus.JobStatus], Optional[toil.server.wes.abstract_backend.TaskLog]]]) โ€” optional. If you set it, it gets called with each task log and its job annotations. It should return a modified copy of the task log you want reported, or None if that task log should be left out. Filter with intention ๐ŸŽ€

Return type: list[dict[str, Union[str, int, None]]]


๐Ÿฆ‹ class toil.server.wes.toil_backend.ToilBackend(work_dir, state_store, options, dest_bucket_base, bypass_celery=False, wes_dialect='standard') ๐Ÿงš

Bases: toil.server.wes.abstract_backend.WESBackend

This is the WES backend built for Toil, and it can run CWL, WDL, or Toil workflows. It's the class that validates and executes the workflows you submit. The whole operation, honestly ๐Ÿ”ฅ

  • work_dir (str)
  • state_store (Optional[str])
  • options (list[str])
  • dest_bucket_base (Optional[str])
  • bypass_celery (bool)
  • wes_dialect (str)

Class attributes ๐Ÿ’–

  • run_id_prefix = 'run-'
  • task_runner
  • wes_dialect = 'standard'
  • dest_bucket_base
  • work_dir = b'.'
  • supported_versions

get_runs() ๐ŸŒˆ

This is a generator that yields a list of run IDs and their states. Scroll through the whole feed ๐Ÿ“ฑ

Return type: collections.abc.Generator[tuple[str, str], None, None]

get_state(run_id) ๐ŸŒธ

Returns the state of the workflow run with the given run ID. Heads up that it may raise an error if the workflow doesn't exist ๐Ÿ’€

  • run_id (str)

Return type: str

get_service_info() โœจ

Gets information about the Workflow Execution Service. The service's bio ๐Ÿ’…

Return type: dict[str, Any]

list_runs(page_size=None, page_token=None) ๐Ÿ“

Lists the workflow runs, with pagination options ๐Ÿ“ƒ

  • page_size (Optional[int])
  • page_token (Optional[str])

Return type: dict[str, Any]

run_workflow(**args) ๐Ÿ”ฅ

Runs a workflow. Hit play and let it cook ๐Ÿณ

  • args (Any)

Return type: dict[str, str]

get_run_log(run_id) ๐Ÿ“œ

Gets detailed info about a workflow run. The full tea โ˜•

  • run_id (str)

Return type: dict[str, Any]

cancel_run(run_id) ๐Ÿ›‘

Cancels a running workflow. Sometimes you gotta close the tab ๐Ÿซ 

  • run_id (str)

Return type: dict[str, str]

get_run_status(run_id) ๐Ÿฆ‹

Gets quick status info about a workflow run. You get a simple result with the overall state of the run, no essay required โญ

  • run_id (str)

Return type: dict[str, str]

get_stdout(run_id) ๐Ÿง

Gets the stdout of a workflow run as a static file. Literally the printout of everything it said ๐Ÿ“„

Parameters: run_id (str) ๐Ÿ“ Return type: Any

๐Ÿ“„ get_stderr(run_id)

okay so this one grabs the stderr of a workflow run and hands it back as a static file ๐Ÿ’…

Parameters: run_id (str) Return type: Any

๐Ÿซถ get_health()

bestie this is the vibe check ๐Ÿ’– it returns successfully if the server is healthy

Return type: werkzeug.wrappers.response.Response

๐Ÿ  get_homepage()

gives / a real answer instead of a 404 ๐ŸŒธ main character energy

Return type: werkzeug.wrappers.response.Response


๐ŸŒธ toil.server.wsgi_app

Classes

  • GunicornApplication: an entry point to integrate a Gunicorn WSGI server in Python. To start a (the summary gets cut off right there, bestie ๐Ÿ’€)

Functions

  • run_app(app[, options]): runs a Gunicorn WSGI server โœจ

Module Contents

๐ŸŽ€ class toil.server.wsgi_app.GunicornApplication(app, options=None)

Bases: gunicorn.app.base.BaseApplication

An entry point to integrate a Gunicorn WSGI server in Python, and it's lowkey iconic. To start a WSGI application with callable app, run the following code:

WSGIApplication(app, options={
    ...
}).run()

For more details, see: https://docs.gunicorn.org/en/latest/custom.html

Parameters

  • app (object)
  • options (Optional[dict[str, Any]])

Members

  • options
  • application

init(*args)

Parameters: args (Any) Return type: None

load_config()

Return type: None

load()

Return type: object

๐Ÿฆ‹ toil.server.wsgi_app.run_app(app, options=None)

Runs a Gunicorn WSGI server, no cap ๐Ÿ”ฅ

Parameters

  • app (object)
  • options (Optional[dict[str, Any]])

Return type: None


๐Ÿฆ‹ toil.serviceManager

Attributes

  • logger ๐ŸŒˆ (no description given)

Classes

  • ServiceManager: manages the scheduling of services, literally the queen of the group chat ๐Ÿ‘‘

Module Contents

  • toil.serviceManager.logger

๐Ÿ’œ class toil.serviceManager.ServiceManager(job_store, toil_state)

Manages the scheduling of services. She's the organizer and she is so good at it ๐Ÿ’…

Parameters

  • job_store (toil.jobStores.abstractJobStore.AbstractJobStore)
  • toil_state (toil.toilState.ToilState)

services_are_starting(job_id)

Checks whether the services for a job are currently getting started ๐ŸŒธ

Returns: True if the services for the given job are currently being started, and False otherwise.

Parameters: job_id (str) Return type: bool

get_job_count()

Gets the total number of jobs we're working on โœจ this counts services and their parent non-service jobs.

Return type: int

start()

Starts the service scheduling thread. Let's get this party started ๐ŸŽ‰

Return type: None

put_client(client_id)

Schedules the services of a job asynchronously ๐Ÿงš once the job's services are running, its ID comes back out of toil.leader.ServiceManager.get_ready_client.

Parameters: client_id (str), which is the ID of the job with services to schedule Return type: None

get_ready_client(maxWait)

Fetches a ready client and waits as long as it needs to ๐Ÿซถ

Parameters: maxWait (float), the time in seconds to wait for a JobDescription before returning

Returns: the ID of a client whose services are running, or None if no such job is available.

Return type: Optional[str]

get_unservable_client(maxWait)

Fetches a client whose services failed to start ๐Ÿ’€ rough day for that one.

Parameters: maxWait (float), the time in seconds to wait for a JobDescription before returning

Returns: the ID of a client whose services failed to start, or None if no such job is available.

Return type: Optional[str]

get_startable_service(maxWait)

Fetches a service job that's ready to start ๐Ÿš€

Parameters: maxWait (float), the time in seconds to wait for a job before returning

Returns: the ID of a service job that the leader can start, or None if no such job exists.

Return type: Optional[str]

kill_services(service_ids, error=False)

Stops all the given service jobs ๐Ÿฅ€

Parameters

  • services: service jobStoreIDs to kill
  • error (bool): whether to signal that the service failed with an error when stopping it
  • service_ids (collections.abc.Iterable[str])

Return type: None

is_active(service_id)

Returns true if the service job has not been told to terminate ๐ŸŒˆ

Parameters: service_id (str), the service to check on Return type: bool

is_running(service_id)

Returns true if the service job has started and is active ๐ŸŽ€

Parameters

  • service: the service to check on
  • service_id (str)

Return type: bool

check()

Checks on the service manager thread ๐Ÿ”

Raises RuntimeError: if the underlying thread has quit. Yikes, that's not it, chief ๐Ÿ˜ญ

Return type: None

shutdown()

Terminates worker threads cleanly ๐Ÿซง this starts and kills all service threads, and it will block until all services are started and blocked.

Return type: None

๐Ÿ’– toil.statsAndLogging ๐Ÿ’–

okay bestie, this module is where all the stats and logging lives, so you can actually see what your workflow is doing ๐Ÿ‘€โœจ it's giving organized and it's giving pretty ๐Ÿ’…


๐Ÿฆ‹ Attributes ๐Ÿฆ‹

okay so these are the module-level bits you can grab:

  • logger
  • root_logger
  • toil_logger
  • DEFAULT_LOGLEVEL
  • TRACE

๐ŸŽ€ Classes ๐ŸŽ€

  • StatsAndLogging โ€” this is a thread that gathers up stats and log messages and collates them, so nothing gets lost in the shuffle ๐Ÿงตโœจ

๐ŸŒธ Functions ๐ŸŒธ

  • set_log_level(level[, set_logger]) โ€” sets the root logger's level to a string level, like "INFO" ๐Ÿ“ข
  • install_log_color([set_logger]) โ€” makes your logs colored ๐ŸŒˆ
  • add_logging_options(parser[, default_level]) โ€” adds logging options so you can set the global log level ๐ŸŽ›๏ธ
  • configure_root_logger() โ€” sets up the root logger with handlers and formatting ๐Ÿง
  • log_to_file(log_file, log_rotation)
  • set_logging_from_options(options)
  • suppress_exotic_logging(local_logger) โ€” tries to quiet the loggers of every non-Toil package by setting them to CRITICAL ๐Ÿ”‡๐Ÿ’€

๐Ÿ’… Module Contents ๐Ÿ’…

here's the full lineup of module-level names and values:

toil.statsAndLogging.logger

toil.statsAndLogging.root_logger

toil.statsAndLogging.toil_logger

toil.statsAndLogging.DEFAULT_LOGLEVEL = 20

toil.statsAndLogging.TRACE = 5

๐ŸŽ€ class toil.statsAndLogging.StatsAndLogging(jobStore, config)

okay this is the big one. it's a thread that aggregates stats and logging so the whole run stays tidy ๐Ÿงต๐Ÿ’–

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)
  • config (toil.common.Config)

โœจ start()

kicks off the stats and logging thread ๐Ÿš€

Return type: None

๐ŸŒˆ classmethod formatLogStream(stream, stream_name)

okay so, you hand this a stream of text or bytes, plus the job name, the job itself, or any other optional identity info that can be turned into a string. it gives you back one big formatted job log that's ready to show the user ๐Ÿ“œ

the vibe here is that we don't stick a prefix on every single line of the job's log. if we did, the prefixes would get wider than any reasonable terminal and longer than the messages themselves, and nobody wants that ๐Ÿ™ˆ

Parameters

  • stream (Union[IO[str], IO[bytes]]) โ€” the stream of text or bytes to print for the user
  • stream_name (str)

Return type: str

๐Ÿฆ‹ classmethod logWithFormatting(stream_name, jobLogs, method=logger.debug, message=None)

Parameters

  • stream_name (str)
  • jobLogs (Union[IO[str], IO[bytes]])
  • method (Callable[[str], None])
  • message (Optional[str])

Return type: None

๐Ÿซถ classmethod writeLogFiles(jobNames, jobLogList, config, failed=False)

Parameters

  • jobNames (list[str])
  • jobLogList (list[str])
  • config (toil.common.Config)
  • failed (bool)

Return type: None

๐Ÿ”ฅ classmethod statsAndLoggingAggregator(jobStore, stop, config)

this one is the collator. it pulls stats and reporting log messages from the workers. it runs inside of a thread and keeps collating for as long as the stop flag is not True ๐Ÿ’…

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)
  • stop (threading.Event)
  • config (toil.common.Config)

Return type: None

๐Ÿ‘€ check()

checks in on the stats and logging aggregator. if the underlying thread has quit, it raises a RuntimeError ๐Ÿ˜ญ

Return type: None

๐Ÿงน shutdown()

wraps up the stats and logging aggregation thread, so everything gets finished neatly ๐Ÿงนโœจ

Return type: None

๐ŸŒธ toil.statsAndLogging.set_log_level(level, set_logger=None)

sets the root logger level to a given string level, like "INFO" ๐Ÿ“ข

Parameters

  • level (str)
  • set_logger (Optional[logging.Logger])

Return type: None

๐ŸŒˆ toil.statsAndLogging.install_log_color(set_logger=None)

makes logs colored, obsessed ๐ŸŒˆ๐Ÿ’–

Parameters

  • set_logger (Optional[logging.Logger])

Return type: None

๐ŸŽ›๏ธ toil.statsAndLogging.add_logging_options(parser, default_level=None)

adds logging options so you can set the global log level ๐ŸŽ›๏ธ

Parameters

  • default_level (Optional[int]) โ€” a logging level, like logging.INFO, to use as the default
  • parser (argparse.ArgumentParser)

Return type: None

๐Ÿง toil.statsAndLogging.configure_root_logger()

sets up the root logger with handlers and formatting ๐Ÿง

this needs to be called before any entry point tries to log anything. that way the formatting stays consistent across the whole thing, no exceptions ๐Ÿซถ

Return type: None

๐Ÿ“ toil.statsAndLogging.log_to_file(log_file, log_rotation)

Parameters

  • log_file (Optional[str])
  • log_rotation (bool)

Return type: None

โš™๏ธ toil.statsAndLogging.set_logging_from_options(options)

toil.statsAndLogging.suppress_exotic_logging(local_logger)

Okay so this one is lowkey a hero ๐Ÿฆธ It tries to mute every non-Toil package's logger by setting it to CRITICAL, so the chatty libraries stop clogging up your terminal. Periodt ๐Ÿ”‡โœจ

The noisy ones it goes after include 'requests_oauthlib', 'google', 'boto', 'websocket', 'oauthlib', etc. ๐Ÿ™ˆ

Heads up though: it only mutes loggers that already exist and that you can actually see in the environment ๐Ÿ‘€ The exception is anything in the list declared in "always_suppress", which gets handled no matter what ๐Ÿ’…

Why does this matter? Some packages, especially boto3, aren't always loaded yet when this runs. So we create the logger and set the level preemptively ๐Ÿงš That way it's already handled before the package shows up and starts yapping ๐Ÿ’€

Parameters ๐ŸŽ€

  • local_logger (str) ๐Ÿ“

Return type โ€” None ๐Ÿ’œ


toil.test ๐Ÿงช

Base testing class for Toil. This is the foundation everything test-related is built on, bestie ๐Ÿซถ

Submodules ๐ŸŒˆ

  • toil.test.batchSystems

Submodules ๐ŸŒˆ

  • toil.test.batchSystems.batchSystemTest

Attributes ๐Ÿ”ฅ

These are the attributes that live in there:

  • logger
  • numCores
  • preemptible
  • defaultRequirements

Classes ๐Ÿ‘‘

Here's the whole lineup of test classes, iykyk ๐Ÿ’…

  • BatchSystemPluginTest โ€” the class that tests batch system plugin functionality โœจ
  • hidden โ€” hides an abstract base class from unittest's test case loader ๐Ÿ™ˆ
  • AbstractBatchSystemJobTest โ€” an abstract base class for batch system tests that use a full Toil workflow rather ๐Ÿฆ‹
  • KubernetesBatchSystemTest โ€” tests against the Kubernetes batch system โ˜๏ธ
  • KubernetesBatchSystemBenchTest โ€” Kubernetes batch system unit tests that don't need to actually talk to a cluster ๐Ÿง
  • AWSBatchBatchSystemTest โ€” tests against the AWS Batch batch system ๐ŸŒธ
  • MesosBatchSystemTest โ€” tests against the Mesos batch system ๐Ÿ“
  • SingleMachineBatchSystemTest โ€” tests against the single-machine batch system ๐Ÿ’œ
  • MaxCoresSingleMachineBatchSystemTest โ€” this test makes sure the single machine batch system doesn't go past the configured number ๐Ÿซก
  • Service โ€” an abstract class used to define the interface to a service ๐Ÿงš
  • GridEngineBatchSystemTest โ€” tests against the GridEngine batch system ๐Ÿ”ฅ
  • SlurmBatchSystemTest โ€” tests against the Slurm batch system โญ
  • LSFBatchSystemTest โ€” tests against the LSF batch system ๐Ÿฆ‹
  • TorqueBatchSystemTest โ€” tests against the Torque batch system ๐ŸŒˆ
  • HTCondorBatchSystemTest โ€” tests against the HTCondor batch system ๐Ÿ‘‘
  • TestSingleMachineBatchSystemJob โ€” tests a Toil workflow against the SingleMachine batch system ๐Ÿ’–
  • TestMesosBatchSystemJob โ€” tests a Toil workflow against the Mesos batch system ๐Ÿซถ

โœจ Functions โœจ

Okay bestie, here's the helper squad ๐Ÿ’… these are the functions living in this test module:

  • write_temp_file(s, temp_dir) โ€” dumps a string into a temp file and hands you back its path ๐Ÿ“„
  • parentJob(job, cmd)
  • childJob(job, cmd)
  • grandChildJob(job, cmd)
  • greatGrandChild(cmd)
  • measureConcurrency(filepath[, sleep_time]) โ€” runs stuff in parallel to figure out how many concurrent tasks can go at once ๐Ÿƒโ€โ™€๏ธ
  • count(delta, file_path) โ€” increments the counter file and returns the max number of times the file (the page literally trails off right there, no cap ๐Ÿ’€)
  • getCounters(path)
  • resetCounters(path)
  • get_omp_threads()

โœจ Module Contents โœจ

Here's what's sitting in the module namespace ๐ŸŽ€

  • toil.test.batchSystems.batchSystemTest.logger
  • toil.test.batchSystems.batchSystemTest.numCores = 2
  • toil.test.batchSystems.batchSystemTest.preemptible = False
  • toil.test.batchSystems.batchSystemTest.defaultRequirements

๐Ÿฆ‹ class toil.test.batchSystems.batchSystemTest.BatchSystemPluginTest(methodName='runTest')

Bases: toil.test.ToilTest โ€” the plugin testing queen ๐Ÿ‘‘ Its whole job is testing batch system plugin functionality.

  • tearDown() โ€” the cleanup hook that takes the test fixture apart once testing is done ๐Ÿงน
    • Return type: None
  • test_add_batch_system_factory()
    • Return type: None

๐ŸŒธ class toil.test.batchSystems.batchSystemTest.hidden

This one's giving hide-and-seek ๐Ÿ™ˆ It hides the abstract base class from unittest's test case loader, so it doesn't get picked up as a real test. The reference for the trick is http://stackoverflow.com/questions/1323455/python-unit-test-with-base-and-sub-class#answer-25695512.

  • class AbstractBatchSystemTest(methodName='runTest')
    • Bases: toil.test.ToilTest
    • A base test case full of generic tests that every batch system should pass ๐Ÿ’– It can't assume the batch system actually runs commands on the local machine or filesystem, so keep that in mind bestie.
    • abstractmethod createBatchSystem()
      • Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem
    • supportsWallTime()
      • Return type: bool
    • classmethod createConfig() โ€” returns a dummy config for the batch system tests. We need a workflowID set up since we're running tests without setting up a jobstore. This is the class version, for when an instance isn't available ๐Ÿ”ง
      • Return type: toil.common.Config
    • classmethod setUpClass() โ€” the hook that sets up the class fixture before any tests in the class run ๐ŸŽฌ
      • Return type: None
    • setUp() โ€” the hook that sets up the test fixture before we put it to work โœจ
      • Return type: None
    • tearDown() โ€” the hook that takes the test fixture apart after testing it ๐Ÿงน
      • Return type: None
    • get_max_startup_seconds() โ€” gets the number of seconds this test should wait for the first job to run. Some batch systems need time to scale up, so this one's a lowkey lifesaver โณ
      • Return type: int
    • test_available_cores()
      • Return type: None
    • test_run_jobs()
      • Return type: None
    • test_set_env()
      • Return type: None
    • test_set_job_env() โ€” tests the mechanism for setting per-job environment variables on batch system jobs ๐ŸŒˆ
      • Return type: None
    • testCheckResourceRequest()
      • Return type: None
    • testScalableBatchSystem()
      • Return type: None
  • class AbstractGridEngineBatchSystemTest(methodName='runTest')
    • Bases: AbstractBatchSystemTest
    • An abstract class that cuts down on repeated code between Grid Engine, Slurm, and other similar batch systems ๐Ÿซถ

๐Ÿ’œ class toil.test.batchSystems.batchSystemTest.AbstractBatchSystemJobTest

An abstract base class for batch system tests that run a full Toil workflow, instead of talking to the batch system directly. It's the bigger, glam version ๐Ÿ’…

  • cpuCount
  • allocatedCores
  • sleepTime = 30
  • abstractmethod getBatchSystemName()
    • Return type: (str, AbstractBatchSystem)
  • getOptions(tempDir) โ€” configures options for the Toil workflow and makes the job store ๐Ÿ—‚๏ธ
    • Parameters: tempDir (pathlib.Path), the path to the test directory
    • Return type: argparse.Namespace
    • Returns: the Toil options object
  • testJobConcurrency(tmp_path) โ€” checks that the batch system is allocating core resources properly for concurrent tasks ๐Ÿงฎ
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • test_omp_threads(tmp_path) โ€” checks that the OMP_NUM_THREADS env var is set correctly based on jobs.cores ๐Ÿงต
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None

๐Ÿ“ class toil.test.batchSystems.batchSystemTest.KubernetesBatchSystemTest(methodName='runTest')

Bases: hidden. The Kubernetes batch system gets its own tests here โ˜ธ๏ธ

  • supportsWallTime()
    • Return type: bool
  • createBatchSystem()
    • Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

๐Ÿงš class toil.test.batchSystems.batchSystemTest.KubernetesBatchSystemBenchTest(methodName='runTest')

Bases: toil.test.ToilTest. These are Kubernetes batch system unit tests that don't need to actually talk to a cluster, so they're low-key chill ๐Ÿง˜โ€โ™€๏ธ

  • test_preemptability_constraints() โ€” makes sure we generate the right preemptability constraints ๐Ÿ›ก๏ธ
    • Return type: None
  • test_label_constraints() โ€” makes sure we generate the right preemptability constraints (yes, the docstring says preemptability here too, iykyk ๐Ÿ™ƒ)
    • Return type: None

๐ŸŽ€ class toil.test.batchSystems.batchSystemTest.AWSBatchBatchSystemTest(methodName='runTest')

Bases: hidden. Tests against the AWS Batch batch system, slay โ˜๏ธ

  • supportsWallTime()

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’…

createBatchSystem() ๐Ÿงช

Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

get_max_startup_seconds() โณ

Gets the number of seconds this test should wait for the first job to run, because some batch systems need time to scale up ๐ŸŒ„

Return type: int (/usr/share/doc/python3/html/library/functions.html#int)


class toil.test.batchSystems.batchSystemTest.MesosBatchSystemTest(methodName='runTest') ๐ŸŒธ

Bases: hidden, toil.batchSystems.mesos.test.MesosTestSupport

Tests against the Mesos batch system โœจ

Attribute: batchSystem: toil.batchSystems.mesos.batchSystem.MesosBatchSystem

classmethod createConfig() ๐ŸŽ€

Needs to set mesos_endpoint to localhost for testing, since the default is now the private IP address ๐Ÿ™ˆ

Return type: toil.common.Config

supportsWallTime() โฐ

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

createBatchSystem() ๐Ÿงช

Return type: toil.batchSystems.mesos.batchSystem.MesosBatchSystem

tearDown() ๐Ÿงน

Hook method for deconstructing the test fixture after testing it, aka cleaning up after the vibes are over ๐Ÿ’œ

Return type: None

testIgnoreNode() ๐Ÿ™…โ€โ™€๏ธ

Return type: None


toil.test.batchSystems.batchSystemTest.write_temp_file(s, temp_dir) ๐Ÿ“

Dumps a string into a temp file and returns its path, no cap ๐Ÿฆ‹

Parameters:

  • s (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • temp_dir (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


class toil.test.batchSystems.batchSystemTest.SingleMachineBatchSystemTest(methodName='runTest') ๐Ÿ“

Bases: hidden

Tests against the single-machine batch system ๐Ÿ’…

supportsWallTime() โฐ

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

createBatchSystem() ๐Ÿงช

Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

testProcessEscape(hide=False) ๐Ÿƒโ€โ™€๏ธ

Tests to make sure child processes and their descendants go away when the Toil workflow stops.

If hide is true, it will try to hide the child processes to make them hard to stop ๐Ÿซฃ

Parameters:

  • hide (bool (/usr/share/doc/python3/html/library/functions.html#bool))

Return type: None

testHidingProcessEscape() ๐Ÿ™ˆ

Tests to make sure child processes and their descendants go away when the Toil workflow stops, even if the job process stops and leaves children behind. That's a whole plot twist ๐Ÿ˜ญ

Return type: None


class toil.test.batchSystems.batchSystemTest.MaxCoresSingleMachineBatchSystemTest(methodName='runTest') ๐Ÿ‘‘

Bases: toil.test.ToilTest

This test makes sure the single machine batch system doesn't go over the configured number of cores. Main character energy, no exceptions ๐Ÿ”ฅ

classmethod setUpClass() ๐ŸŒˆ

Hook method for setting up the class fixture before running tests in the class โœจ

Return type: None

setUp() ๐ŸŒท

Hook method for setting up the test fixture before exercising it.

Return type: None

tearDown() ๐Ÿงน

Hook method for deconstructing the test fixture after testing it.

Return type: None

scriptCommand() ๐Ÿ“œ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

test() ๐Ÿงช

Return type: None

testServices() ๐Ÿ›Ž๏ธ

Return type: None


toil.test.batchSystems.batchSystemTest.parentJob(job, cmd) ๐Ÿ‘ฉโ€๐Ÿ‘ง

Parameters:

  • job (toil.job.Job)
  • cmd (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: None

toil.test.batchSystems.batchSystemTest.childJob(job, cmd) ๐Ÿง’

Parameters:

  • job (toil.job.Job)
  • cmd (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: None

toil.test.batchSystems.batchSystemTest.grandChildJob(job, cmd) ๐Ÿ‘ถ

Parameters:

  • job (toil.job.Job)
  • cmd (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: None

toil.test.batchSystems.batchSystemTest.greatGrandChild(cmd) ๐Ÿผ

Parameters:

  • cmd (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: None


class toil.test.batchSystems.batchSystemTest.Service(cmd) ๐Ÿงš

Bases: toil.job.Job.Service

Abstract class used to define the interface to a service. You subclass it to make your own services ๐Ÿซถ

It is not executed as a job. It runs inside a ServiceHostJob ๐Ÿ 

Parameters:

  • cmd (str (/usr/share/doc/python3/html/library/stdtypes.html#str))

Attribute: cmd

start(job) ๐Ÿš€

Starts the service.

Parameters:

  • job (toil.job.ServiceHostJob): the underlying host job the service runs in. You can use it to register deferred functions or to reach the fileStore for making temporary files ๐Ÿ—‚๏ธ

Returns: an object describing how to access the service. It has to be pickleable, and jobs use it to access the service (see toil.job.Job.addService()) ๐Ÿ’Œ

Return type: None

check() ๐Ÿฉบ

Checks that the service is still running.

Raises exceptions.RuntimeError: if the service failed, the service job gets labeled failed. ๐Ÿ’€

Returns: True if the service is still running, otherwise False. If it returns False, the service job gets terminated and counted as a success. Important point: if the service job exits due to a failure, it should raise a RuntimeError, not return False! ๐Ÿšจ

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)

stop(job) ๐Ÿ›‘

Stops the service. This function can block until it's complete โณ

Parameters:

  • job (toil.job.ServiceHostJob): the underlying host job the service runs in. You can use it to register deferred functions or to reach the fileStore for making temporary files ๐Ÿ—‚๏ธ

Return type: None


class toil.test.batchSystems.batchSystemTest.GridEngineBatchSystemTest(methodName='runTest') ๐ŸŒฟ

Bases: hidden

Tests against the GridEngine batch system ๐ŸŒฝ

createBatchSystem() ๐Ÿงช

Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

tearDown() ๐Ÿงน

Hook method for deconstructing the test fixture after testing it.

Return type: None


class toil.test.batchSystems.batchSystemTest.SlurmBatchSystemTest(methodName='runTest') ๐ŸŒ

Bases: hidden

Tests against the Slurm batch system ๐Ÿ”ฅ

createBatchSystem() ๐Ÿงช

Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

tearDown() ๐Ÿงน

Hook method for deconstructing the test fixture after testing it.

Return type: None


class toil.test.batchSystems.batchSystemTest.LSFBatchSystemTest(methodName='runTest') ๐Ÿฆฉ

Bases: hidden

Tests against the LSF batch system ๐Ÿซง

createBatchSystem() ๐Ÿงช

Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem


class toil.test.batchSystems.batchSystemTest.TorqueBatchSystemTest(methodName='runTest') ๐ŸŽถ

Bases: hidden

Tests against the Torque batch system ๐Ÿ’œ

createBatchSystem() ๐Ÿงช

Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem

Okay so the tearDown() hook is where you clean up the test fixture after a test is done running ๐Ÿงนโœจ It's a hook method for deconstructing the test fixture after testing it, and it returns None. ๐Ÿ’…

๐Ÿฃ HTCondorBatchSystemTest

class toil.test.batchSystems.batchSystemTest.HTCondorBatchSystemTest(methodName='runTest')

Bases: hidden ๐Ÿ™ˆ

This one's the HTCondor test squad, and it runs tests against the HTCondor batch system ๐Ÿฆ‹

  • createBatchSystem() โ€” builds the batch system for these tests. Return type: toil.batchSystems.abstractBatchSystem.AbstractBatchSystem ๐Ÿ”ฅ
  • tearDown() โ€” the same cleanup hook as before, now for the HTCondor tests. It's a hook method for deconstructing the test fixture after testing it. Return type: None ๐Ÿงน

๐ŸŒˆ TestSingleMachineBatchSystemJob

class toil.test.batchSystems.batchSystemTest.TestSingleMachineBatchSystemJob

Bases: AbstractBatchSystemJobTest โœจ

This class is the main character for testing Toil workflows against the SingleMachine batch system ๐Ÿ‘‘

  • getBatchSystemName() โ€” returns the name of the batch system under test. Return type: (str, AbstractBatchSystem), where the AbstractBatchSystem is toil.batchSystems.abstractBatchSystem.AbstractBatchSystem ๐Ÿ’–
testConcurrencyWithDisk(tmp_path)
  • testConcurrencyWithDisk(tmp_path) โ€” checks that the batch system is allocating disk resources properly. It takes:
    • tmp_path (pathlib.Path) ๐Ÿ“
    • Return type: None
testNestedResourcesDoNotBlock(tmp_path)
  • testNestedResourcesDoNotBlock(tmp_path) โ€” resources get requested in the order Memory > Cpu > Disk. This test makes sure that when there aren't enough CPUs for one scheduled job, it doesn't block another job that can run. No waiting around for the bestie ๐Ÿซถ It takes:
    • tmp_path (pathlib.Path) ๐Ÿ“
    • Return type: None

๐Ÿฆ‹ TestMesosBatchSystemJob

class toil.test.batchSystems.batchSystemTest.TestMesosBatchSystemJob

Bases: AbstractBatchSystemJobTest, toil.batchSystems.mesos.test.MesosTestSupport ๐Ÿ”ฅ

This class tests Toil workflows against the Mesos batch system, and it's giving full test squad energy ๐Ÿ’œ

  • mesos_support() โ€” the Mesos setup helper. Return type: collections.abc.Generator[None] ๐ŸŒธ
  • getOptions(tempDir) โ€” configures the options for the Toil workflow and makes the job store. It's documented as taking a str path to the test directory and returning the Toil options object. It takes:
    • tempDir (pathlib.Path) ๐Ÿ“
    • Return type: argparse.Namespace ๐Ÿ’…
  • getBatchSystemName() โ€” returns the name of the batch system under test. Return type: (str, AbstractBatchSystem), where the AbstractBatchSystem is toil.batchSystems.abstractBatchSystem.AbstractBatchSystem โœจ

๐Ÿง measureConcurrency

toil.test.batchSystems.batchSystemTest.measureConcurrency(filepath, sleep_time=10)

Okay this one runs in parallel to figure out how many tasks are running at the same time ๐Ÿ‘ฏโ€โ™€๏ธ The code was copied from toil.batchSystemTestMaxCoresSingleMachineBatchSystemTest. It takes:

  • filepath (toil.lib.misc.StrPath) โ€” the path to the counter file ๐Ÿ“‚
  • sleep_time (int) โ€” the number of seconds to sleep before counting down โฐ

It returns the max concurrency value as an int ๐Ÿ’–

๐Ÿญ count

toil.test.batchSystems.batchSystemTest.count(delta, file_path)

This one increments the counter file and returns the max number of times the file has been modified ๐Ÿ“ˆ The counter data has to look like this: concurrent tasks, max concurrent tasks. The counter should be initialized to 0,0 ๐Ÿซถ It takes:

  • delta (int) โ€” the increment value โž•
  • file_path (toil.lib.misc.StrPath) โ€” the path to the shared counter file ๐Ÿ“‚

It returns the max concurrent tasks as an int ๐Ÿ‘‘

๐Ÿ”ข getCounters

toil.test.batchSystems.batchSystemTest.getCounters(path)

It takes path (toil.lib.misc.StrPath) and returns a tuple[int, int] ๐Ÿ’…

๐Ÿงน resetCounters

toil.test.batchSystems.batchSystemTest.resetCounters(path)

It takes path (toil.lib.misc.StrPath) and returns None ๐Ÿงน

๐Ÿงต get_omp_threads

toil.test.batchSystems.batchSystemTest.get_omp_threads()

It returns a str ๐ŸŒˆ


๐Ÿ”Œ toil.test.batchSystems.batch_system_plugin_test

โœจ Attributes

  • logger โ€” the module's logger ๐Ÿ“

๐Ÿ‘ฏโ€โ™€๏ธ Classes

  • FakeBatchSystem โ€” adds cleanup support when the last running job leaves a node, for batch systems that can't provide it using the backing scheduler ๐Ÿซง
  • BatchSystemPluginTest โ€” the legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ

๐Ÿ“ฆ Module Contents

toil.test.batchSystems.batch_system_plugin_test.logger ๐Ÿ“

๐ŸŽ€ FakeBatchSystem

class toil.test.batchSystems.batch_system_plugin_test.FakeBatchSystem(config, maxCores, maxMemory, maxDisk)

Bases: toil.batchSystems.cleanup_support.BatchSystemCleanupSupport ๐Ÿฆ‹

This is the fake batch system with cleanup support. It adds cleanup when the last running job leaves a node, for batch systems that can't do it using the backing scheduler ๐Ÿงš It takes:

  • config (toil.common.Config) โš™๏ธ
  • maxCores (float) ๐Ÿ“
  • maxMemory (float) ๐Ÿ“
  • maxDisk (int) ๐Ÿ“
classmethod supportsAutoDeployment()
  • supportsAutoDeployment() โ€” tells you whether this batch system supports auto-deployment of the user script itself ๐Ÿš€

If it does, setUserScript() can be invoked to set the resource object that represents the user script. Return type: bool โœจ

Note to implementors: if your implementation returns True here, it should also override ๐Ÿ™ˆ (That's where the page trails off, so that's all the info we get on that one, bestie.)
issueBatchJob(command, job_desc, job_environment=None)
  • issueBatchJob(command, job_desc, job_environment=None) โ€” issues a job with the specified command to the batch system and returns a unique job ID number ๐ŸŽซ It takes:
    • command (str) โ€” the command to execute somewhere to run the Toil worker process ๐Ÿƒโ€โ™€๏ธ
    • job_desc (toil.job.JobDescription) โ€” the JobDescription for the job being run ๐Ÿ“‹
    • job_environment (Optional[dict[str, str]]) โ€” a collection of job-specific environment variables to be set on the worker ๐ŸŒฟ
  • It returns a unique job ID number (int) that can be used to reference the newly issued job ๐Ÿ”–
killBatchJobs(jobIDs)
  • killBatchJobs(jobIDs) โ€” kills the given job IDs โ˜ ๏ธ After it returns, the killed jobs won't show up in the results of getRunningBatchJobIDs, and they won't be returned from getUpdatedBatchJob either. It takes:
    • jobIDs (list[int]) โ€” the list of IDs of jobs to kill ๐Ÿ—‘๏ธ
    • Return type: None
getIssuedBatchJobIDs()
  • getIssuedBatchJobIDs() โ€” gets all currently issued jobs ๐Ÿ“ฌ It returns a list of jobs (as job ID numbers) that are currently issued, which means they might be running or waiting to be run. Even though the result is a list, don't depend on the ordering ๐Ÿ™…โ€โ™€๏ธ Return type: list[int]

getUpdatedBatchJob(maxWait)

  • getRunningBatchJobIDs() โ€” Hmm okay so this one hands you a dict of job ID numbers that are actively running right now (not just sitting in the queue waiting ๐Ÿ’…), with how many seconds each one has been going as the value.

Returns

  • A dictionary with running job ID number keys, and how many seconds each has been running as the values ๐Ÿฆ‹

Return type

  • dict[int, float]

Okay so getUpdatedBatchJob(maxWait) is giving "tell me what just finished" energy ๐Ÿซถ It returns info about a job that has updated its status (aka it stopped running, either successfully or with an error). Each job gets returned exactly once, so no double-counting bestie ๐Ÿ’–

Does not return info for jobs killed by killBatchJobs, although they may cause None to be returned earlier than maxWait. ngl that's a plot twist ๐Ÿ™ˆ

Parameters

  • maxWait (int) โ€” the number of seconds to block, waiting for a result โณ

Returns

  • If a result is available, it returns UpdatedBatchJobInfo. Otherwise it returns None. The wallTime is the number of seconds (a strictly positive float) of wall-clock time the job ran for, or None if this batch system doesn't support tracking wall time. Main character energy for the timing info ๐Ÿงš

Return type

  • Optional[toil.batchSystems.abstractBatchSystem.UpdatedBatchJobInfo]

โœจ shutdown() โœจ

Called at the completion of a toil invocation. It should cleanly terminate all worker threads, so no loose ends ๐ŸŒธ

Return type

  • None

โœจ classmethod add_options(parser) โœจ

If this batch system provides any command line options, it adds them to the given parser. Iconic behaviour ๐Ÿ‘‘

Parameters

  • parser (configargparse.ArgumentParser)

Return type

  • None

โœจ classmethod setOptions(setOption) โœจ

This one processes command line or configuration options that are relevant to this batch system. It's giving config-wrangling queen ๐Ÿ’…

Parameters

  • setOption (toil.batchSystems.options.OptionSetter) โ€” A function with signature setOption(option_name, parsing_function=None, check_function=None, default=None, env=None) that returns nothing. It's used to update the run configuration as a side effect ๐ŸŽ€

Return type

  • None

โœจ toil.test.batchSystems.batch_system_plugin_test.BatchSystemPluginTest(methodName='runTest') โœจ

Bases: toil.test.ToilTest

Legacy common base class for Toil tests. New tests should be made in the pytest style and not use this class, bestie ๐Ÿ™ˆ

When running tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files placed. The directory gets created if it doesn't exist. The path may be relative, in which case it's assumed to be relative to the project root. If TOIL_TEST_TEMP isn't defined, temporary files and directories get created in the system's default location for such files, and any temporary files or directories left over from tests will be removed automatically during tear down. Otherwise, left-over files will not be removed. ๐Ÿงน

โœจ tearDown() โœจ

Hook method for deconstructing the test fixture after testing it.

Return type

  • None

โœจ test_batchsystem_plugin_installable() โœจ

Tests that installing a batch system plugin works. ๐Ÿฆ‹ :return:


โœจ toil.test.batchSystems.test_gridengine โœจ

Classes

  • FakeBatchSystem โ€” A class that implements a minimal Batch System, needed to create a Worker (see below). ๐Ÿงš
  • GridEngineTest โ€” Class for unit-testing GridEngineBatchSystem ๐Ÿ’–

Functions

  • call_qstat_or_qacct(args, **_)

โœจ toil.test.batchSystems.test_gridengine.FakeBatchSystem โœจ

Class that implements a minimal Batch System, needed to create a Worker (see below).

config

getWaitDuration()

โœจ with_retries(operation, *args, **kwargs) โœจ

The grid engine batch system needs a with_retries function when running the GridEngineThread, so we fake one ๐Ÿซถ


โœจ toil.test.batchSystems.test_gridengine.call_qstat_or_qacct(args, **_) โœจ


โœจ toil.test.batchSystems.test_gridengine.GridEngineTest(methodName='runTest') โœจ

Bases: toil.test.ToilTest

Class for unit-testing GridEngineBatchSystem ๐ŸŒˆ

โœจ setUp() โœจ

Hook method for setting up the test fixture before exercising it. ๐Ÿ’œ

test_coalesce_job_exit_codes_one_exists()

test_coalesce_job_exit_codes_one_still_running()

test_coalesce_job_exit_codes_many_all_exist()


โœจ toil.test.batchSystems.test_lsf_helper โœจ

lsfHelper.py shouldn't need a batch system, so the unit tests here should aim to run on any system. ๐Ÿ“

Classes

  • LSFHelperTest โ€” Legacy common base class for Toil tests. ๐ŸŽ€

โœจ toil.test.batchSystems.test_lsf_helper.LSFHelperTest(methodName='runTest') โœจ

Bases: toil.test.ToilTest

Legacy common base class for Toil tests. New tests should be made in the pytest style and not use this class ๐Ÿ’…

When running tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files placed. The directory gets created if it doesn't exist. The path may be relative, in which case it's assumed to be relative to the project root. If TOIL_TEST_TEMP isn't defined, temporary files and directories get created in the system's default location for such files, and any temporary files or directories left over from tests will be removed automatically during tear down. Otherwise, left-over files will not be removed. ๐Ÿซถ

โœจ test_parse_mem_and_cmd_from_output() โœจ


โœจ toil.test.batchSystems.test_slurm โœจ

Attributes

  • logger
  • JOB_BASE_TIME

Classes

  • FakeBatchSystem โ€” A class that implements a minimal Batch System, needed to create a Worker (see below). โœจ
  • SlurmTest โ€” Class for unit-testing SlurmBatchSystem ๐Ÿ‘‘

โœจ Functions โœจ

Okay bestie, this little table is the lineup of fake helpers that pretend to be Slurm ๐Ÿงš

  • call_either(args, **_): pretends to call either sacct or scontrol, whichever one fits ๐Ÿ’…
  • call_sacct(args, **_): shows the arguments call_command gets when it runs sacct. The full example is down in Module Contents ๐Ÿฆ‹
  • call_scontrol(args, **_): same energy, but for when call_command runs scontrol ๐Ÿ’œ
  • call_sacct_raises(*_): fakes a failing sacct by raising a CalledProcessErrorStderr ๐Ÿ’€
  • call_sinfo(*_): simulates asking Slurm for partition info ๐ŸŒธ

โœจ Module Contents โœจ

Okay so here are the goods, starting with the module-level bits ๐ŸŽ€

  • toil.test.batchSystems.test_slurm.logger
  • toil.test.batchSystems.test_slurm.JOB_BASE_TIME

toil.test.batchSystems.test_slurm.call_either(args, **_)

Pretends to call either sacct or scontrol, whichever one is the right pick โœจ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.test.batchSystems.test_slurm.call_sacct(args, **_)

Okay, when call_command runs sacct, the arguments look something like this: ['sacct', '-n', '-j', '<comma-separated list of job-ids>', '--format', 'JobIDRaw,State,ExitCode', '-P', '-S', '1970-01-01']. The multi-line output is something like this ๐Ÿ‘€

1234|COMPLETED|0:0
1234.batch|COMPLETED|0:0
1235|PENDING|0:0
1236|FAILED|0:2
1236.extern|COMPLETED|0:0

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.test.batchSystems.test_slurm.call_scontrol(args, **_)

When call_command runs scontrol, the arguments are either ['scontrol', 'show', 'job'] or ['scontrol', 'show', 'job', '<job-id>'] ๐Ÿ“

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.test.batchSystems.test_slurm.call_sacct_raises(*_)

Fakes the sacct command failing by raising a CalledProcessErrorStderr ๐Ÿ’€

toil.test.batchSystems.test_slurm.call_sinfo(*_)

Simulates asking Slurm for partition info ๐Ÿซถ

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)

class toil.test.batchSystems.test_slurm.FakeBatchSystem

Bases: toil.batchSystems.abstractBatchSystem.BatchSystemSupport (#toil.batchSystems.abstractBatchSystem.BatchSystemSupport)

A bare-bones batch system class, just enough to build a Worker (see below) ๐Ÿงš

  • start_time
  • getWaitDuration()

class toil.test.batchSystems.test_slurm.SlurmTest(methodName='runTest')

Bases: toil.test.ToilTest (#toil.test.ToilTest)

The unit-test class for SlurmBatchSystem ๐Ÿงช

  • setUp(): the hook method that sets up the test fixture before it gets exercised
  • test_getJobDetailsFromSacct_one_exists()
  • test_getJobDetailsFromSacct_one_not_exists()
  • test_getJobDetailsFromSacct_many_all_exist()
  • test_getJobDetailsFromSacct_many_some_exist()
  • test_getJobDetailsFromSacct_many_none_exist()
  • test_getJobDetailsFromSacct_argument_list_too_big()
  • test_getJobDetailsFromScontrol_one_exists()
  • test_getJobDetailsFromScontrol_one_not_exists(): asking for the job details of a single job that scontrol doesn't know about should raise an exception ๐Ÿ™ˆ
  • test_getJobDetailsFromScontrol_many_all_exist()
  • test_getJobDetailsFromScontrol_many_some_exist()
  • test_getJobDetailsFromScontrol_many_none_exist()
  • test_getJobExitCode_job_exists()
  • test_getJobExitCode_job_not_exists()
  • test_getJobExitCode_sacct_raises_job_exists(): this one forces scontrol to be used for job info, by letting sacct raise an exception
  • test_getJobExitCode_sacct_raises_job_not_exists(): this one forces scontrol to be used for job info, by letting sacct raise an exception. Then scontrol should also raise, because it doesn't know the job
  • test_coalesce_job_exit_codes_one_exists()
  • test_coalesce_job_exit_codes_one_not_exists()
  • test_coalesce_job_exit_codes_many_all_exist()
  • test_coalesce_job_exit_codes_mix_sacct_scontrol()
  • test_coalesce_job_exit_codes_some_exists()
  • test_coalesce_job_exit_codes_sacct_raises_job_exists(): forces scontrol to be used for job info, by letting sacct raise an exception
  • test_coalesce_job_exit_codes_sacct_raises_job_not_exists(): forces scontrol to be used for job info, by letting sacct raise an exception. Then scontrol should also raise, because it doesn't know the job
  • test_PartitionSet_get_partition()
  • test_PartitionSet_default_gpu_partition()
  • test_prepareSbatch_partition()
  • test_prepareSbatch_time()
  • test_prepareSbatch_export()
  • test_option_detector()
  • test_any_option_detector()

โœจ toil.test.cactus โœจ

Submodules

toil.test.cactus.test_cactus_integration

Classes

Here's the one class in this module, the Cactus Integration test running on a Kubernetes AWS cluster ๐ŸŒˆ

  • CactusIntegrationTest: runs the Cactus Integration test on a Kubernetes AWS cluster

Module Contents

class toil.test.cactus.test_cactus_integration.CactusIntegrationTest(methodName)

Bases: toil.test.provisioners.clusterTest.AbstractClusterTest (#toil.test.provisioners.clusterTest.AbstractClusterTest)

Runs the Cactus Integration test on a Kubernetes AWS cluster ๐Ÿ’–

  • clusterName = 'cactus-test-'
  • leaderNodeType = 't2.medium'
  • clusterType = 'kubernetes'
  • setUp(): sets up for the test. It has to be overridden to call this method and set self.jobStore
  • test_cactus_integration()

โœจ toil.test.conftest โœจ

Functions

  • rootpath(request): records the rootpath at the class level, so you can use it on a unittest.TestCase ๐ŸŒธ

Module Contents

toil.test.conftest.rootpath(request)

Records the rootpath at the class level, so you can use it on a unittest.TestCase ๐ŸŒธ

Parameters: request (pytest.FixtureRequest)

Return type: None


โœจ toil.test.cwl โœจ

Submodules

toil.test.cwl.conftest

Attributes

  • logger
  • collect_ignore

Functions

  • pytest_cwl_execute_test(config, processfile, jobfile): uses Toil to run CWL tests, the same way toil-cwl-runner would ๐Ÿ”ฅ

Module Contents

  • toil.test.cwl.conftest.logger
  • toil.test.cwl.conftest.collect_ignore = ['spec']

toil.test.cwl.conftest.pytest_cwl_execute_test(config, processfile, jobfile)

Uses Toil to execute CWL tests, the same way running toil-cwl-runner would ๐Ÿ‘‘

Parameters

  • config (cwltest.utils.CWLTestConfig)
  • processfile (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • jobfile (Optional[str] (/usr/share/doc/python3/html/library/stdtypes.html#str))

Return type: Tuple[int, Optional[Dict[str, Any]]] (/usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ’– toil.test.cwl.cwlTest ๐Ÿ’–

๐ŸŽ€ Attributes

  • pkg_root โ€” no description given, but it's one of the module's attributes ๐ŸŒธ
  • log โ€” no description given, just sitting there being an attribute โœจ
  • CONFORMANCE_TEST_TIMEOUT โ€” no description given, bestie, but the name says it all โฑ๏ธ
  • TesterFuncType โ€” no description given ๐Ÿฆ‹

๐Ÿ‘‘ Classes

  • TestCWLWorkflow โ€” the CWL tests that ship with Toil and don't involve the whole CWL conformance suite ๐Ÿ’…
  • TestCWLv10Conformance โ€” runs the CWL 1.0 conformance tests in various environments ๐ŸŒˆ
  • TestCWLv11Conformance โ€” runs the CWL 1.1 conformance tests in various environments ๐ŸŒˆ
  • TestCWLv12Conformance โ€” runs the CWL 1.2 conformance tests in various environments ๐ŸŒˆ
  • ImportWorkersMessageHandler โ€” checks whether any WorkerImportJob jobs ran during a workflow ๐Ÿ”ฅ

๐Ÿ’… Functions

  • run_conformance_tests(workDir, yml[, runner, caching, ...]) โ€” this is the one that actually runs the CWL conformance tests, so it's giving main character ๐Ÿ‘‘
  • cwl_v1_0_spec(tmp_path) โ€” no description given ๐Ÿ“œ
  • cwl_v1_1_spec(tmp_path) โ€” no description given ๐Ÿ“œ
  • cwl_v1_2_spec(tmp_path) โ€” no description given ๐Ÿ“œ
  • test_workflow_echo_string_scatter_stderr_log_dir(tmp_path) โ€” no description given ๐Ÿงš
  • test_log_dir_echo_no_output(tmp_path) โ€” no description given ๐Ÿงš
  • test_log_dir_echo_stderr(tmp_path) โ€” no description given ๐Ÿงš
  • test_filename_conflict_resolution(tmp_path) โ€” no description given ๐Ÿงš
  • test_filename_conflict_resolution_3_or_more(tmp_path) โ€” no description given ๐Ÿงš
  • test_filename_conflict_detection(tmp_path) โ€” makes sure we don't just stage files over each other when using a container ๐Ÿณ
  • test_filename_conflict_detection_at_root(tmp_path) โ€” makes sure we don't just stage files over each other ๐Ÿซถ
  • test_pick_value_with_one_null_value(caplog, tmp_path) โ€” makes sure toil-cwl-runner does not false log a warning when pickValue is (the original description just trails off right there, bestie ๐Ÿ’€)
  • test_workflow_echo_string(tmp_path) โ€” no description given ๐Ÿงš
  • test_workflow_echo_string_scatter_capture_stdout(tmp_path) โ€” no description given ๐Ÿงš
  • test_visit_top_cwl_class() โ€” no description given ๐Ÿงš
  • test_visit_cwl_class_and_reduce() โ€” no description given ๐Ÿงš
  • test_trim_mounts_op_nonredundant() โ€” makes sure we don't remove all non-duplicate listings ๐Ÿ™ˆ
  • test_trim_mounts_op_redundant() โ€” makes sure we remove all duplicate listings ๐Ÿงน
  • test_trim_mounts_op_partially_redundant() โ€” makes sure we remove only the redundant listings in the CWL object and leave nonredundant listings intact โœจ
  • test_trim_mounts_op_mixed_urls_and_paths(): main character energy check that we clean up redundant listings in certain edge cases ๐Ÿ’…
  • test_trim_mounts_op_decodable_paths() ๐Ÿฆ‹
  • test_trim_mounts_op_multiple_encodings() ๐ŸŒธ
  • test_download_structure(tmp_path): makes sure download_structure makes the right calls to what it thinks is the file store ๐Ÿ“ฆ
  • test_import_on_workers() ๐Ÿงš
  • test_missing_tmpdir_and_tmp_outdir(tmp_path): tmpdir_prefix and tmp_outdir_prefix don't need to exist before the workflow runs ๐ŸŽ€

โœจ Module Contents โœจ

  • toil.test.cwl.cwlTest.pkg_root = b'.' ๐ŸŒˆ
  • toil.test.cwl.cwlTest.log ๐Ÿ“
  • toil.test.cwl.cwlTest.CONFORMANCE_TEST_TIMEOUT = 10000 โฐ

๐Ÿƒโ€โ™€๏ธ toil.test.cwl.cwlTest.run_conformance_tests

toil.test.cwl.cwlTest.run_conformance_tests(workDir, yml, runner=None,
caching=False, batchSystem=None, selected_tests=None,
selected_tags=None, skipped_tests=None, extra_args=None,
must_support_all_features=False, junit_file=None)

Okay so this one runs the whole CWL conformance test suite, bestie ๐Ÿ’–

Parameters ๐Ÿ’Œ

  • workDir (str </usr/share/doc/python3/html/library/stdtypes.html#str>): the folder the tests run in ๐Ÿ“
  • yml (str </usr/share/doc/python3/html/library/stdtypes.html#str>): the CWL test list YML that tells us which tests to pull from
  • runner (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]): if you set this, it uses that cwl runner instead of the default toil-cwl-runner
  • caching (bool </usr/share/doc/python3/html/library/functions.html#bool>): if True, Toil file store caching gets turned on ๐Ÿง 
  • batchSystem (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]): if set, uses this batch system instead of the default single_machine
  • selected_tests (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]): if set, a description of which test numbers to run (comma-separated numbers or ranges) ๐Ÿ”ข
  • selected_tags (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]): an alternative to selected_tests, runs the tests that have the given tags ๐Ÿท๏ธ
  • skipped_tests (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]): comma-separated string labels of the tests to skip ๐Ÿ™ˆ
  • extra_args (Optional[list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]]): extra arguments handed to the runner for each test
  • must_support_all_features (bool </usr/share/doc/python3/html/library/functions.html#bool>): if set, the run fails when some optional CWL features aren't supported ๐Ÿ’€
  • junit_file (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>]): the JUnit XML file the test info gets written to ๐Ÿ“„

Return type: None

๐ŸŒŸ toil.test.cwl.cwlTest.TesterFuncType

  • toil.test.cwl.cwlTest.TesterFuncType ๐ŸŽญ

๐ŸŽ€ class toil.test.cwl.cwlTest.TestCWLWorkflow

CWL tests that live in Toil and don't involve the whole CWL conformance suite. These check Toil-specific stuff, like which URL types are supported for inputs ๐Ÿ”—

๐Ÿ’… test_cwl_cmdline_input()

Checks that a CWL workflow with inputs specified on the command line runs and passes ๐Ÿ†

Return type: None

๐Ÿฆ‹ revsort(cwl_filename, tester_fn, out_dir)

Parameters ๐Ÿ’Œ

  • cwl_filename (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • tester_fn (TesterFuncType)
  • out_dir (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐ŸŒธ revsort_no_checksum(cwl_filename, tester_fn, out_dir)

Parameters ๐Ÿ’Œ

  • cwl_filename (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • tester_fn (TesterFuncType)
  • out_dir (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿ“ฆ download(inputs, tester_fn, out_dir)

Parameters ๐Ÿ’Œ

  • inputs (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • tester_fn (TesterFuncType)
  • out_dir (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿงš load_contents(inputs, tester_fn, out_dir)

Parameters ๐Ÿ’Œ

  • inputs (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • tester_fn (TesterFuncType)
  • out_dir (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿ“ download_directory(inputs, tester_fn, out_dir)

Parameters ๐Ÿ’Œ

  • inputs (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • tester_fn (TesterFuncType)
  • out_dir (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿ—‚๏ธ download_subdirectory(inputs, tester_fn, out_dir)

Parameters ๐Ÿ’Œ

  • inputs (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • tester_fn (TesterFuncType)
  • out_dir (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐ŸŒˆ test_mpi(tmp_path)

Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

โ˜๏ธ test_s3_as_secondary_file(tmp_path)

Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿ“ test_run_revsort(tmp_path)

Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿง test_run_revsort_nochecksum(tmp_path)

Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿ”ฅ test_run_revsort_no_container(tmp_path)

Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

โญ test_run_revsort2(tmp_path)

Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿซถ test_run_revsort_debug_worker(tmp_path)

Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type: None

๐Ÿ‘‘ test_run_colon_output(tmp_path)

we're so close to the end of this section, bestie ๐ŸŒˆ

test_run_dockstore_trs(tmp_path) โœจ

  • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • Return type ๐Ÿ’…: None
  • test_glob_dir_bypass_file_store(tmp_path) ๐Ÿฆ‹
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_required_input_condition_protection(tmp_path) ๐Ÿ›ก๏ธ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_slurm_node_memory(tmp_path) ๐Ÿง 
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_s3(tmp_path) โ˜๏ธ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_http(tmp_path) ๐ŸŒธ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_https(tmp_path) ๐Ÿ”’
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_https_reference(tmp_path) ๐Ÿ”—
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_file(tmp_path) ๐Ÿ“
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_directory_s3(tmp_path) ๐Ÿ—‚๏ธ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_directory_s3_reference(tmp_path) ๐Ÿ—‚๏ธ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_directory_file(tmp_path) ๐Ÿ—‚๏ธ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_subdirectory_s3(tmp_path) ๐Ÿ“‚
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_download_subdirectory_file(tmp_path) ๐Ÿ“‚
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_load_contents_s3(tmp_path) ๐Ÿ“ฆ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_load_contents_http(tmp_path) ๐Ÿ“ฆ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_load_contents_https(tmp_path) ๐Ÿ“ฆ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_load_contents_file(tmp_path) ๐Ÿ“ฆ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_bioconda(tmp_path) ๐Ÿงฌ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_default_args(tmp_path) ๐ŸŽฏ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_biocontainers(tmp_path) ๐Ÿณ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_cuda(tmp_path) ๐ŸŽฎ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_restart(tmp_path) ๐Ÿ”
    • Enable restarts with toil-cwl-runner: run the failing test, then re-run the correct test. Only implemented for single machine ๐Ÿ™ˆ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_caching(tmp_path) ๐Ÿ’พ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_streamable(tmp_path, extra_args=None) ๐Ÿงœ
    • Checks that a file with 'streamable'=True is a named pipe. This is a CWL1.2 feature โœจ
    • Parameters ๐ŸŽ€:
      • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
      • extra_args (Optional[list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]])
    • Return type ๐Ÿ’…: None
  • test_streamable_reference(tmp_path) ๐ŸŒŠ
    • Checks that a streamable file is still a stream even when it gets passed around by URI.
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_preemptible(tmp_path) ๐Ÿ’œ
    • Makes sure the http://arvados.org/cwl#UsePreemptible extension is supported.
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_preemptible_expression(tmp_path) ๐Ÿ’œ
    • Makes sure the http://arvados.org/cwl#UsePreemptible extension gets validated.
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_missing_import(tmp_path) ๐Ÿ™ˆ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_optional_secondary_files_exists(tmp_path) ๐Ÿ“Ž
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • test_optional_secondary_files_missing(tmp_path) ๐Ÿ“Ž
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: None
  • toil.test.cwl.cwlTest.cwl_v1_0_spec(tmp_path) ๐Ÿ“œ
    • Parameters ๐ŸŽ€: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • Return type ๐Ÿ’…: collections.abc.Generator </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator>[pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>]
  • class toil.test.cwl.cwlTest.TestCWLv10Conformance ๐Ÿ‘‘
    • Runs the CWL 1.0 conformance tests in various environments ๐ŸŒˆ
    • test_run_conformance_with_caching(cwl_v1_0_spec) ๐Ÿ’พ
      • Parameters ๐ŸŽ€: cwl_v1_0_spec (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
      • Return type ๐Ÿ’…: None
    • test_run_conformance(cwl_v1_0_spec, batchSystem=None, caching=False, selected_tests=None, skipped_tests=None, extra_args=None) ๐Ÿƒ
      • Parameters ๐ŸŽ€:
        • cwl_v1_0_spec (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
        • batchSystem (Optional[str </usr/share/doc/python3/html/library/stdtypes.html#str>])
        • caching (bool </usr/share/doc/python3/html/library/functions.html#bool>)
  • selected_tests โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str> ๐ŸŒธ
  • skipped_tests โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str> ๐Ÿ™ˆ
  • extra_args โ€” Optional[list[str]] </usr/share/doc/python3/html/library/stdtypes.html#list> </usr/share/doc/python3/html/library/stdtypes.html#str> โœจ

Return type: None ๐Ÿ’–

โœจ test_lsf_cwl_conformance(cwl_v1_0_spec, caching=False)

Parameters ๐ŸŽ€

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>

Return type: None ๐Ÿ’…

โœจ test_slurm_cwl_conformance(cwl_v1_0_spec, caching=False)

Parameters ๐ŸŽ€

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>

Return type: None ๐Ÿ’…

โœจ test_torque_cwl_conformance(cwl_v1_0_spec, caching=False)

Parameters ๐ŸŽ€

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>

Return type: None ๐Ÿ’…

โœจ test_gridengine_cwl_conformance(cwl_v1_0_spec, caching=False)

Parameters ๐ŸŽ€

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>

Return type: None ๐Ÿ’…

โœจ test_mesos_cwl_conformance(cwl_v1_0_spec, caching=False)

Parameters ๐ŸŽ€

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>

Return type: None ๐Ÿ’…

โœจ test_kubernetes_cwl_conformance(cwl_v1_0_spec, caching=False)

Parameters ๐ŸŽ€

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_lsf_cwl_conformance_with_caching(cwl_v1_0_spec)

Parameters

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_slurm_cwl_conformance_with_caching(cwl_v1_0_spec)

Parameters

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_torque_cwl_conformance_with_caching(cwl_v1_0_spec)

Parameters

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_gridengine_cwl_conformance_with_caching(cwl_v1_0_spec)

Parameters

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_mesos_cwl_conformance_with_caching(cwl_v1_0_spec)

Parameters

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_kubernetes_cwl_conformance_with_caching(cwl_v1_0_spec)

Parameters

  • cwl_v1_0_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…


โœจ toil.test.cwl.cwlTest.cwl_v1_1_spec(tmp_path)

Parameters ๐ŸŽ€

  • tmp_path โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type ๐ŸŒˆ: collections.abc.Generator[pathlib.Path] </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator> </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

๐Ÿ‘‘ class toil.test.cwl.cwlTest.TestCWLv11Conformance

Okay, this class runs the CWL 1.1 conformance tests across different environments ๐ŸŒˆ

๐Ÿ’– test_run_conformance(cwl_v1_1_spec, caching=False, batchSystem=None, skipped_tests=None, extra_args=None)

Parameters ๐ŸŽ€

  • cwl_v1_1_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>
  • batchSystem โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>
  • skipped_tests โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>
  • extra_args โ€” Optional[list[str]] </usr/share/doc/python3/html/library/stdtypes.html#list> </usr/share/doc/python3/html/library/stdtypes.html#str>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_run_conformance_with_caching(cwl_v1_1_spec)

Parameters

  • cwl_v1_1_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_kubernetes_cwl_conformance(cwl_v1_1_spec, caching=False)

Parameters

  • cwl_v1_1_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_kubernetes_cwl_conformance_with_caching(cwl_v1_1_spec)

Parameters

  • cwl_v1_1_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…


โœจ toil.test.cwl.cwlTest.cwl_v1_2_spec(tmp_path)

Parameters ๐ŸŽ€

  • tmp_path โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type ๐ŸŒˆ: collections.abc.Generator[pathlib.Path] </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator> </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

๐Ÿ‘‘ class toil.test.cwl.cwlTest.TestCWLv12Conformance

Okay, this one runs the CWL 1.2 conformance tests across different environments ๐ŸŒˆ

๐Ÿ’– test_run_conformance(cwl_v1_2_spec, runner=None, caching=False, batchSystem=None, selected_tests=None, skipped_tests=None, extra_args=None, must_support_all_features=False, junit_file=None)

Parameters ๐ŸŽ€

  • cwl_v1_2_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • runner โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>
  • caching โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>
  • batchSystem โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>
  • selected_tests โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>
  • skipped_tests โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>
  • extra_args โ€” Optional[list[str]] </usr/share/doc/python3/html/library/stdtypes.html#list> </usr/share/doc/python3/html/library/stdtypes.html#str>
  • must_support_all_features โ€” bool </usr/share/doc/python3/html/library/functions.html#bool>
  • junit_file โ€” Optional[str] </usr/share/doc/python3/html/library/stdtypes.html#str>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_run_conformance_with_caching(cwl_v1_2_spec)

Parameters

  • cwl_v1_2_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_run_conformance_with_task_caching(cwl_v1_2_spec, tmp_path)

Parameters

  • cwl_v1_2_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>
  • tmp_path โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

๐Ÿฆ‹ test_run_conformance_with_in_place_update(cwl_v1_2_spec)

The main thing here: with --bypass-file-store, in-place update has to work properly on a single node, and it can't break any other features ๐Ÿ’€๐Ÿซถ

Parameters

  • cwl_v1_2_spec โ€” pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>

Return type: None ๐Ÿ’…

Return type: None ๐Ÿซถ

  • test_kubernetes_cwl_conformance_with_caching(cwl_v1_2_spec) โ€” ๐Ÿฆ‹ the kubernetes CWL conformance test, but the caching version
    • Parameters: cwl_v1_2_spec (pathlib.Path)
    • Return type: None
  • test_wes_server_cwl_conformance(cwl_v1_2_spec) โ€” ๐ŸŒˆ runs the CWL conformance tests through WES. You must set TOIL_WES_ENDPOINT or it won't work bestie. If your WES server wants auth, set TOIL_WES_USER and TOIL_WES_PASSWORD too ๐Ÿ”

To run it manually, use this:

TOIL_WES_ENDPOINT=http://localhost:8080 TOIL_WES_USER=test TOIL_WES_PASSWORD=password python -m pytest src/toil/test/cwl/cwlTest.py::TestCWLv12Conformance::test_wes_server_cwl_conformance -vv --log-level INFO --log-cli-level INFO
  • Parameters: cwl_v1_2_spec (pathlib.Path)
  • Return type: None
  • toil.test.cwl.cwlTest.test_workflow_echo_string_scatter_stderr_log_dir(tmp_path) ๐Ÿ“
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_log_dir_echo_no_output(tmp_path) ๐Ÿ™ˆ
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_log_dir_echo_stderr(tmp_path) ๐Ÿ“ฃ
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_filename_conflict_resolution(tmp_path) ๐Ÿงฉ
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_filename_conflict_resolution_3_or_more(tmp_path) ๐Ÿงฉ
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_filename_conflict_detection(tmp_path) ๐Ÿ‘€ Make sure we don't just stage files over each other when using a container.
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_filename_conflict_detection_at_root(tmp_path) ๐Ÿ‘€ Again, make sure we don't stage files over each other, specifically when using a container and the files sit at the root of the work dir. The vibe check is strict here ๐Ÿ’…
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_pick_value_with_one_null_value(caplog, tmp_path) ๐Ÿช„ Make sure toil-cwl-runner does not falsely log a warning when pickValue is used but outputSource only has one null value. See: #3991.
    • Parameters:
      • caplog (pytest.LogCaptureFixture)
      • tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_workflow_echo_string(tmp_path) ๐ŸŒธ
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_workflow_echo_string_scatter_capture_stdout(tmp_path) ๐ŸŒธ
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_visit_top_cwl_class() ๐Ÿฆ‹
    • Return type: None
  • toil.test.cwl.cwlTest.test_visit_cwl_class_and_reduce() ๐Ÿฆ‹
    • Return type: None
  • toil.test.cwl.cwlTest.test_trim_mounts_op_nonredundant() โœ‚๏ธ Make sure we don't remove all the non-duplicate listings.
    • Return type: None
  • toil.test.cwl.cwlTest.test_trim_mounts_op_redundant() โœ‚๏ธ Make sure we remove all the duplicate listings.
    • Return type: None
  • toil.test.cwl.cwlTest.test_trim_mounts_op_partially_redundant() โœ‚๏ธ Make sure we remove only the redundant listings in the CWL object and leave the nonredundant listings intact.
    • Return type: None
  • toil.test.cwl.cwlTest.test_trim_mounts_op_mixed_urls_and_paths() โœ‚๏ธ Ensure we remove redundant listings in certain edge cases.
    • Return type: None
  • toil.test.cwl.cwlTest.test_trim_mounts_op_decodable_paths() โœ‚๏ธ
    • Return type: None
  • toil.test.cwl.cwlTest.test_trim_mounts_op_multiple_encodings() โœ‚๏ธ
    • Return type: None
  • toil.test.cwl.cwlTest.test_download_structure(tmp_path) ๐Ÿ“‚ Make sure download_structure makes the right calls to what it thinks is the file store.
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • toil.test.cwl.cwlTest.test_import_on_workers() ๐Ÿšš
    • Return type: None
  • toil.test.cwl.cwlTest.test_missing_tmpdir_and_tmp_outdir(tmp_path) ๐Ÿซง tmpdir_prefix and tmp_outdir_prefix do not need to exist before you run the workflow. Literally no setup needed, bestie ๐Ÿ’–
    • Parameters: tmp_path (pathlib.Path)
    • Return type: None
  • class toil.test.cwl.cwlTest.ImportWorkersMessageHandler ๐Ÿ•ต๏ธโ€โ™€๏ธ This one is a detective ๐Ÿ”
    • Bases: _stream_handler
    • Detects whether any WorkerImportJob jobs ran during a workflow.
    • Attribute: detected = False
    • Method: emit(record). Emits a record ๐Ÿ“จ
      • If a formatter is set, it gets used to format the record. Then the record gets written to the stream with a trailing newline.
      • If there's exception info, it's formatted with traceback.print_exception and tacked onto the stream.
      • If the stream has an 'encoding' attribute, that's what decides how the output gets written to the stream.
      • Parameters: record (logging.LogRecord)
      • Return type: None

โœจ toil.test.docs โœจ

Submodules

  • toil.test.docs.scriptsTest ๐Ÿ“œ

Attributes

  • pkg_root (no value listed here, just the name ๐ŸŒฟ)

Classes

  • toil.test.docs.scriptsTest.ToilDocumentationTest ๐ŸŽ€ Tests for scripts in the Toil tutorials.

Module Contents

  • toil.test.docs.scriptsTest.pkg_root = b'.' ๐ŸŒฟ
  • class toil.test.docs.scriptsTest.ToilDocumentationTest(methodName='runTest') ๐Ÿ’œ
    • Bases: toil.test.ToilTest
    • Tests for scripts in the Toil tutorials.
    • classmethod setUpClass() โ€” ๐Ÿง Hook method for setting up the class fixture before the tests in the class run.
    • tearDown() โ€” ๐Ÿงน Hook method for deconstructing the test fixture after testing it.
      • Return type: None
    • checkExitCode(script, extra_args=[]) ๐Ÿšฆ
      • Parameters: extra_args (list[str])
    • checkExpectedOut(script, expectedOutput) ๐Ÿ“ค
    • checkExpectedPattern(script, expectedPattern) ๐Ÿ”Ž
    • testStats() ๐Ÿ“Š
    • testDynamic() ๐ŸŒ€
    • testEncapsulation() ๐Ÿซง
    • testEncapsulation2() ๐Ÿซง
    • testHelloworld() ๐Ÿ‘‹
    • testInvokeworkflow() ๐Ÿš€
    • testInvokeworkflow2() ๐Ÿš€
    • testJobFunctions() ๐Ÿง 
    • testManaging() ๐Ÿ—‚๏ธ
    • testManaging2() ๐Ÿ—‚๏ธ
    • testMultiplejobs() ๐Ÿงต
    • testMultiplejobs2() ๐Ÿงต
    • testMultiplejobs3() ๐Ÿงต
    • testPromises2() ๐Ÿคž
    • testQuickstart() ๐Ÿ
    • testRequirements() ๐Ÿ“‹
    • testArguments() ๐ŸŽ›๏ธ
    • testDocker() ๐Ÿณ
    • testPromises() ๐Ÿคž
    • testServices() ๐Ÿ›Ž๏ธ
    • testStaging() ๐Ÿ“ฆ

โœจ toil.test.jobStores โœจ

Submodules

  • toil.test.jobStores.jobStoreTest ๐Ÿ—„๏ธ

Attributes

  • logger (no value listed here, just the name ๐Ÿชต)

โœจ Classes โœจ

okay so here's the whole test class lineup, bestie ๐Ÿ’…

  • AbstractJobStoreTest โ€” hides this abstract base class from unittest's test case loader so it doesn't get picked up as a real test ๐Ÿ™ˆ
  • AbstractEncryptedJobStoreTest โ€” no blurb on this one ๐Ÿคท
  • FileJobStoreTest โ€” legacy common base class for Toil tests ๐Ÿ—‚๏ธ
  • GoogleJobStoreTest โ€” legacy common base class for Toil tests โ˜๏ธ
  • AWSJobStoreTest โ€” legacy common base class for Toil tests ๐ŸŸง
  • InvalidAWSJobStoreTest โ€” legacy common base class for Toil tests ๐Ÿ’€
  • EncryptedAWSJobStoreTest โ€” legacy common base class for Toil tests ๐Ÿ”
  • StubHttpRequestHandler โ€” a simple HTTP request handler that only speaks GET and HEAD ๐ŸŒ

โœจ Functions โœจ

  • google_retry(x) โ€” no blurb listed ๐Ÿซถ
  • tearDownModule() โ€” no blurb listed ๐Ÿงน

โœจ Module Contents โœจ

here's everything that lives in the module, all in one spot ๐Ÿง

  • toil.test.jobStores.jobStoreTest.google_retry(x)
  • toil.test.jobStores.jobStoreTest.logger
  • toil.test.jobStores.jobStoreTest.tearDownModule()

๐ŸŽ€ class toil.test.jobStores.jobStoreTest.AbstractJobStoreTest

Hide abstract base class from unittest's test case loader ๐Ÿ™ˆ this is literally the whole point of this one.

Here's the Stack Overflow thread this trick comes from ๐Ÿงต: http://stackoverflow.com/questions/1323455/python-unit-test-with-base-and-sub-class#answer-25695512

  • class Test(methodName='runTest') ๐ŸŒธ
    • Bases: toil.test.ToilTest
    • Legacy common base class for Toil tests. New tests should be made in the 'pytest' style and not use this class.
    • When running tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files placed. The directory gets created if it doesn't exist. The path can be relative, in which case it's treated as relative to the project root. If TOIL_TEST_TEMP isn't defined, temporary files and directories go in the system's default location for such files, and any leftovers from tests get automatically removed during tear down. Otherwise, left-over files won't be removed.
    • classmethod setUpClass() โ€” hook method for setting up the class fixture before running tests in the class ๐Ÿ—๏ธ
    • setUp() โ€” hook method for setting up the test fixture before exercising it ๐Ÿงช
    • tearDown() โ€” hook method for deconstructing the test fixture after testing it ๐Ÿงผ
    • testInitialState() โ€” ensures proper handling of nonexistent files ๐Ÿ‘ป
    • testJobCreation() โ€” tests creation of a job. Does the job exist in the jobstore it's supposed to be in? Are its attributes what we expect? ๐Ÿงพ
    • testConfigEquality() โ€” ensures the command line configurations get loaded and stored successfully. In setUp(), self.jobstore1 is created and initialized. In this test, after creating newJobStore, .resume() looks for a previously instantiated job store and loads its config options. These are expected to be equal but not the same object โš–๏ธ
    • testJobLoadEquality() โ€” tests that a job created via one JobStore instance can be loaded from another ๐Ÿ”
    • testChildLoadingEquality() โ€” tests that loading a child job operates as expected ๐Ÿ‘ถ
    • testPersistantFilesToDelete() โ€” makes sure updating a job persists filesToDelete. The pattern goes like this: files to be deleted atomically with a job update are referenced in the "filesToDelete" array, which gets persisted to disk first. If things go wrong during the update, this list is used to make sure the updated job and the files are never both visible at the same time ๐Ÿ—‘๏ธ
    • testUpdateBehavior() โ€” tests the proper behavior when updating jobs ๐Ÿ”„
    • testJobDeletions() โ€” tests the consequences of deleting jobs ๐Ÿ’ฅ
    • testSharedFiles() โ€” tests the sharing of files ๐Ÿ“‚
    • testReadWriteSharedFilesTextMode() โ€” checks if text mode is compatible with shared file streams ๐Ÿ“
    • testReadWriteFileStreamTextMode() โ€” checks if text mode is compatible with file streams ๐Ÿ“„
    • testPerJobFiles() โ€” tests the behavior of files on jobs ๐Ÿ—ƒ๏ธ
    • testStatsAndLogging() โ€” tests the behavior of reading and writing stats and logging ๐Ÿ“Š
    • testWriteLogFiles() โ€” tests writing log files ๐Ÿชต
    • testBatchCreate() โ€” tests creation of many jobs at once ๐Ÿญ
    • testGrowingAndShrinkingJob() โ€” makes sure jobs update correctly when they grow or shrink ๐Ÿ“ˆ
    • externalStoreCache โ€” attribute, no blurb listed ๐Ÿ—„๏ธ
    • classmethod cleanUpExternalStores() โ€” cleans up external stores ๐Ÿงฝ
    • mpTestPartSize = 5242880 โ€” the multipart test part size attribute ๐Ÿ“
    • classmethod makeImportExportTests() โ€” makes the import and export tests ๐Ÿ“ฆ
    • testImportHttpFile() โ€” tests importing a file over HTTP ๐ŸŒ
    • testImportFtpFile() โ€” tests importing a file over FTP ๐Ÿ“ก
    • testFileDeletion() โ€” intended to cover batch deletion of items in the AWSJobStore, but it doesn't hurt to run it on the other job stores too ๐Ÿงจ
    • testMultipartUploads() โ€” meant to cover multi-part uploads in the AWSJobStore, but it doesn't hurt to run it against the other job stores as well ๐Ÿงฉ
    • testZeroLengthFiles() โ€” tests reading and writing of empty files ๐Ÿซฅ
    • testLargeFile() โ€” tests reading and writing of large files ๐Ÿ˜
    • fetch_url(url) โ€” fetches the given URL. Throws an error if it can't be fetched in a reasonable number of attempts ๐Ÿ›ฐ๏ธ
      • Parameters: url (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
      • Return type: None
    • assertUrl(url) โ€” no blurb listed ๐Ÿ”—
    • testCleanCache() โ€” no blurb listed ๐Ÿงน
    • testPartialReadFromStream() โ€” tests whether readFileStream will deadlock on a partial read ๐Ÿ”’
    • testDestructionOfCorruptedJobStore() โ€” no blurb listed ๐ŸงŸ
    • testDestructionIdempotence() โ€” no blurb listed โ™ป๏ธ
    • testEmptyFileStoreIDIsReadable() โ€” creates an empty fileStoreID and attempts to read from it ๐Ÿซง

๐ŸŽ€ class toil.test.jobStores.jobStoreTest.AbstractEncryptedJobStoreTest

  • class Test(methodName='runTest') ๐Ÿ”
    • Bases: AbstractJobStoreTest
    • A test of job stores that use encryption ๐Ÿ›ก๏ธ
    • setUp() โ€” hook method for setting up the test fixture before exercising it ๐Ÿงช
    • tearDown() โ€” hook method for deconstructing the test fixture after testing it ๐Ÿงผ
    • testEncrypted() โ€” creates an encrypted file and reads it in encrypted mode. Then it tries again with encryption off, to make sure that fails โŒ
โš ๏ธ testEncrypted() is the one that proves the encryption actually bites. If reading with encryption off doesn't fail, something is very wrong, so don't ignore it ๐Ÿ˜ญ

๐ŸŽ€ class toil.test.jobStores.jobStoreTest.FileJobStoreTest(methodName='runTest')

Bases: AbstractJobStoreTest ๐Ÿ—‚๏ธ

Legacy common base class for Toil tests. Same vibe as before, bestie ๐Ÿ’œ

New tests should be made in the 'pytest' style, so bestie, don't reach for this class for anything new ๐Ÿ™ˆ It's giving legacy energy and we're not doing that anymore ๐Ÿ’…

New tests should be made in the 'pytest' style and not use this class.

When you're running tests, you can optionally set the TOIL_TEST_TEMP environment variable ๐ŸŒธ to the path of a directory where you want your temporary test files to live. The directory gets created if it doesn't exist yet. The path can be relative, and if it is, it's relative to the project root ๐Ÿ—บ๏ธ. If TOIL_TEST_TEMP isn't defined, temporary files and directories get made in the system's default location for that sort of thing, and any temp files or directories left over from tests get automatically removed during tear down ๐Ÿงน. But if TOIL_TEST_TEMP is defined, left-over files will not be removed.

  • testPreserveFileName() โ€” Checks that the fileID ends with the file name you gave it โœจ
  • test_jobstore_init_preserves_symlink_path() โ€” Makes sure that if you hand a fileJobStore a symlink to a directory, it doesn't de-reference it ๐Ÿ”—
  • test_jobstore_does_not_leak_symlinks() โ€” If we link imports into the FileJobStore, you can't get hardlinks to symlinks. No leaks, periodt ๐Ÿ™…โ€โ™€๏ธ
  • test_file_link_imports() โ€” Checks that imported files get symlinked when expected ๐Ÿฆ‹
  • test_symlink_read_control() โ€” Checks that files are read by symlink when expected ๐Ÿ‘€

๐ŸŽ€ class toil.test.jobStores.jobStoreTest.GoogleJobStoreTest(methodName='runTest')

Bases: AbstractJobStoreTest

This is a legacy common base class for Toil tests, so it's not the move for new stuff. New tests should be made in the 'pytest' style and not use this class.

When running tests, you can optionally set TOIL_TEST_TEMP to the path of a directory where your temp test files should go. The directory gets created if it doesn't exist. Relative paths are relative to the project root. If TOIL_TEST_TEMP isn't defined, temp files and directories go in the system's default location, and any leftovers from tests get automatically removed during tear down. If TOIL_TEST_TEMP is defined, left-over files will not be removed.

  • projectID
  • headers

๐ŸŽ€ class toil.test.jobStores.jobStoreTest.AWSJobStoreTest(methodName='runTest')

Bases: AbstractJobStoreTest

Legacy common base class for Toil tests, vibes only for old code. New tests should be made in the 'pytest' style and not use this class.

When running tests, you can optionally set TOIL_TEST_TEMP to a directory path for your temp test files. It gets created if it doesn't exist. Relative paths are relative to the project root. If TOIL_TEST_TEMP isn't defined, temp files and directories go in the system's default location, and leftovers get automatically removed during tear down. If TOIL_TEST_TEMP is defined, left-over files will not be removed.

  • testOverlargeJob()
  • testMultiThreadImportFile() โ€” Tests that importFile is thread-safe ๐Ÿงต

Return type: None


๐ŸŽ€ class toil.test.jobStores.jobStoreTest.InvalidAWSJobStoreTest(methodName='runTest')

Bases: toil.test.ToilTest

This is a legacy common base class for Toil tests. New tests should be made in the 'pytest' style and not use this class.

When running tests, you can optionally set TOIL_TEST_TEMP to the path of a directory where you want temporary test files placed. It gets created if it doesn't exist. Relative paths are relative to the project root. If TOIL_TEST_TEMP isn't defined, temp files and directories get created in the system's default location, and leftovers from tests get automatically removed during tear down. If TOIL_TEST_TEMP is defined, left-over files will not be removed.

  • testInvalidJobStoreName() ๐Ÿ™…โ€โ™€๏ธ

๐ŸŽ€ class toil.test.jobStores.jobStoreTest.EncryptedAWSJobStoreTest(methodName='runTest')

Bases: AWSJobStoreTest, AbstractEncryptedJobStoreTest

Legacy common base class for Toil tests. New tests should be made in the 'pytest' style and not use this class. ๐Ÿซถ

When running tests, you can optionally set TOIL_TEST_TEMP to the path of a directory for temporary test files. It gets created if it doesn't exist. Relative paths are relative to the project root. If TOIL_TEST_TEMP isn't defined, temp files and directories go to the system's default location, and leftovers get automatically removed during tear down. If TOIL_TEST_TEMP is defined, left-over files will not be removed.


๐ŸŽ€ class toil.test.jobStores.jobStoreTest.StubHttpRequestHandler(*args, directory=None, **kwargs)

Bases: http.server.SimpleHTTPRequestHandler (see /usr/share/doc/python3/html/library/http.server.html#http.server.SimpleHTTPRequestHandler)

Okay so this is a simple HTTP request handler with GET and HEAD commands ๐Ÿ“ก. It serves files from the current directory and any of its subdirectories. The MIME type for files is determined by calling the .guess_type() method.

The GET and HEAD requests are identical, except that the HEAD request omits the actual contents of the file.

fileContents = 'A good programmer looks both ways before crossing a one-way street'
  • do_GET() โ€” Serves a GET request ๐Ÿ“

๐ŸŒˆ toil.test.lib

Submodules

  • toil.test.lib.aws

๐ŸŒˆ toil.test.lib.aws

Submodules

  • toil.test.lib.aws.test_iam
  • toil.test.lib.aws.test_s3
  • toil.test.lib.aws.test_utils

๐Ÿงš toil.test.lib.aws.test_iam

Attributes

  • logger

Classes

  • IAMTest โ€” Checks that given permissions and associated functions perform correctly ๐Ÿ’œ

Module Contents

  • toil.test.lib.aws.test_iam.logger

๐ŸŽ€ class toil.test.lib.aws.test_iam.IAMTest(methodName='runTest')

Bases: toil.test.ToilTest

Checks that given permissions and associated functions perform correctly ๐Ÿ”

  • test_permissions_iam()

Return type: None

  • test_negative_permissions_iam()

Return type: None

  • test_wildcard_handling()

Return type: None

  • test_get_policy_permissions()

Return type: None

  • test_create_delete_iam_role()

Return type: None


๐Ÿงš toil.test.lib.aws.test_s3

Attributes

  • logger

Classes

  • S3Test โ€” Confirms the workarounds for us-east-1 ๐Ÿ‡บ๐Ÿ‡ธ

Module Contents

  • toil.test.lib.aws.test_s3.logger

๐ŸŽ€ class toil.test.lib.aws.test_s3.S3Test(methodName='runTest')

Bases: toil.test.ToilTest

Confirms the workarounds for us-east-1, no cap ๐Ÿ’…

  • s3_resource: mypy_boto3_s3.S3ServiceResource | None (the None points to the Python constants docs at /usr/share/doc/python3/html/library/constants.html#None)
  • setUpClass() (classmethod) โ€” Hook method for setting up the class fixture before running tests in the class.

Return type: None

  • test_create_bucket() โ€” Tests bucket creation for us-east-1 ๐Ÿชฃ

Return type: None

  • test_get_bucket_location_public_bucket() โ€” Tests getting the bucket location for a bucket we don't own ๐Ÿ‘€

Return type: None


๐Ÿงš toil.test.lib.aws.test_utils

Attributes

  • logger

Classes

  • TagGenerationTest โ€” Tests tag generation from environment variables ๐Ÿท๏ธ

Module Contents

  • toil.test.lib.aws.test_utils.logger

๐ŸŽ€ class toil.test.lib.aws.test_utils.TagGenerationTest(methodName='runTest')

Bases: toil.test.ToilTest

Tests tag generation from environment variables โœจ

  • test_build_tag()

Return type: None

  • test_empty_aws_tags()

Return type: None

  • test_incorrect_json_object()

Return type: None

  • test_incorrect_json_emoji()

Return type: None

  • test_build_tag_with_tags()

Return type: None

โœจ toil.test.lib.dockerTest โœจ

๐Ÿท๏ธ Attributes

  • logger โ€” a module attribute ๐Ÿ“ with no description attached

๐Ÿง Classes

  • TestDocker โ€” the one class here. It tests dockerCall and makes sure no containers are left around ๐Ÿ‘ป

๐Ÿ“ฆ Module Contents

  • toil.test.lib.dockerTest.logger ๐Ÿ“
  • class toil.test.lib.dockerTest.TestDocker โ€” tests dockerCall and ensures no containers are left around ๐Ÿณ

๐Ÿณ TestDocker

okay so TestDocker is the whole main character ๐Ÿ’… It tests dockerCall and makes sure no containers are left around.

  • dockerTestLogLevel = 'INFO' โ€” a class attribute set to 'INFO' โœจ

๐Ÿงช Methods

Heads up, bestie: the type names in these parameter lists are links in the original page. They point into the Python 3 docs at /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path, /usr/share/doc/python3/html/library/functions.html#bool and /usr/share/doc/python3/html/library/functions.html#int.
  • testDockerClean(tmp_path, caching=False, detached=True, rm=True, deferParam=None) โ€” this one is seriously iconic ๐Ÿ”ฅ It runs the test container, which creates a file in the work dir and then sleeps for 5 minutes. It makes sure the calling job gets SIGKILLed after a minute, leaving behind the spooky/ghost/zombie container ๐Ÿ‘ป It also checks that the container gets killed on batch system shutdown (through the deferParam mechanism) ๐Ÿ’€
    • Parameters:
      • tmp_path (pathlib.Path)
      • caching (bool)
      • detached (bool)
      • rm (bool)
      • deferParam (Optional[int])
    • Return type: None
  • testDockerClean_CRx_FORGO(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_CRx_STOP(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_CRx_RM(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_CRx_None(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_CxD_FORGO(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_CxD_STOP(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_CxD_RM(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_CxD_None(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_Cxx_FORGO(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_Cxx_STOP(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_Cxx_RM(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_Cxx_None(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xRx_FORGO(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xRx_STOP(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xRx_RM(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xRx_None(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xxD_FORGO(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xxD_STOP(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xxD_RM(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xxD_None(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xxx_FORGO(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xxx_STOP(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xxx_RM(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerClean_xxx_None(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerPipeChain(tmp_path, caching=False) โ€” this checks the piping API for dockerCall() ๐Ÿ”— The API kicks in when you pass a list of argument lists as parameters, and the commands get piped together into a chain. For example, parameters=[ ['printf', 'x\n y\n'], ['wc', '-l'] ] should run printf 'x\n y\n' | wc -l ๐Ÿงš
    • Parameters:
      • tmp_path (pathlib.Path)
      • caching (bool)
    • Return type: None
  • testDockerPipeChainErrorDetection(tmp_path, caching=False) โ€” by default, running cmd1 | cmd2 | ... | cmdN only throws an error if cmdN fails ๐Ÿ™ˆ That means all manner of errors can get silently missed. This test makes sure the piping API for dockerCall() throws an exception if any non-last command in the chain fails ๐Ÿšจ
    • Parameters:
      • tmp_path (pathlib.Path)
      • caching (bool)
    • Return type: None
  • testNonCachingDockerChain(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testNonCachingDockerChainErrorDetection(tmp_path) โ€” no description, just vibes ๐Ÿคทโ€โ™€๏ธ Takes tmp_path (pathlib.Path) and returns None
  • testDockerLogs(tmp_path, stream=False, demux=False) โ€” tests the different log outputs when deatch=False ๐Ÿ“œ Only tmp_path (pathlib.Path) shows up in the parameter list here, and it returns None. The stream and demux arguments aren't described on this page.
  • stream (bool, see /usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’–
  • demux (bool, see /usr/share/doc/python3/html/library/functions.html#bool) โœจ

Return type: None ๐Ÿ’…

  • testDockerLogs_Stream(tmp_path) ๐ŸŒŠ
    • Parameters
      • tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • Return type: None
  • testDockerLogs_Demux(tmp_path) ๐Ÿงƒ
    • Parameters
      • tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • Return type: None
  • testDockerLogs_Demux_Stream(tmp_path) ๐Ÿฆ‹
    • Parameters
      • tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • Return type: None

๐ŸŒธ toil.test.lib.test_conversions

๐Ÿซง Attributes

  • logger โ€” no description given, it just vibes ๐Ÿ™ˆ

๐ŸŽ€ Classes

  • ConversionTest โ€” Legacy common base class for Toil tests.

๐Ÿ’œ Module Contents

  • toil.test.lib.test_conversions.logger
  • class toil.test.lib.test_conversions.ConversionTest(methodName='runTest')

Bases: toil.test.ToilTest

This is the legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ Real talk, new tests should be made in the pytest style and not use this class, so don't you dare start something new with it ๐Ÿ™…โ€โ™€๏ธ

Okay, here's the tea on TOIL_TEST_TEMP ๐Ÿต When you run tests, you can optionally set it to the path of a directory where you want temporary test files to go. The directory gets created if it doesn't exist yet. The path can be relative, in which case it's assumed to be relative to the project root. If TOIL_TEST_TEMP is not defined, temp files and directories get made in the system's default location for that stuff, and any leftovers from the tests get removed automatically during tear down. Otherwise, left-over files will not be removed ๐Ÿงน

  • test_convert()
  • test_human2bytes()
  • test_hms_duration_to_seconds()

๐Ÿฆข toil.test.lib.test_ec2

๐Ÿซง Attributes

  • logger โ€” no description given, it just vibes ๐Ÿ™ˆ

๐ŸŽ€ Classes

  • FlatcarFeedTest โ€” Test accessing the Flatcar AMI release feed, independent of the AWS API
  • AMITest โ€” Legacy common base class for Toil tests.

๐Ÿ’œ Module Contents

  • toil.test.lib.test_ec2.logger
  • class toil.test.lib.test_ec2.FlatcarFeedTest(methodName='runTest')

Bases: toil.test.ToilTest

Okay so this one checks the Flatcar AMI release feed, and it's giving independent of the AWS API ๐Ÿ›ฐ๏ธ

  • test_parse_archive_feed() โ€” Make sure we can get a Flatcar release from the Internet Archive.
  • test_parse_beta_feed() โ€” Make sure we can get a Flatcar release from the beta channel.
  • test_parse_stable_feed() โ€” Make sure we can get a Flatcar release from the stable channel.
  • class toil.test.lib.test_ec2.AMITest(methodName='runTest')

Bases: toil.test.ToilTest

Another legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ Same deal as before, new tests should be made in the pytest style and not use this class ๐Ÿ™…โ€โ™€๏ธ

Same TOIL_TEST_TEMP energy here ๐Ÿต You can optionally set it to the path of a directory where you want temporary test files placed. The directory gets created if it doesn't exist. The path may be relative, in which case it's assumed to be relative to the project root. If TOIL_TEST_TEMP is not defined, temporary files and directories get created in the system's default location, and any temporary files or directories left over from tests will be removed automatically during tear down. Otherwise, left-over files will not be removed.

  • classmethod setUpClass() โ€” Hook method for setting up class fixture before running tests in the class.
  • test_fetch_flatcar()
  • test_fetch_arm_flatcar() โ€” Test flatcar AMI finder architecture parameter.

๐Ÿ“œ toil.test.lib.test_history

๐Ÿซง Attributes

  • logger โ€” no description given, it just vibes ๐Ÿ™ˆ

๐ŸŽ€ Classes

  • TestHistory โ€” Tests for Toil history tracking.

๐Ÿ’œ Module Contents

  • toil.test.lib.test_history.logger
  • class toil.test.lib.test_history.TestHistory

Tests for Toil history tracking. Each test gets its own history database ๐Ÿ—‚๏ธ

  • private_history_manager(tmp_path, monkeypatch)
    • Parameters
      • tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • monkeypatch (pytest.MonkeyPatch)
    • Return type: collections.abc.Generator[None], see /usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator
  • make_fake_workflow(workflow_id)
    • Parameters
      • workflow_id (str, see /usr/share/doc/python3/html/library/stdtypes.html#str)
    • Return type: None
  • test_history_submittable_detection() ๐Ÿ” Make sure that a submittable workflow shows up as such before submission and doesn't afterward. Return type: None
  • test_history_deletion() ๐Ÿ—‘๏ธ Return type: None
  • test_history_size_limit() ๐Ÿ“ Make sure the database size can be controlled. Return type: None

๐Ÿ‘‘ toil.test.lib.test_misc

๐Ÿซง Attributes

  • logger โ€” no description given, it just vibes ๐Ÿ™ˆ

๐ŸŽ€ Classes

  • UserNameAvailableTest โ€” Make sure we can get user names when they are available.
  • UserNameUnvailableTest โ€” Make sure we can get something for a user name when user names are not (the table cuts off right there, bestie, but the full version is down below ๐Ÿ‘‡)
  • UserNameVeryBrokenTest โ€” Make sure we can get something for a user name when user name fetching is (cut off here too, full version below ๐Ÿ‘‡)

๐Ÿ’œ Module Contents

  • toil.test.lib.test_misc.logger
  • class toil.test.lib.test_misc.UserNameAvailableTest(methodName='runTest')

Bases: toil.test.ToilTest

Make sure we can get user names when they are available ๐Ÿ™Œ

  • test_get_user_name()
  • class toil.test.lib.test_misc.UserNameUnvailableTest(methodName='runTest')

Bases: toil.test.ToilTest

Make sure we can get something for a user name when user names are not available ๐Ÿซฅ

  • setUp() โ€” Hook method for setting up the test fixture before exercising it.
  • tearDown() โ€” Hook method for deconstructing the test fixture after testing it.
  • test_get_user_name()
  • class toil.test.lib.test_misc.UserNameVeryBrokenTest(methodName='runTest')

Bases: toil.test.ToilTest

Make sure we can get something for a user name when user name fetching is broken in ways we did not expect ๐Ÿ’€

  • setUp() โ€” Hook method for setting up the test fixture before exercising it.
  • tearDown() โ€” Hook method for deconstructing the test fixture after testing it.
  • test_get_user_name()

๐ŸŒธ toil.test.lib.test_trs ๐ŸŒธ

okay bestie, this one is all about testing that we can look up workflows on Dockstore ๐Ÿงš

โœจ Attributes โœจ

  • logger โ€” the only attribute here, with its value left blank in this listing ๐Ÿ’…

๐Ÿ’… Classes ๐Ÿ’…

  • DockstoreLookupTest โ€” make sure we can look up workflows on Dockstore. โœจ

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.test.lib.test_trs.logger

๐Ÿฆ‹ DockstoreLookupTest ๐Ÿฆ‹

class toil.test.lib.test_trs.DockstoreLookupTest(methodName='runTest')

Bases: toil.test.ToilTest

Same vibe as the table up top: this class makes sure we can look up workflows on Dockstore ๐Ÿ’–

๐Ÿ“– read_result(url_or_path) ๐Ÿ“–

Reads a file or a URL, in binary mode so we can test binary file support too ๐Ÿซถ

This is the move because it lets us check that we have the right workflow contents without caring how they're being shown to us. no cap, very clean ๐Ÿ”ฅ

Parameters: url_or_path (str, which points to /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: IO[bytes] (with bytes pointing to /usr/share/doc/python3/html/library/stdtypes.html#bytes)

๐ŸŒˆ test_lookup_from_page_url() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_lookup_from_trs_with_version() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_lookup_from_trs_no_version() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get_from_trs_cached() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_lookup_from_trs_nonexistent_workflow() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_lookup_from_trs_nonexistent_workflow_bad_format() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_lookup_from_trs_nonexistent_version() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get_nonexistent_workflow() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get_nonexistent_version() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get_nonexistent_workflow_bad_format() ๐ŸŒˆ

Return type: None ๐Ÿ’€


๐Ÿงš toil.test.lib.test_url ๐Ÿงš

this module is where the URL access tests live, and they're giving thorough ๐Ÿฆ‹

โœจ Attributes โœจ

  • logger โ€” the only attribute listed, value left blank ๐Ÿ’…

๐Ÿ’… Classes ๐Ÿ’…

  • TestURLAccess โ€” test URLAccess class handling read, list, and checking the size/existence of resources at given URL ๐Ÿซถ

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.test.lib.test_url.logger

๐Ÿฆ‹ TestURLAccess ๐Ÿฆ‹

class toil.test.lib.test_url.TestURLAccess

Test URLAccess class handling read, list, and checking the size/existence of resources at given URL. the whole main character energy of URL testing ๐Ÿ‘‘

๐Ÿ“– test_get_url_access(httpserver) ๐Ÿ“–

Parameters: httpserver (pytest_httpserver.HTTPServer)

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get_size() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get_is_directory() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_list_url() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_read_from_url() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_open_url() ๐ŸŒˆ

Return type: None ๐Ÿ’€


๐ŸŒˆ toil.test.lib.url_plugin_test ๐ŸŒˆ

this one has a fake plugin AND a legacy test class, so pay attention ๐Ÿ‘€

โœจ Attributes โœจ

  • logger โ€” the only attribute here, value left blank ๐Ÿ’…

๐Ÿ’… Classes ๐Ÿ’…

  • FakeURLPlugin โ€” widget for accessing external storage (URLs) ๐Ÿ”ฅ
  • TestURLAccess โ€” legacy common base class for Toil tests ๐Ÿซถ

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.test.lib.url_plugin_test.logger

๐Ÿฆ‹ FakeURLPlugin ๐Ÿฆ‹

class toil.test.lib.url_plugin_test.FakeURLPlugin

Bases: toil.lib.url.URLAccess

Widget for accessing external storage (URLs). a little fake, a lot of vibes ๐Ÿ’–

๐Ÿฆ‹ TestURLAccess ๐Ÿฆ‹

class toil.test.lib.url_plugin_test.TestURLAccess(methodName='runTest')

Bases: toil.test.ToilTest

Legacy common base class for Toil tests. ๐Ÿงš

โš ๏ธ bestie, new tests should be written in the pytest style and should not use this class. it's giving old school, so keep it for the vintage stuff only ๐Ÿ’€

When running tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files placed ๐ŸŒธ The directory gets created if it doesn't exist. The path can be relative, and if it is, it's treated as relative to the project root ๐Ÿ—บ๏ธ

If TOIL_TEST_TEMP isn't defined, temporary files and directories go in the system's default location for that kind of thing. Any temporary files or directories left over from tests get removed automatically during tear down โœจ But if you do set TOIL_TEST_TEMP, the left-over files stick around and won't be removed ๐Ÿซ 

๐Ÿ“– setUp() ๐Ÿ“–

Hook method for setting up the test fixture before exercising it. ๐Ÿซถ

Return type: None ๐Ÿ’€

๐Ÿ“– tearDown() ๐Ÿ“–

Hook method for deconstructing the test fixture after testing it. the clean-up crew ๐Ÿงน

Return type: None ๐Ÿ’€

๐ŸŒˆ test_url_exists() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get_size() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_get_is_directory() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_list_url() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_read_from_url() ๐ŸŒˆ

Return type: None ๐Ÿ’€

๐ŸŒˆ test_open_url() ๐ŸŒˆ

Return type: None ๐Ÿ’€


๐Ÿ“ toil.test.mesos ๐Ÿ“

the mesos tests are next, and this section is a whole mood ๐Ÿงš

โœจ Submodules โœจ

  • toil.test.mesos.MesosDataStructuresTest

๐Ÿ’… Classes ๐Ÿ’…

  • DataStructuresTest โ€” legacy common base class for Toil tests ๐Ÿซถ

๐ŸŽ€ Module Contents ๐ŸŽ€

class toil.test.mesos.MesosDataStructuresTest.DataStructuresTest(methodName='runTest')

Bases: toil.test.ToilTest

Legacy common base class for Toil tests. ๐Ÿงš

โš ๏ธ same deal as before: new tests should be written in the pytest style and not use this class ๐Ÿ’€

When running tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files placed ๐ŸŒธ The directory gets created if it doesn't exist. The path can be relative, and if it is, it's treated as relative to the project root ๐Ÿ—บ๏ธ

If TOIL_TEST_TEMP isn't defined, temporary files and directories go in the system's default location for that kind of thing. Any temporary files or directories left over from tests get removed automatically during tear down โœจ But if you do set TOIL_TEST_TEMP, the left-over files stick around and won't be removed ๐Ÿซ 

๐Ÿ“– testJobQueue(testJobs=1000) ๐Ÿ“–

The mesos JobQueue sorts MesosShape objects by requirement, and this test checks that the sorting is what we expect: non-preemptible job groups go first, with priority given to large jobs ๐Ÿ‘‘ no thoughts, just clean sorting ๐Ÿ”ฅ


๐ŸŒธ toil.test.mesos.helloWorld ๐ŸŒธ

A simple user script for Toil. the OG hello world, iconic ๐Ÿงš

โœจ Attributes โœจ

  • childMessage โ€” value shown under Module Contents ๐Ÿ’–
  • parentMessage โ€” value shown under Module Contents ๐Ÿ’–

๐Ÿ’… Functions ๐Ÿ’…

  • hello_world(job) ๐Ÿฆ‹
  • hello_world_child(job, hw) ๐Ÿฆ‹
  • main() ๐Ÿฆ‹

๐ŸŽ€ Module Contents ๐ŸŽ€

๐Ÿฆ‹ Attributes ๐Ÿฆ‹

toil.test.mesos.helloWorld.childMessage = 'The child job is now running!'
toil.test.mesos.helloWorld.parentMessage = 'The parent job is now running!'

๐ŸŒˆ Functions ๐ŸŒˆ

toil.test.mesos.helloWorld.hello_world(job)
toil.test.mesos.helloWorld.hello_world_child(job, hw)
toil.test.mesos.helloWorld.main()

๐Ÿฆ‹ toil.test.mesos.stress ๐Ÿฆ‹

okay bestie, this is the stress module and it's giving organized ๐Ÿ’… here's everything in it

Classes

  • LongTestJob โ€” a class that represents a unit of work in toil ๐ŸŽ€
  • LongTestFollowOn โ€” also a class that represents a unit of work in toil ๐ŸŒธ
  • HelloWorldJob โ€” yep, another unit of work in toil, the classic ๐Ÿงš
  • HelloWorldFollowOn โ€” the follow-on version, still a unit of work in toil ๐Ÿ’œ

Functions

  • touchFile(fileStore)
  • main(numJobs)

Module Contents

toil.test.mesos.stress.touchFile(fileStore)

toil.test.mesos.stress.touchFile(fileStore)

class toil.test.mesos.stress.LongTestJob(numJobs)

Bases: toil.job.Job

This one's a unit of work in toil, obviously ๐Ÿ’…

Attribute:

  • numJobs

run(fileStore) is where you override to do the actual work and make successor jobs on the fly โœจ

Parameters

  • fileStore โ€” this is your tool for making local and globally sharable temporary files, and for sending log messages to the leader process ๐Ÿ“ฌ

Returns

The return value can be handed to other jobs through toil.job.Job.rv() ๐Ÿ”ฅ

class toil.test.mesos.stress.LongTestFollowOn

Bases: toil.job.Job

Also a unit of work in toil, no notes ๐Ÿ’–

run(fileStore) is where you override to do the work and dynamically create successor jobs ๐Ÿฆ‹

Parameters

  • fileStore โ€” used to create local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“ฌ

Returns

The return value can be passed to other jobs by means of toil.job.Job.rv() ๐ŸŒˆ

class toil.test.mesos.stress.HelloWorldJob(i)

Bases: toil.job.Job

Classic unit of work in toil, hi world ๐Ÿงš

Attribute:

  • i

run(fileStore) is where you override to do the work and dynamically create successor jobs ๐ŸŽ€

Parameters

  • fileStore โ€” used to create local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“ฌ

Returns

The return value can be passed to other jobs by means of toil.job.Job.rv() ๐Ÿ’œ

class toil.test.mesos.stress.HelloWorldFollowOn(i)

Bases: toil.job.Job

The follow-on hello world, still a unit of work in toil ๐ŸŒธ

Attribute:

  • i

run(fileStore) is where you override to do the work and dynamically create successor jobs โœจ

Parameters

  • fileStore โ€” used to create local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“ฌ

Returns

The return value can be passed to other jobs by means of toil.job.Job.rv() ๐Ÿ‘‘

toil.test.mesos.stress.main(numJobs)

toil.test.mesos.stress.main(numJobs)

๐ŸŒˆ toil.test.options ๐ŸŒˆ

Submodules

  • toil.test.options.options

toil.test.options.options

Classes

  • OptionsTest โ€” a class to test functionality of all Toil options ๐Ÿงช

Module Contents

class toil.test.options.options.OptionsTest(methodName='runTest')

Bases: toil.test.ToilTest

This class tests the functionality of all Toil options, so it's basically the options main character ๐Ÿ‘‘

test_default_caching_slurm() โ€” makes sure caching gets set to false when running on Slurm ๐ŸŒธ :return:

test_caching_option_priority() โ€” makes sure the --caching option beats the default_caching() return value ๐Ÿ’… :return:


๐Ÿ’– toil.test.provisioners ๐Ÿ’–

Submodules

  • toil.test.provisioners.aws

toil.test.provisioners.aws

Submodules

  • toil.test.provisioners.aws.awsProvisionerTest

toil.test.provisioners.aws.awsProvisionerTest

Attributes

  • log

Classes

  • TestAWSProvisionerBenchTest โ€” tests for the AWS provisioner that don't actually spin up any instances ๐Ÿซถ
  • AbstractAWSAutoscaleTest โ€” a legacy common base class for Toil tests ๐Ÿฆ–
  • AWSAutoscaleTest โ€” a legacy common base class for Toil tests ๐Ÿฆ–
  • AWSStaticAutoscaleTest โ€” runs the tests on a statically provisioned cluster with autoscaling enabled ๐Ÿ”ฅ
  • AWSManagedAutoscaleTest โ€” runs the tests on a self-scaling Kubernetes cluster โ˜๏ธ
  • AWSAutoscaleTestMultipleNodeTypes โ€” a legacy common base class for Toil tests ๐Ÿฆ–
  • AWSRestartTest โ€” this test makes sure autoscaling still works on a restarted Toil run ๐Ÿ”
  • PreemptibleDeficitCompensationTest โ€” a legacy common base class for Toil tests ๐Ÿฆ–

Functions

  • aws_zone() โ€” supplies an appropriate AWS zone for tests that need one ๐ŸŒ
  • aws_region(aws_zone) โ€” supplies an appropriate AWS region for tests that need one ๐Ÿ—บ๏ธ
  • ec2_client(aws_region) โ€” supplies an AWS EC2 client for tests that need one ๐Ÿ–ฅ๏ธ

Module Contents

toil.test.provisioners.aws.awsProvisionerTest.log

๐ŸŒธ toil.test.provisioners.aws.awsProvisionerTest.aws_zone()

okay so this one is the zone fairy ๐Ÿงš it hands an appropriate AWS zone to any test that needs one. no setup drama, just vibes โœจ

๐Ÿ’œ toil.test.provisioners.aws.awsProvisionerTest.aws_region(aws_zone)

this one takes that zone and gives back an appropriate AWS region for any test that needs one ๐Ÿฆ‹

๐Ÿงš toil.test.provisioners.aws.awsProvisionerTest.ec2_client(aws_region)

and this is your AWS EC2 client for the tests that need one. iconic supporting role ๐Ÿ’…

๐Ÿ”ฅ class toil.test.provisioners.aws.awsProvisionerTest.TestAWSProvisionerBenchTest

bestie, these are the tests for the AWS provisioner that don't actually provision instances ๐Ÿ™ˆ no real cloud spending, just checking the logic slays ๐Ÿ’–

  • test_AMI_finding()
  • test_read_write_global_files(aws_zone) โ€” makes sure _write_file_to_cloud() and _read_file_from_cloud() in the AWS provisioner work the way they're supposed to โœจ
  • test_get_spot_history(ec2_client) โ€” checks that we can download spot price history from AWS ๐Ÿ“ˆ
    • Return type: None
  • test_get_aws_zone_from_spot_market(ec2_client) โ€” checks that we can process spot price history to pick a zone ๐ŸŽฏ
    • Return type: None

๐ŸŽ€ class toil.test.provisioners.aws.awsProvisionerTest.AbstractAWSAutoscaleTest(methodName)

Bases: toil.test.provisioners.clusterTest.AbstractClusterTest

โš ๏ธ this is a legacy common base class for Toil tests. new tests should be written in the pytest style and not use this class, no cap ๐Ÿ’€

okay so when you run tests you can optionally set the TOIL_TEST_TEMP environment variable to a directory where you want the temp test files to go ๐ŸŒˆ the directory gets created if it doesn't exist yet. the path can be relative, in which case it's treated as relative to the project root. if TOIL_TEST_TEMP isn't defined, temp files and directories go in the system's default spot for that stuff, and any leftovers get automatically removed during tear down ๐Ÿงน. but if you do set it, the leftover files are not removed.

โœจ Attributes

  • instanceTypes = ['m5a.large']
  • clusterName = 'aws-provisioner-test-'
  • numWorkers = ['2']
  • numSamples = 2
  • spotBid = 0.15
  • scriptDir = '/tmp/t'
  • venvDir = '/tmp/venv'
  • dataDir = '/tmp'
  • scriptName = 'test_script.py'

๐Ÿ’… Methods

  • script() โ€” returns the full path to the user script on the leader ๐Ÿซถ
  • data(filename) โ€” returns the full path to the data file with the given name on the leader ๐Ÿ“
  • rsyncUtil(src, dest)
    • Parameters:
      • src (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
      • dest (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
    • Return type: None
  • getRootVolID()
    • Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • putScript(content) โ€” a helper for _getScript that injects a script file at the configured script path, made from text ๐Ÿ“
    • Parameters:
      • content (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ’– class toil.test.provisioners.aws.awsProvisionerTest.AWSAutoscaleTest(name)

Bases: AbstractAWSAutoscaleTest

โš ๏ธ legacy common base class for Toil tests, again! new tests should be made in the pytest style and not use this class ๐Ÿ™ˆ

same TOIL_TEST_TEMP energy as before ๐ŸŒธ: set it optionally to a directory for temp test files, it gets created if missing, relative paths count from the project root, and with it undefined the temp stuff lives in the system default spot and gets cleaned up on tear down. set it, and leftovers stay put.

โœจ Attributes

  • clusterName = 'provisioner-test-'
  • requestedLeaderStorage = 80
  • scriptName = 'sort.py'

๐Ÿ’… Methods

  • setUp() โ€” set up for the test. it must be overridden to call this method and set self.jobStore โš ๏ธ
  • launchCluster()
  • getRootVolID() โ€” adds a check that the EBS volume is built with an adequate size. otherwise it's functionally the same as the parent ๐Ÿงš
    • Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
    • Returns: volumeID
  • testAutoScale()
  • testSpotAutoScale()
  • testSpotAutoScaleBalancingTypes()

๐ŸŒˆ class toil.test.provisioners.aws.awsProvisionerTest.AWSStaticAutoscaleTest(name)

Bases: AWSAutoscaleTest

this one runs the tests on a statically provisioned cluster with autoscaling turned on ๐Ÿ‘‘

  • requestedNodeStorage = 20
  • launchCluster()

๐ŸŒˆ class toil.test.provisioners.aws.awsProvisionerTest.AWSManagedAutoscaleTest(name)

Bases: AWSAutoscaleTest

and this one runs the tests on a self-scaling Kubernetes cluster ๐Ÿงš it's giving managed, it's giving effortless โœจ

  • requestedNodeStorage = 20
  • launchCluster()

๐Ÿ”ฅ class toil.test.provisioners.aws.awsProvisionerTest.AWSAutoscaleTestMultipleNodeTypes(name)

Bases: AbstractAWSAutoscaleTest

โš ๏ธ legacy common base class for Toil tests, yes it's the same warning, the pytest style is the move ๐Ÿ’…

and the TOIL_TEST_TEMP rules are the same too ๐Ÿฆ‹: optional, created if missing, relative to the project root, default system location when undefined with automatic cleanup on tear down, and no cleanup for leftovers when it's set.

โœจ Attributes

  • clusterName = 'provisioner-test-'

๐Ÿ’… Methods

  • setUp() โ€” set up for the test. must be overridden to call this method and set self.jobStore โš ๏ธ
  • testAutoScale()

๐Ÿซถ class toil.test.provisioners.aws.awsProvisionerTest.AWSRestartTest(name)

Bases: AbstractAWSAutoscaleTest

this test makes sure autoscaling still works on a restarted Toil run ๐Ÿ”„ main character restart energy ๐Ÿ’–

  • clusterName = 'restart-test-'
  • scriptName = 'restartScript.py'
  • setUp() โ€” set up for the test. must be overridden to call this method and set self.jobStore โš ๏ธ
  • testAutoScaledCluster()

๐ŸŽ€ class toil.test.provisioners.aws.awsProvisionerTest.PreemptibleDeficitCompensationTest(name)

Bases: AbstractAWSAutoscaleTest

โš ๏ธ legacy common base class for Toil tests. use the pytest style for new tests, not this class ๐Ÿ™ˆ

same deal with TOIL_TEST_TEMP ๐ŸŒธ: set it optionally to a temp directory (created if missing, relative paths start from the project root). left unset, temp files live in the system default spot and leftovers get removed on tear down. set it, and leftovers are kept.

โœจ Attributes

  • clusterName = 'deficit-test-'
  • scriptName = 'userScript.py'

๐Ÿ’… Methods

  • setUp() โ€” set up for the test. must be overridden to call this method and set self.jobStore โš ๏ธ
  • test()

๐Ÿ’œ toil.test.provisioners.clusterScalerTest

โœจ Attributes

  • logger
  • c4_8xlarge_preemptible
  • c4_8xlarge
  • r3_8xlarge
  • r5_2xlarge
  • r5_4xlarge
  • t2_micro

๐ŸŽ€ Classes ๐ŸŽ€

Four classes live here, bestie ๐Ÿ’…

  • BinPackingTest: Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ
  • ClusterScalerTest: Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ
  • ScalerThreadTest: Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ
  • MockBatchSystemAndProvisioner: Mimics a leader, a job batcher, a provisioner and a scalable batch system, all in one ๐Ÿ‘‘ multitasking queen energy

๐Ÿ’– Module Contents ๐Ÿ’–

Here's the lineup of module-level names ๐Ÿงš

  • toil.test.provisioners.clusterScalerTest.logger
  • toil.test.provisioners.clusterScalerTest.c4_8xlarge_preemptible
  • toil.test.provisioners.clusterScalerTest.c4_8xlarge
  • toil.test.provisioners.clusterScalerTest.r3_8xlarge
  • toil.test.provisioners.clusterScalerTest.r5_2xlarge
  • toil.test.provisioners.clusterScalerTest.r5_4xlarge
  • toil.test.provisioners.clusterScalerTest.t2_micro

๐Ÿฆ‹ BinPackingTest

class toil.test.provisioners.clusterScalerTest.BinPackingTest(methodName='runTest')

Bases: toil.test.ToilTest

Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ New tests should be made in the 'pytest' style and not use this class, bestie ๐Ÿ™…โ€โ™€๏ธ

When you run tests, you can optionally set the TOIL_TEST_TEMP environment variable to a directory where you want temp test files to go ๐Ÿ—‚๏ธ It'll get created if it doesn't exist yet. The path can be relative, in which case it's relative to the project root. If TOIL_TEST_TEMP isn't set, temp files and directories go to the system's default temp location, and any leftovers from tests get automatically removed during tear down. If you DO set it, leftover files won't be removed.

setUp()

Hook method for setting up the test fixture before exercising it ๐Ÿง

testPackingOneShape()

Pack one shape and check that the resulting reservations look sane โœจ

testSorting()

Test that sorting is correct: preemptible, then memory, then cores, then disk, then wallTime ๐Ÿ“‹

testAddingInitialNode()

Pack one shape when no nodes are available and confirm that we fit one node properly ๐ŸŒฑ

testLowTargetTime()

Test that a low targetTime (0) parallelizes jobs aggressively (1000 queued jobs require 1000 nodes) ๐Ÿš€

Ideally, low targetTime means: start quickly and maximize parallelization after the cpu/disk/mem have been packed.

Disk/cpu/mem packing is prioritized first, so we set job resource reqs so that each t2.micro (1 cpu/8G disk/1G RAM) can only run one job at a time with its resources.

Each job is parametrized to take 300 seconds, so (the minimum of) 1 of them should fit into each node's 0 second window, so we expect 1000 nodes.

testHighTargetTime()

Test that a high targetTime (3600 seconds) maximizes packing within the targetTime ๐Ÿงฉ

Ideally, high targetTime means: maximize packing within the targetTime after the cpu/disk/mem have been packed.

Disk/cpu/mem packing is prioritized first, so we set job resource reqs so that each t2.micro (1 cpu/8G disk/1G RAM) can only run one job at a time with its resources.

Each job is parametrized to take 300 seconds, so 12 of them should fit into each node's 3600 second window. 1000/12 = 83.33, so we expect 84 nodes.

testZeroResourceJobs()

Test that jobs requiring zero cpu/disk/mem pack first, regardless of targetTime ๐Ÿซง

Disk/cpu/mem packing is prioritized first, so we set job resource reqs so that each t2.micro (1 cpu/8G disk/1G RAM) can run a seemingly infinite number of jobs with its resources.

Since all jobs should pack cpu/disk/mem-wise on a t2.micro, we expect only one t2.micro to be provisioned. If we raise this, as in testLowTargetTime, it will launch 1000 t2.micros.

testLongRunningJobs()

Test that jobs with long run times (especially service jobs) are aggressively parallelized ๐Ÿƒโ€โ™€๏ธ

This is important, because services are one case where the degree of parallelization really, really matters. If you have multiple services, they may all need to be running simultaneously before any real work can be done.

Despite setting globalTargetTime=3600, this should launch 1000 t2.micros because each job's estimated runtime (30000 seconds) extends well beyond 3600 seconds.

run1000JobsOnMicros(jobCores, jobMem, jobDisk, jobTime, globalTargetTime)

Test packing 1000 jobs on t2.micros. Depending on the targetTime and resources, these should pack differently ๐Ÿ“ฆ

testPathologicalCase()

Test a pathological case where only one node can be requested to fit months' worth of jobs ๐Ÿ˜ตโ€๐Ÿ’ซ

If the reservation is extended to fit a long job, and the bin-packer naively searches through all the reservation slices to find the first slice that fits, it will happily assign the first slot that fits the job, even if that slot occurs days in the future.

testJobTooLargeForAllNodes()

If a job is too large for all node types, the scaler should print a warning, but definitely not crash ๐Ÿ™ warning, not a crash

๐Ÿฆ‹ ClusterScalerTest

class toil.test.provisioners.clusterScalerTest.ClusterScalerTest(methodName='runTest')

Bases: toil.test.ToilTest

Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ New tests should be made in the 'pytest' style and not use this class, bestie ๐Ÿ™…โ€โ™€๏ธ

When you run tests, you can optionally set the TOIL_TEST_TEMP environment variable to a directory where you want temp test files to go ๐Ÿ—‚๏ธ It'll get created if it doesn't exist yet. The path can be relative, in which case it's relative to the project root. If TOIL_TEST_TEMP isn't set, temp files and directories go to the system's default temp location, and any leftovers from tests get automatically removed during tear down. If you DO set it, leftover files won't be removed.

setUp()

Hook method for setting up the test fixture before exercising it ๐Ÿง

testRounding()

Test to make sure the ClusterScaler's rounding rounds properly ๐Ÿ”ข

testMaxNodes()

Set the scaler to be very aggressive, give it a ton of jobs, and make sure it doesn't go over maxNodes ๐Ÿ›‘

testMinNodes()

Without any jobs queued, the scaler should still estimate "minNodes" nodes ๐Ÿ˜Œ

testPreemptibleDeficitResponse()

When a preemptible deficit was detected by a previous run of the loop, the scaler should add non-preemptible nodes to compensate in proportion to preemptibleCompensation โš–๏ธ

testPreemptibleDeficitIsSet()

Make sure that updateClusterSize sets the preemptible deficit if it can't launch preemptible nodes properly. That way, the deficit can be communicated to the next run of estimateNodeCount ๐Ÿ“จ

testNoLaunchingIfDeltaAlreadyMet()

Check that the scaler doesn't try to launch "0" more instances if the delta was able to be met by unignoring nodes ๐Ÿ™…โ€โ™€๏ธ no need to launch zero more

testBetaInertia()

No description for this one, it's a mystery ๐Ÿ™ˆ

test_overhead_accounting_large()

If a node has a certain raw memory or disk capacity, that won't all be available when it actually comes up; some disk and memory will be used by the OS, and the backing scheduler (Mesos, Kubernetes, etc.) ๐Ÿงฎ

Make sure this overhead is accounted for for large nodes ๐Ÿ˜

test_overhead_accounting_small()

If a node has a certain raw memory or disk capacity, that won't all be available when it actually comes up; some disk and memory will be used by the OS, and the backing scheduler (Mesos, Kubernetes, etc.) ๐Ÿงฎ

Make sure this overhead is accounted for for small nodes ๐Ÿญ

test_overhead_accounting_observed()

If a node has a certain raw memory or disk capacity, that won't all be available when it actually comes up; some disk and memory will be used by the OS, and the backing scheduler (Mesos, Kubernetes, etc.) ๐Ÿงฎ

Make sure this overhead is accounted for so that real-world observed failures cannot happen again ๐Ÿ”’

๐Ÿฆ‹ ScalerThreadTest

class toil.test.provisioners.clusterScalerTest.ScalerThreadTest(methodName='runTest')

Bases: toil.test.ToilTest

Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ New tests should be made in the 'pytest' style and not use this class, bestie ๐Ÿ™…โ€โ™€๏ธ

okay bestie, so when you run tests you can optionally set the TOIL_TEST_TEMP environment variable ๐Ÿ’… to a path where your temporary test files should live. if that directory doesn't exist yet, it gets created for you ๐Ÿงš. the path can be relative, and if it is, it's measured from the project root ๐ŸŒธ. if TOIL_TEST_TEMP isn't defined, temp files and dirs go to the system's default spot for that stuff, and any leftover temp files or directories from tests get automatically removed during tear down โœจ. but if you do set it, leftover files stick around and don't get removed ๐Ÿ˜ญ

  • testClusterScaling() โ€” tests scaling for a batch of non-preemptible jobs and no preemptible jobs (makes debugging easier ๐Ÿ›)
  • testClusterScalingMultipleNodeTypes() ๐Ÿฆ‹
  • testClusterScalingWithPreemptibleJobs() โ€” tests scaling at the same time for a batch of preemptible and non-preemptible jobs ๐Ÿ‘‘

class toil.test.provisioners.clusterScalerTest.MockBatchSystemAndProvisioner(config, secondsPerJob)

Bases: toil.batchSystems.abstractBatchSystem.AbstractScalableBatchSystem, toil.provisioners.abstractProvisioner.AbstractProvisioner

this class is giving multitasking ๐Ÿ’œ it mimics a leader, job batcher, provisioner and scalable batch system all at once, and it's honestly iconic for it ๐Ÿ”ฅ

Attributes:

  • config
  • secondsPerJob
  • provisioner
  • batchSystem
  • jobQueue
  • updatedJobsQueue
  • jobBatchSystemIDToIssuedJob
  • totalJobs = 0
  • totalWorkerTime = 0.0
  • toilMetrics = None
  • nodesToWorker
  • workers
  • maxWorkers
  • running = False
  • leaderThread
  • toilState

Methods:

  • start() ๐ŸŒˆ
  • shutDown() ๐Ÿฅ€
  • nodeInUse(nodeIP) โ€” ngl this one is so useful. it can tell you if a worker node is running any tasks. if the node doesn't exist, it just returns False ๐Ÿ™ˆ
    • Parameters: nodeIP โ€” the worker node's private IP address
    • Returns: True if the worker node has been issued any tasks, else False
  • ignoreNode(nodeAddress) โ€” stop sending jobs to this node. this is used in autoscaling when the autoscaler is ready to terminate a node but jobs are still running. it lets the node get terminated once the current jobs finish ๐Ÿซถ
    • Parameters: nodeAddress โ€” IP address of node to ignore
  • unignoreNode(nodeAddress) โ€” stop ignoring this address, presumably after a node with this address got terminated. this way a brand new node can have the same address as a terminated one, which is kinda wild ๐ŸŒธ
  • supportedClusterTypes() โ€” get all the cluster types this provisioner implementation supports โœจ
  • createClusterSettings() โ€” initialize the class for a new cluster that's going to be deployed when you're running outside the cloud ๐ŸŒ
  • readClusterSettings() โ€” initialize the class from an existing cluster. this method assumes the instance we're running on is the leader ๐Ÿ‘‘. implementations must call _setLeaderWorkerAuthentication()
  • setAutoscaledNodeTypes(node_types) โ€” sets node types, shapes and spot bids for Toil-managed autoscaling ๐Ÿ’… :param nodeTypes: A list of node types, as parsed with parse_node_types.
    • Parameters: node_types (list[tuple[set[toil.provisioners.abstractProvisioner.Shape], Optional[float]]])
  • getProvisionedWorkers(instance_type=None, preemptible=None) โ€” returns a list of Node objects, each one representing a worker node in the cluster ๐Ÿงš
    • Parameters: preemptible โ€” if True, only return preemptible nodes, else return non-preemptible nodes
    • Returns: list of Node
  • terminateNodes(nodes) โ€” terminates the nodes represented by the given Node objects ๐Ÿ’€
    • Parameters: nodes โ€” list of Node objects
  • remainingBillingInterval(node) โณ
  • addJob(jobShape, preemptible=False) โ€” adds a job to the job queue ๐Ÿ“
  • getNumberOfJobsIssued(preemptible=None) ๐Ÿ”ข
  • getJobs() ๐Ÿ“‹
  • getNodes(preemptible=False, timeout=600) โ€” returns a dictionary mapping node identifiers of preemptible or non-preemptible nodes to NodeInfo objects, one for each node ๐Ÿฆ‹
    • Parameters:
      • preemptible (Optional[bool]) โ€” if True (False), only (non-)preemptible nodes will be returned. if None, all nodes will be returned
      • timeout (int)
  • addNodes(nodeTypes, numNodes, preemptible) โ€” used to add worker nodes to the cluster ๐Ÿš€
    • Parameters:
      • numNodes โ€” the number of nodes to add
      • preemptible โ€” whether or not the nodes will be preemptible
      • spotBid โ€” the bid for preemptible nodes if applicable (this can be set in config, also)
      • nodeTypes (set[str])
    • Returns: number of nodes successfully added
    • Return type: int
  • getNodeShape(nodeType, preemptible=False) โ€” the shape of a preemptible or non-preemptible node managed by this provisioner. the node shape defines key properties of a machine, like its number of cores or the time between billing intervals ๐Ÿง 
    • Parameters: instance_type (str) โ€” instance type name to return the shape of
  • getWorkersInCluster(nodeShape) ๐Ÿ‘ฏ
  • launchCluster(leaderNodeType, keyName, userTags=None, vpcSubnet=None, leaderStorage=50, nodeStorage=50, botoPath=None, **kwargs) โ€” initializes a cluster and creates a leader node ๐ŸŽ€. implementations must call _setLeaderWorkerAuthentication() with the leader so workers can be launched
    • Parameters:
      • leaderNodeType โ€” the leader instance
      • leaderStorage โ€” the amount of disk to allocate to the leader in gigabytes
      • owner โ€” tag identifying the owner of the instances
  • destroyCluster() โ€” terminates all nodes in the specified cluster and cleans up every resource associated with it ๐Ÿงน :param clusterName: identifier of the cluster to terminate.
    • Return type: None
  • getLeader() ๐Ÿ‘‘
    • Returns: the leader node
  • getNumberOfNodes(nodeType=None, preemptible=None) ๐Ÿ”ข

toil.test.provisioners.clusterTest

Attributes

                                     โ”Œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”
                                     โ”‚ log โ”‚   โ”‚
                                     โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜

Classes

                 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                 โ”‚ AbstractClusterTest โ”‚ Legacy common base class โ”‚
                 โ”‚                     โ”‚ for Toil tests.          โ”‚
                 โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
                 โ”‚ CWLOnARMTest        โ”‚ Run the CWL 1.2          โ”‚
                 โ”‚                     โ”‚ conformance tests on ARM โ”‚
                 โ”‚                     โ”‚ specifically.            โ”‚
                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Module Contents

  • toil.test.provisioners.clusterTest.log ๐Ÿ“

class toil.test.provisioners.clusterTest.AbstractClusterTest(methodName)

Bases: toil.test.ToilTest

this is the legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ new tests should be written in the 'pytest' style and not use this class, bestie ๐Ÿ™…โ€โ™€๏ธ

when running tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files placed. the directory gets created if it doesn't exist. the path may be relative, in which case it's assumed to be relative to the project root ๐ŸŒธ. if TOIL_TEST_TEMP isn't defined, temp files and directories get created in the system's default location, and any temporary files or directories left over from tests get automatically removed during tear down. otherwise, left-over files will not be removed ๐Ÿงผ

Parameters:

  • methodName (str)

Attributes:

  • keyName
  • clusterName = 'aws-provisioner-test-Instance of uuid.UUID' ๐Ÿฆ„
  • leaderNodeType = 't2.medium' ๐Ÿ’ป
  • clusterType = 'mesos' ๐ŸŒต
  • zone
  • region ๐ŸŒ

aws ๐Ÿฆ‹ okay so we're still in the AWS testing stuff, bestie, and this is where the good bits are ๐Ÿ’…

  • venvDir = '/tmp/venv' โ€” the venv lives in /tmp/venv ๐Ÿงš

python()

Grab the full path to the venv Python on the leader ๐Ÿโœจ

Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

pip()

Same energy, but this time you get the full path to the venv pip on the leader ๐ŸŒธ

Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

destroyCluster()

Destroys the cluster we built, if it exists ๐Ÿ’€ And if it's already gone? It still counts as a success, so no drama ๐Ÿซถ

Return type: None

setUp()

Sets up the test. You must override this and call this method, and you also have to set self.jobStore or it's not it ๐Ÿ”ฅ

Return type: None

tearDown()

Hook method for cleaning up the test fixture after testing it. Clean up after yourself, besties ๐Ÿงน

Return type: None

sshUtil(command)

Runs the command you give it on the cluster. If it fails, you'll get a subprocess.CalledProcessError raised at you ๐Ÿ˜ญ

Parameters:

  • command (list[str], docs: /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None

rsync_util(from_file, to_file)

Transfers a file to or from the cluster ๐Ÿ“ฆ Heads up: the cluster-side path needs a : in front of it, so don't forget it, bestie ๐Ÿ™ˆ

Parameters:

  • from_file (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • to_file (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None

createClusterUtil(args=None)

Parameters:

  • args (Optional[list[str]], docs: /usr/share/doc/python3/html/library/stdtypes.html#list and /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: None

launchCluster()

Launches the cluster ๐Ÿš€ It's giving "ready to go."

Return type: None


class toil.test.provisioners.clusterTest.CWLOnARMTest(methodName)

Bases: AbstractClusterTest ๐Ÿ‘‘

Runs the CWL 1.2 conformance tests on ARM specifically. The ARM check is the whole main character moment ๐Ÿฆ‹

Parameters:

  • methodName (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

Attributes:

  • clusterName = 'cwl-test-Instance of uuid.UUID'
  • leaderNodeType = 't4g.2xlarge'
  • clusterType = 'kubernetes'
  • cwl_test_dir = '/tmp/toil/cwlTests'

setUp()

Sets up the test. Like before, you must override it, call this method, and set self.jobStore ๐Ÿซถ

Return type: None

test_cwl_on_arm()

Return type: None


toil.test.provisioners.gceProvisionerTest

Attributes

  • log โœจ

Classes

  • AbstractGCEAutoscaleTest โ€” legacy common base class for Toil tests ๐Ÿง
  • GCEAutoscaleTest โ€” legacy common base class for Toil tests ๐Ÿง
  • GCEStaticAutoscaleTest โ€” runs the tests on a statically provisioned cluster with autoscaling enabled โšก
  • GCEAutoscaleTestMultipleNodeTypes โ€” legacy common base class for Toil tests ๐Ÿง
  • GCERestartTest โ€” this test makes sure autoscaling works on a restarted Toil run ๐Ÿ”

Module Contents

  • toil.test.provisioners.gceProvisionerTest.log

class toil.test.provisioners.gceProvisionerTest.AbstractGCEAutoscaleTest(methodName)

Bases: toil.test.ToilTest ๐Ÿ’œ

Legacy common base class for Toil tests. Okay, real talk: new tests should be made in the pytest style and not use this class, so don't build on it ๐Ÿ™…โ€โ™€๏ธ

Now, the TOIL_TEST_TEMP environment variable is optional, and you can set it to the path of a directory where you want your temporary test files to go ๐ŸŒท If the directory doesn't exist, it gets created for you. The path can be relative, in which case it's relative to the project root. If TOIL_TEST_TEMP isn't defined, temporary files and directories go in the system's default location, and anything left over from the tests gets removed automatically during tear down ๐Ÿงน If you did set it, though, leftover files stay put and won't be removed.

Attributes:

  • projectID
  • sshUtil(command)
  • rsyncUtil(src, dest)
  • destroyClusterUtil()
  • createClusterUtil(args=None)
  • cleanJobStoreUtil()
  • keyName
  • botoDir
  • googleZone = 'us-west1-a'
  • leaderInstanceType = 'n1-standard-1'
  • instanceTypes = ['n1-standard-2']
  • numWorkers = ['2']
  • numSamples = 2
  • spotBid = 0.15
  • setUp() โ€” hook method for setting up the test fixture before exercising it ๐ŸŒˆ
  • tearDown() โ€” hook method for deconstructing the test fixture after testing it ๐Ÿงผ
  • launchCluster() ๐Ÿš€

class toil.test.provisioners.gceProvisionerTest.GCEAutoscaleTest(name)

Bases: AbstractGCEAutoscaleTest ๐Ÿ’–

Legacy common base class for Toil tests. Same rule as before: new tests should be made in the pytest style and not use this class ๐Ÿ™…โ€โ™€๏ธ

Same TOIL_TEST_TEMP tea as above: it's optional, it can point at a directory you want for temp test files, and the directory gets created if it's missing. Relative paths count as relative to the project root. If TOIL_TEST_TEMP isn't defined, temp files and directories go to the system's default spot and get removed automatically during tear down. If you set it, left-over files will not be removed.

Attributes:

  • clusterName = 'provisioner-test-'
  • requestedLeaderStorage = 80
  • setUp() โ€” hook method for setting up the test fixture before exercising it ๐ŸŒธ
  • launchCluster() ๐Ÿš€
  • testAutoScale() โญ
  • testSpotAutoScale() โญ

class toil.test.provisioners.gceProvisionerTest.GCEStaticAutoscaleTest(name)

Bases: GCEAutoscaleTest ๐Ÿ‘‘

Runs the tests on a statically provisioned cluster with autoscaling enabled. It's giving static but make it autoscale ๐Ÿ˜ค

Attributes:

  • requestedNodeStorage = 20
  • launchCluster() ๐Ÿš€

class toil.test.provisioners.gceProvisionerTest.GCEAutoscaleTestMultipleNodeTypes(name)

Bases: AbstractGCEAutoscaleTest ๐Ÿง

Legacy common base class for Toil tests. Reminder, bestie: new tests should be made in the pytest style and not use this class ๐Ÿ™…โ€โ™€๏ธ

The TOIL_TEST_TEMP variable is optional. Point it at a directory for temp test files and it gets created if needed. Relative paths are relative to the project root. If you leave TOIL_TEST_TEMP undefined, temp files and directories go to the system's default location and get removed automatically during tear down. If you set it, left-over files won't be removed ๐Ÿซง

Attributes:

  • clusterName = 'provisioner-test-'
  • setUp() โ€” hook method for setting up the test fixture before exercising it ๐ŸŒˆ
  • testAutoScale() โญ

class toil.test.provisioners.gceProvisionerTest.GCERestartTest(name)

Bases: AbstractGCEAutoscaleTest ๐Ÿ”

This test makes sure autoscaling works on a restarted Toil run. Restarts are a whole mood, and this one checks that it still scales ๐Ÿ™Œ

Attributes:

  • clusterName = 'restart-test-'
  • setUp() โ€” hook method for setting up the test fixture before exercising it ๐ŸŒธ
  • testAutoScaledCluster() โญ

toil.test.provisioners.provisionerTest

Attributes

  • log ๐Ÿฆ‹

Okay so the ProvisionerTest class is a legacy common base class for Toil tests ๐Ÿงš ngl, it's giving old school. New tests should be made in the pytest style and not use this class ๐Ÿ™ˆ

โœจ Module Contents โœจ

  • toil.test.provisioners.provisionerTest.log ๐Ÿฆ‹

๐Ÿ’– ProvisionerTest

class toil.test.provisioners.provisionerTest.ProvisionerTest(methodName='runTest')

Bases: toil.test.ToilTest ๐ŸŒˆ

Legacy common base class for Toil tests. Bestie, reminder: new tests go in the pytest style, not this class ๐Ÿ’…

When you run tests you can optionally set the TOIL_TEST_TEMP environment variable to a directory path where you want temporary test files to live ๐Ÿซถ The directory gets created if it doesn't exist yet. The path can be relative, and if it is, it's assumed to be relative to the project root. If TOIL_TEST_TEMP isn't defined, temporary files and directories get created in the system's default location for that stuff, and any leftovers from tests get removed automatically during tear down. Otherwise, left-over files will not be removed ๐Ÿ˜ญ

  • test_node_type_parsing() ๐Ÿ“
    • Return type: None

๐Ÿงš toil.test.provisioners.restartScript

๐ŸŒธ Attributes

  • parser (no description attached) ๐Ÿฆ‹

๐ŸŒธ Functions

  • f0(job) (no description attached) ๐Ÿฆ‹

โœจ Module Contents โœจ

  • toil.test.provisioners.restartScript.f0(job)
  • toil.test.provisioners.restartScript.parser

๐ŸŒˆ toil.test.server

๐ŸŽ€ Submodules

  • toil.test.server.serverTest

๐ŸŒˆ toil.test.server.serverTest

๐Ÿ’œ Attributes

  • logger ๐Ÿฆ‹

๐Ÿ’œ Classes

  • ToilServerUtilsTest โ€” tests for the utility functions used by the Toil server ๐Ÿ”ฅ
  • hidden โ€” no description attached, but it holds some nested test classes, see below ๐Ÿ™ˆ
  • FileStateStoreTest โ€” test file-based state storage ๐Ÿ’–
  • FileStateStoreURLTest โ€” test file-based state storage using URLs instead of local paths ๐ŸŒธ
  • BucketUsingTest โ€” base class for tests that need a bucket ๐Ÿชฃ
  • AWSStateStoreTest โ€” test AWS-based state storage โ˜๏ธ
  • TrueDict โ€” dict that is truthy even when empty ๐Ÿ‘‘
  • AbstractToilWESServerTest โ€” class for server tests that provides a self.app in testing mode โœจ
  • ToilWESServerBenchTest โ€” tests for Toil's Workflow Execution Service API that don't run workflows โญ
  • ToilWESServerWorkflowTest โ€” tests of the WES server running workflows ๐Ÿƒโ€โ™€๏ธ
  • ToilWESServerCeleryWorkflowTest โ€” end-to-end workflow-running tests against Celery ๐Ÿฅฌ
  • ToilWESServerCeleryS3StateWorkflowTest โ€” test the server with Celery and state stored in S3 ๐Ÿง

๐Ÿ’œ Module Contents

  • toil.test.server.serverTest.logger ๐Ÿฆ‹

๐Ÿ’– ToilServerUtilsTest

class toil.test.server.serverTest.ToilServerUtilsTest(methodName='runTest')

Bases: toil.test.ToilTest ๐ŸŒˆ

Tests for the utility functions used by the Toil server ๐Ÿ”ฅ

  • test_workflow_canceling_recovery() ๐Ÿ“
    • Make sure that a workflow in CANCELING state will be recovered to a terminal state eventually, even if the workflow runner Celery task goes away without flipping the state. No cap, this one is important ๐Ÿ˜ญ

๐Ÿ’– hidden

This one's a container, bestie. It holds the classes below ๐Ÿงš

๐Ÿฆ‹ AbstractStateStoreTest

class AbstractStateStoreTest(methodName='runTest')

Bases: toil.test.ToilTest ๐ŸŒˆ

Basic tests for state stores ๐Ÿ’…

  • get_state_store() (abstract method) ๐ŸŒธ
    • Make a state store to test, on a single fixed URL.
    • Return type: AbstractStateStore (toil.server.utils.AbstractStateStore)
  • test_state_store() ๐ŸŒธ
    • Make sure that the state store under test can store and load keys.
    • Return type: None

๐Ÿ’– FileStateStoreTest

class toil.test.server.serverTest.FileStateStoreTest(methodName='runTest')

Bases: hidden ๐ŸŒˆ

Test file-based state storage ๐Ÿ’–

  • setUp() ๐Ÿซถ
    • Hook method for setting up the test fixture before exercising it.
    • Return type: None
  • get_state_store() ๐Ÿซถ
    • Make a state store to test, on a single fixed local path.
    • Return type: AbstractStateStore (toil.server.utils.AbstractStateStore)

๐Ÿ’– FileStateStoreURLTest

class toil.test.server.serverTest.FileStateStoreURLTest(methodName='runTest')

Bases: hidden ๐ŸŒˆ

Test file-based state storage using URLs instead of local paths ๐ŸŒธ

  • setUp() ๐Ÿซถ
    • Hook method for setting up the test fixture before exercising it.
    • Return type: None
  • get_state_store() ๐Ÿซถ
    • Make a state store to test, on a single fixed URL.
    • Return type: AbstractStateStore (toil.server.utils.AbstractStateStore)

๐Ÿ’– BucketUsingTest

class toil.test.server.serverTest.BucketUsingTest(methodName='runTest')

Bases: toil.test.ToilTest ๐ŸŒˆ

Base class for tests that need a bucket ๐Ÿชฃ

  • region (str | None) ๐Ÿฆ‹
  • s3_resource (mypy_boto3_s3.S3ServiceResource | None) ๐Ÿฆ‹
  • bucket (mypy_boto3_s3.service_resource.Bucket | None) ๐Ÿฆ‹
  • bucket_name (str | None) ๐Ÿฆ‹
  • setUpClass() (classmethod) ๐Ÿ”ฅ
    • Set up the class with a single pre-existing AWS bucket for all tests.
    • Return type: None
  • tearDownClass() (classmethod) ๐Ÿ”ฅ
    • Hook method for deconstructing the class fixture after running all tests in the class.
    • Return type: None

๐ŸŽ€ class toil.test.server.serverTest.AWSStateStoreTest(methodName='runTest')

Bases: hidden, BucketUsingTest ๐Ÿ’…

Okay so this is the test class for AWS-based state storage โ˜๏ธโœจ. It's literally checking that the state store works on AWS, no cap.

The class attribute is bucket_path = 'prefix/of/keys' ๐ŸŒธ. That's the little prefix all the keys hang out under.

get_state_store()

Makes a state store to test, on a single fixed URL ๐Ÿ”—.

Return type: AbstractStateStore (#toil.server.utils.AbstractStateStore) ๐Ÿ’–

test_state_store_paths()

Makes sure the S3 state store puts things in the right places ๐Ÿ“ฆ. We don't really care about the exact internal structure, but we do care that everything is actually under the path we're supposed to use ๐Ÿซถ.

Return type: None


๐Ÿฆ‹ class toil.test.server.serverTest.TrueDict

Bases: dict (/usr/share/doc/python3/html/library/stdtypes.html#dict)

This is a dict that is truthy even when empty ๐Ÿ‘‘. It's a workaround to set httpx post request encoding, as recommended in https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 ๐Ÿงš.

__bool__()

Always says the object is truthy. Iconic behaviour ๐Ÿ’….

Return type: bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐ŸŒˆ class toil.test.server.serverTest.AbstractToilWESServerTest(*args, **kwargs)

Bases: toil.test.ToilTest (#toil.test.ToilTest)

This is the base class for server tests, and it gives you a self.app in testing mode ๐ŸŽ€.

setUp()

Hook method for setting up the test fixture before exercising it โœจ.

Return type: None

tearDown()

Hook method for deconstructing the test fixture after testing it ๐Ÿงน.

Return type: None


โญ class toil.test.server.serverTest.ToilWESServerBenchTest(*args, **kwargs)

Bases: AbstractToilWESServerTest

These are tests for Toil's Workflow Execution Service API that don't run workflows ๐Ÿƒ. Low-key a chill vibe.

test_home()

Tests the homepage endpoint ๐Ÿ .

Return type: None

test_health()

Tests the health check endpoint ๐Ÿซ€.

Return type: None

test_get_service_info()

Tests the GET /service-info endpoint ๐Ÿ’โ€โ™€๏ธ.

Return type: None


๐Ÿ“ class toil.test.server.serverTest.ToilWESServerWorkflowTest(*args, **kwargs)

Bases: AbstractToilWESServerTest

These are the tests of the WES server actually running workflows ๐Ÿ”ฅ.

run_zip_workflow(zip_path, include_message=True, include_params=True)

We have several zip file tests, so this helper submits a zip file and makes sure it ran OK ๐Ÿ“ฆโœ….

If include_message is set to False, don't send a "message" argument in workflow_params. If include_params is also set to False, don't send workflow_params at all ๐Ÿ™ˆ.

Parameters:

  • zip_path (str (/usr/share/doc/python3/html/library/stdtypes.html#str))
  • include_message (bool (/usr/share/doc/python3/html/library/functions.html#bool))
  • include_params (bool (/usr/share/doc/python3/html/library/functions.html#bool))

Return type: None

test_run_workflow_relative_url_no_attachments_fails()

Runs the example CWL workflow from a relative workflow URL, but with no attachments. This one is supposed to fail, bestie ๐Ÿ’€.

Return type: None

test_run_workflow_relative_url()

Runs the example CWL workflow from a relative workflow URL ๐Ÿ”—.

Return type: None

test_run_workflow_https_url()

Runs the example CWL workflow from the Internet ๐ŸŒ.

Return type: None

test_run_workflow_single_file_zip()

Runs the example CWL workflow from a single-file ZIP ๐Ÿค.

Return type: None

test_run_workflow_multi_file_zip()

Runs the example CWL workflow from a multi-file ZIP ๐Ÿ—‚๏ธ.

Return type: None

test_run_workflow_manifest_zip()

Runs the example CWL workflow from a ZIP with a manifest ๐Ÿ“œ.

Return type: None

test_run_workflow_inputs_zip()

Runs the example CWL workflow from a ZIP without a manifest, but with inputs ๐ŸŽ.

Return type: None

test_run_workflow_manifest_and_inputs_zip()

Runs the example CWL workflow from a ZIP with a manifest and inputs ๐Ÿ‘‘.

Return type: None

test_run_workflow_no_params_zip()

Runs the example CWL workflow from a ZIP without workflow_params ๐Ÿซฅ.

Return type: None

test_run_and_cancel_workflows()

Runs two workflows, cancels one of them, and makes sure they all exist ๐Ÿšซโœจ.

Return type: None


๐Ÿงš class toil.test.server.serverTest.ToilWESServerCeleryWorkflowTest(*args, **kwargs)

Bases: ToilWESServerWorkflowTest

These are end-to-end workflow-running tests against Celery ๐Ÿฅ•โšก.


๐Ÿ’œ class toil.test.server.serverTest.ToilWESServerCeleryS3StateWorkflowTest(*args, **kwargs)

Bases: ToilWESServerWorkflowTest, BucketUsingTest

This tests the server with Celery and its state stored in S3 โ˜๏ธ๐Ÿ’œ.

setUp()

Hook method for setting up the test fixture before exercising it ๐ŸŒท.

Return type: None


๐ŸŒธ toil.test.sort

๐Ÿง Submodules

๐Ÿซง toil.test.sort.restart_sort

A demonstration of toil! It sorts the lines of a file into ascending order by doing a parallel merge sort ๐Ÿ”€.

bestie, this one is intentionally buggy ๐Ÿ’€. It doesn't include restart() on purpose, for testing purposes.

๐ŸŽ€ Attributes

  • defaultLines
  • defaultLineLen
  • sortMemory

๐Ÿ› ๏ธ Functions

  • setup(job, inputFile, N, downCheckpoints, options) โ€” Sets up the sort ๐Ÿ—๏ธ.
  • down(job, inputFileStoreID, N, path, downCheckpoints, ...) โ€” Input is a file, a subdivision size N, and a path in the hierarchy of jobs ๐Ÿชœ.
  • up(job, inputFileID1, inputFileID2, path, options[, ...]) โ€” Merges the two files and places them in the output ๐Ÿซถ.
  • sort(file) โ€” Sorts the given file ๐Ÿ”ค.
  • merge(fileHandle1, fileHandle2, outputFileHandle) โ€” Merges together two files while keeping sorted order ๐Ÿ“š.
  • copySubRangeOfFile(inputFile, fileStart, fileEnd) โ€” Copies the range (in bytes) between fileStart and fileEnd to the given (the description got cut off in the source, bestie ๐Ÿ™ˆ).
  • getMidPoint(file, fileStart, fileEnd) โ€” Finds the point in the file to split โœ‚๏ธ.
  • makeFileToSort(fileName[, lines, lineLen]) โ€” No description given ๐Ÿคทโ€โ™€๏ธ.
  • main([options]) โ€” No description given ๐Ÿคทโ€โ™€๏ธ.

๐Ÿ“ฆ Module Contents

toil.test.sort.restart_sort.defaultLines = 1000
toil.test.sort.restart_sort.defaultLineLen = 50
toil.test.sort.restart_sort.sortMemory = '600M'
toil.test.sort.restart_sort.setup(job, inputFile, N, downCheckpoints, options)

Sets up the sort. Returns the FileID of the sorted file ๐ŸŽ‰.

  • toil.test.sort.restart_sort.down(job, inputFileStoreID, N, path, downCheckpoints, options, memory=sortMemory) โ€” okay bestie, this one takes a file, a subdivision size N, and a path through the hierarchy of jobs ๐ŸŒณ. If the range is bigger than the threshold N, it gets split recursively and a follow-on job is created to merge everything back together. Otherwise it just sorts the file and drops it into the output ๐Ÿ’…
  • toil.test.sort.restart_sort.up(job, inputFileID1, inputFileID2, path, options, memory=sortMemory) โ€” merges the two files and places the result in the output ๐Ÿซถ
  • toil.test.sort.restart_sort.sort(file) โ€” sorts the given file ๐Ÿงน
  • toil.test.sort.restart_sort.merge(fileHandle1, fileHandle2, outputFileHandle) โ€” squishes two files together while keeping them in sorted order ๐ŸŽ€
โš ๏ธ Bestie, every handle here has to be a text-mode stream. No exceptions. ๐Ÿ™…
  • toil.test.sort.restart_sort.copySubRangeOfFile(inputFile, fileStart, fileEnd) โ€” copies the bytes between fileStart and fileEnd into the output file handle you give it ๐Ÿ“‹
  • toil.test.sort.restart_sort.getMidPoint(file, fileStart, fileEnd) โ€” finds the spot in the file where it should get split โœ‚๏ธ It hands back an int called i where fileStart <= i < fileEnd โœจ
  • toil.test.sort.restart_sort.makeFileToSort(fileName, lines=defaultLines, lineLen=defaultLineLen) โ€” no description given for this one ๐Ÿ™ˆ
  • toil.test.sort.restart_sort.main(options=None) โ€” no description given for this one ๐Ÿ™ˆ

toil.test.sort.sort

A demonstration of toil ๐ŸŽ€ It sorts the lines of a file into ascending order by doing a parallel merge sort ๐Ÿ’œ

Attributes

  • defaultLines โ€” no notes on this one ๐Ÿคท
  • defaultLineLen โ€” no notes on this one ๐Ÿคท
  • sortMemory โ€” no notes on this one ๐Ÿคท

Functions

  • setup(job, inputFile, N, downCheckpoints, options) โ€” sets up the sort ๐ŸŒธ
  • down(job, inputFileStoreID, N, path, downCheckpoints, ...) โ€” takes a file, a subdivision size N, and a path in the hierarchy of jobs ๐ŸŒณ If the range is larger than N, it divides recursively and creates a follow-on job to merge the results back. Otherwise it sorts the file and places it in the output ๐Ÿ’…
  • up(job, inputFileID1, inputFileID2, path, options[, ...]) โ€” merges the two files and places them in the output ๐Ÿซถ
  • sort(file) โ€” sorts the given file ๐Ÿงน
  • merge(fileHandle1, fileHandle2, outputFileHandle) โ€” merges two files together while keeping sorted order ๐ŸŽ€
  • copySubRangeOfFile(inputFile, fileStart, fileEnd) โ€” copies the bytes between fileStart and fileEnd to the given output file handle ๐Ÿ“‹
  • getMidPoint(file, fileStart, fileEnd) โ€” finds the point in the file to split โœ‚๏ธ
  • makeFileToSort(fileName[, lines, lineLen]) โ€” no description given ๐Ÿ™ˆ
  • main([options]) โ€” no description given ๐Ÿ™ˆ

Module Contents

  • toil.test.sort.sort.defaultLines = 1000 ๐Ÿ”ข
  • toil.test.sort.sort.defaultLineLen = 50 ๐Ÿ”ข
  • toil.test.sort.sort.sortMemory = '600M' ๐Ÿ’พ
  • toil.test.sort.sort.setup(job, inputFile, N, downCheckpoints, options) โ€” gets the sort set up and hands back the FileID of the sorted file ๐ŸŽ‰
  • toil.test.sort.sort.down(job, inputFileStoreID, N, path, downCheckpoints, options, memory=sortMemory) โ€” takes a file, a subdivision size N, and a path in the hierarchy of jobs ๐ŸŒณ If the range is larger than the threshold N, it gets divided recursively and a follow-on job is created to merge the results back. Otherwise the file is sorted and placed in the output ๐Ÿ’…
  • toil.test.sort.sort.up(job, inputFileID1, inputFileID2, path, options, memory=sortMemory) โ€” merges the two files and places them in the output ๐Ÿซถ
  • toil.test.sort.sort.sort(file) โ€” sorts the given file ๐Ÿงน
  • toil.test.sort.sort.merge(fileHandle1, fileHandle2, outputFileHandle) โ€” merges two files together while keeping sorted order ๐ŸŽ€
โš ๏ธ All handles must be text-mode streams. ๐Ÿ™…
  • toil.test.sort.sort.copySubRangeOfFile(inputFile, fileStart, fileEnd) โ€” copies the bytes between fileStart and fileEnd into the given output file handle ๐Ÿ“‹
  • toil.test.sort.sort.getMidPoint(file, fileStart, fileEnd) โ€” finds the point in the file to split โœ‚๏ธ It returns an int i where fileStart <= i < fileEnd โœจ
  • toil.test.sort.sort.makeFileToSort(fileName, lines=defaultLines, lineLen=defaultLineLen) ๐Ÿ“

Parameters

  • fileName (toil.lib.misc.StrPath)
  • lines (int)
  • lineLen (int)

Return type: None

  • toil.test.sort.sort.main(options=None) โ€” no description given ๐Ÿ™ˆ

toil.test.sortTest

Attributes

  • logger โ€” no notes on this one ๐Ÿคท
  • defaultLineLen โ€” no notes on this one ๐Ÿคท
  • defaultLines โ€” no notes on this one ๐Ÿคท
  • defaultN โ€” no notes on this one ๐Ÿคท

Classes

  • SortTest โ€” tests Toil by sorting a file in parallel across various combinations of job stores and batch systems ๐Ÿงช

Functions

  • runMain(options) โ€” makes sure the output file gets deleted every single time main is run ๐Ÿงน

Module Contents

  • toil.test.sort.sortTest.logger ๐Ÿ“ฃ
  • toil.test.sort.sortTest.defaultLineLen ๐Ÿ”ข
  • toil.test.sort.sortTest.defaultLines ๐Ÿ”ข
  • toil.test.sort.sortTest.defaultN ๐Ÿ”ข
  • toil.test.sort.sortTest.runMain(options) โ€” makes sure the output file is deleted every time main is run ๐Ÿงน
  • class toil.test.sort.sortTest.SortTest(methodName='runTest') ๐Ÿ’…

Bases: toil.test.ToilTest, toil.batchSystems.mesos.test.MesosTestSupport

Tests Toil by sorting a file in parallel on various combinations of job stores and batch systems ๐Ÿงช

  • setUp() โ€” hook method for setting up the test fixture before exercising it ๐Ÿ› ๏ธ
  • tearDown() โ€” hook method for deconstructing the test fixture after testing it ๐Ÿงผ
  • testAwsSingle() ๐Ÿฆ‹
  • testAwsMesos() ๐Ÿฆ‹
  • testFileMesos() ๐Ÿฆ‹
  • testGoogleSingle() ๐Ÿฆ‹
  • testGoogleMesos() ๐Ÿฆ‹
  • testFileSingle() ๐Ÿฆ‹
  • testFileSingleNonCaching() ๐Ÿฆ‹
  • testFileSingleCheckpoints() ๐Ÿฆ‹
  • testFileSingle10000() ๐Ÿฆ‹
  • testFileGridEngine() ๐Ÿฆ‹
  • testFileTorqueEngine() ๐Ÿฆ‹
  • testNo = 5 ๐Ÿ”ข
  • testSort() ๐Ÿฆ‹
  • testMerge() ๐Ÿฆ‹
  • testCopySubRangeOfFile() ๐Ÿฆ‹
  • testGetMidPoint() ๐Ÿฆ‹

toil.test.src

Submodules

toil.test.src.autoDeploymentTest

Attributes

  • logger โ€” no notes on this one ๐Ÿคท

๐Ÿ’– Classes ๐Ÿ’–

  • AutoDeploymentTest โ€” bestie, this one is the queen of auto-deployment tests ๐Ÿ‘‘ It runs a bunch of different scenarios using the appliance, i.e. a docker container ๐Ÿณ

โœจ Module Contents โœจ

  • toil.test.src.autoDeploymentTest.logger โ€” the logger for this module ๐Ÿ“
class toil.test.src.autoDeploymentTest.AutoDeploymentTest(methodName='runTest')

Bases: toil.test.ApplianceTestSupport

okay so this class tests all the auto-deployment scenarios ๐Ÿ’… Using the appliance (a docker container) lets worker processes run on the same node as the leader process, while keeping their file systems separate from each other and from the leader ๐Ÿซถ Separate file systems are crucial here, because that's how we prove auto-deployment is actually doing its job ๐Ÿ”ฅ

  • setUp() โ€” the hook method that sets up the test fixture before we exercise it ๐Ÿงš
  • sitePackages โ€” set to 'venv/lib/python3.13/site-packages' ๐Ÿ“ฆ
sitePackages = 'venv/lib/python3.13/site-packages'
  • testRestart() โ€” checks whether auto-deployment still works on restart ๐Ÿ”
  • testSplitRootPackages() โ€” checks whether auto-deployment works with a virtualenv where jobs are defined in completely separate branches of the package hierarchy ๐ŸŒณ Back in the day, auto-deployment did deploy the entire virtualenv, but jobs could only be defined in one branch of the package hierarchy ๐Ÿ˜ญ A branch is the maximum set of fully qualified package paths that share the same first component. IOW, a.b and a.c are in the same branch, while a.b and d.c are not.
  • testUserTypesInJobFunctionArgs() โ€” tests encapsulated, function-wrapping jobs where the function arguments reference user-defined types ๐Ÿ’œ This was mainly written to cover https://github.com/BD2KGenomics/toil/issues/1259, but it also revealed https://github.com/BD2KGenomics/toil/issues/1278 ๐Ÿ™ˆ
  • testDeferralWithConcurrentEncapsulation() โ€” ensures that the following DAG succeeds ๐ŸŒˆ
                 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                 โ”‚ Root (W1) โ”‚
                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚
            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
            โ–ผ                    โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚ Deferring (W2) โ”‚ โ”‚ Encapsulating (W3) โ”‚โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ•‘
                                 โ”‚                         โ•‘
                                 โ–ผ                         โ–ผ
                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                       โ”‚ Encapsulated (W3) โ”‚      โ”‚ Follow-on (W6) โ”‚
                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚                         โ”‚
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                โ”‚
                         โ–ผ                โ–ผ                โ–ผ
                 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                 โ”‚ Dummy 1 (W4) โ”‚ โ”‚ Dummy 2 (W5) โ”‚ โ”‚  Last (W6)   โ”‚
                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Wn numbers show which worker process a particular job runs in ๐Ÿฆ‹ Deferring adds a deferred function and then runs for a long time. That deferred function stays in the cache state for the whole duration of Deferred. Follow-on is the generic Job instance that gets added when you encapsulate a job. It runs on the same worker node, but in a separate worker process, as the first job in that worker. Becauseโ€ฆ

  1. it is the first job in its worker process (the user script has not been put on the sys.path by a previous job in that worker) and
  2. it shares the cache state with the Deferring job and
  3. it is an instance of Job (and so does not introduce the user script to sys.path itself),

โ€ฆit might cause problems with deserializing a deferred function defined in the user script ๐Ÿ˜ฌ

Encapsulated has two children so that Follow-on runs in a separate worker ๐Ÿงš

  • testDeferralWithFailureAndEncapsulation() โ€” ensures that the following DAG succeeds ๐Ÿ’€
                 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                 โ”‚ Root (W1) โ”‚
                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚
            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
            โ–ผ                    โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚ Deferring (W2) โ”‚ โ”‚ Encapsulating (W3) โ”‚โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                       โ•‘
                                 โ”‚                                 โ•‘
                                 โ–ผ                                 โ–ผ
                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                       โ”‚ Encapsulated (W3) โ”‚โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ”‚ Follow-on (W7) โ”‚
                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜            โ•‘ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚                      โ•‘
                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”               โ•‘
                          โ–ผ             โ–ผ               โ–ผ
                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                   โ”‚ Dummy (W4) โ”‚โ”‚ Dummy (W5) โ”‚ โ”‚ Trigger (W6) โ”‚
                   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Trigger causes Deferring to crash ๐Ÿ’ฅ Follow-on runs next, detects Deferring's left-overs and runs the deferred function. Follow-on is an instance of Job and the first job in its worker process. This test makes sure that, even in these circumstances, the user script is loaded before the deferred functions defined in it get run ๐Ÿ”ฅ

Encapsulated has two children so that Follow-on runs in a new worker. That's the only way to guarantee the user script hasn't been loaded yet, which would make the test pass by accident ๐Ÿ™ˆ We want to test that auto-deploying and loading the user script are done properly before deferred functions run, and before any jobs have been executed by that worker ๐Ÿ‘‘

โœจ toil.test.src.busTest โœจ

๐Ÿฆ‹ Attributes ๐Ÿฆ‹

  • logger

๐ŸŒธ Classes ๐ŸŒธ

  • TestMessageBus

๐Ÿ’… Functions ๐Ÿ’…

  • failing_job_fn(job) โ€” this function is guaranteed to fail ๐Ÿ’€

โœจ Module Contents โœจ

  • toil.test.src.busTest.logger
  • class toil.test.src.busTest.TestMessageBus
    • test_enum_ints_in_file(tmp_path) โ€” makes sure writing bus messages to files works with enums ๐Ÿ“

Parameters: tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

Return type: None

  • test_cross_thread_messaging() โ€” makes sure the message bus works across threads ๐Ÿงต

Return type: None

  • test_restart_without_bus_path(tmp_path) โ€” tests the ability to restart a workflow when the message bus path used by the previous attempt is gone ๐Ÿซฃ

Parameters: tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

Return type: None

  • toil.test.src.busTest.failing_job_fn(job) โ€” this is the same guaranteed-to-fail function from above, now in its module-contents home ๐ŸŒˆ

Parameters: job (toil.job.Job)

โœจ toil.test.src.checkpointTest โœจ

Return type: NoReturn ๐Ÿ’…

๐Ÿ’– Classes

  • CheckpointTest โ€” Legacy common base class for Toil tests. ๐ŸŽ€
  • CheckRetryCount โ€” Fail N times, succeed on the next try. ๐Ÿ”ฅ
  • AlwaysFail โ€” Class represents a unit of work in toil. โญ
  • CheckpointFailsFirstTime โ€” Class represents a unit of work in toil. ๐Ÿฆ‹
  • FailOnce โ€” Fail the first time the workflow is run, but succeed thereafter. ๐ŸŒธ

๐Ÿงš Module Contents

toil.test.src.checkpointTest.CheckpointTest(methodName='runTest')

Bases: toil.test.ToilTest ๐Ÿซถ

Legacy common base class for Toil tests. Okay bestie, heads up: new tests should be made in the 'pytest' style and not use this class. ๐Ÿ™ˆ

When you run tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files to go. The directory gets created if it doesn't exist yet. The path can be relative, in which case it's assumed to be relative to the project root. If TOIL_TEST_TEMP isn't defined, temporary files and directories get created in the system's default location for that stuff, and any leftover temp files or directories from tests get removed automatically during tear down. Otherwise, leftover files will not be removed. โœจ

  • testCheckpointNotRetried() โ€” A checkpoint job should not be retried if the workflow has a retryCount of 0. ๐Ÿ™…โ€โ™€๏ธ
  • testCheckpointRetriedOnce() โ€” A checkpoint job should be retried exactly once if the workflow has a retryCount of 1. ๐Ÿ”
  • testCheckpointedRestartSucceeds() โ€” A checkpointed job should succeed on restart of a failed run if its child job succeeds. ๐Ÿ‘‘

class toil.test.src.checkpointTest.CheckRetryCount(numFailuresBeforeSuccess)

Bases: toil.job.Job ๐Ÿ’œ

Fail N times, succeed on the next try. It's giving stubborn but iconic ๐Ÿ’…

Attribute: numFailuresBeforeSuccess ๐Ÿ“

  • getNumRetries(fileStore) โ€” Marks a retry in the fileStore, then returns the number of retries so far. ๐Ÿ“ˆ
  • run(fileStore) โ€” Override this function to perform work and dynamically create successor jobs. ๐Ÿ› ๏ธ
    • Parameters:
      • fileStore โ€” Used to create local and globally sharable temporary files and to send log messages to the leader process. ๐Ÿ“ฌ
    • Returns: The return value of the function can be passed to other jobs by means of toil.job.Job.rv(). ๐ŸŽ

class toil.test.src.checkpointTest.AlwaysFail(memory=None, cores=None, disk=None, accelerators=None, preemptible=None, preemptable=None, unitName='', checkpoint=False, displayName='', descriptionClass=None, local=None, files=None)

Bases: toil.job.Job ๐ŸŒˆ

Class represents a unit of work in toil. Main character energy, no notes ๐Ÿ‘‘

class toil.test.src.checkpointTest.AlwaysFail(memory=None, cores=None, disk=None, accelerators=None, preemptible=None, preemptable=None, unitName='', checkpoint=False, displayName='', descriptionClass=None, local=None, files=None)

Parameters:

  • memory (Optional[ParseableIndivisibleResource])
  • cores (Optional[ParseableDivisibleResource])
  • disk (Optional[ParseableIndivisibleResource])
  • accelerators (Optional[ParseableAcceleratorRequirement])
  • preemptible (Optional[ParseableFlag])
  • preemptable (Optional[ParseableFlag])
  • unitName (Optional[str])
  • checkpoint (Optional[bool])
  • displayName (Optional[str])
  • descriptionClass (Optional[type])
  • local (Optional[bool])
  • files (Optional[set[toil.fileStores.FileID]])
  • run(fileStore) โ€” Override this function to perform work and dynamically create successor jobs. ๐Ÿ› ๏ธ
    • Parameters:
      • fileStore โ€” Used to create local and globally sharable temporary files and to send log messages to the leader process. ๐Ÿ“ฌ
    • Returns: The return value of the function can be passed to other jobs by means of toil.job.Job.rv(). ๐ŸŽ

class toil.test.src.checkpointTest.CheckpointFailsFirstTime

Bases: toil.job.Job ๐Ÿฆ‹

Class represents a unit of work in toil. โœจ

  • run(fileStore) โ€” Override this function to perform work and dynamically create successor jobs. ๐Ÿ› ๏ธ
    • Parameters:
      • fileStore โ€” Used to create local and globally sharable temporary files and to send log messages to the leader process. ๐Ÿ“ฌ
    • Returns: The return value of the function can be passed to other jobs by means of toil.job.Job.rv(). ๐ŸŽ

class toil.test.src.checkpointTest.FailOnce(memory=None, cores=None, disk=None, accelerators=None, preemptible=None, preemptable=None, unitName='', checkpoint=False, displayName='', descriptionClass=None, local=None, files=None)

Bases: toil.job.Job ๐Ÿ“

Fail the first time the workflow is run, but succeed thereafter. First run = oops, every run after = slay ๐Ÿ’€โœจ

class toil.test.src.checkpointTest.FailOnce(memory=None, cores=None, disk=None, accelerators=None, preemptible=None, preemptable=None, unitName='', checkpoint=False, displayName='', descriptionClass=None, local=None, files=None)

Parameters:

  • memory (Optional[ParseableIndivisibleResource])
  • cores (Optional[ParseableDivisibleResource])
  • disk (Optional[ParseableIndivisibleResource])
  • accelerators (Optional[ParseableAcceleratorRequirement])
  • preemptible (Optional[ParseableFlag])
  • preemptable (Optional[ParseableFlag])
  • unitName (Optional[str])
  • checkpoint (Optional[bool])
  • displayName (Optional[str])
  • descriptionClass (Optional[type])
  • local (Optional[bool])
  • files (Optional[set[toil.fileStores.FileID]])
  • run(fileStore) โ€” Override this function to perform work and dynamically create successor jobs. ๐Ÿ› ๏ธ
    • Parameters:
      • fileStore โ€” Used to create local and globally sharable temporary files and to send log messages to the leader process. ๐Ÿ“ฌ
    • Returns: The return value of the function can be passed to other jobs by means of toil.job.Job.rv(). ๐ŸŽ

โœจ toil.test.src.deferredFunctionTest โœจ

๐ŸŒธ Attributes

  • logger ๐Ÿ“

๐Ÿ’… Classes

  • TestDeferredFunction โ€” Test the deferred function system. ๐Ÿงช

๐Ÿฆ‹ Functions

  • options(tmp_path) ๐Ÿ”ง

๐Ÿงš Module Contents

toil.test.src.deferredFunctionTest.logger

Attribute, no description attached. Just vibes ๐Ÿซง

toil.test.src.deferredFunctionTest.options(tmp_path)

Parameters:

  • tmp_path (pathlib.Path)

Return type: collections.abc.Generator[argparse.Namespace] ๐ŸŒˆ

class toil.test.src.deferredFunctionTest.TestDeferredFunction

Test the deferred function system. The whole deferred function system, tested. Iconic behaviour ๐Ÿ‘‘๐Ÿ”ฅ

testDeferredFunctionRunsWithMethod(tmp_path, options)

Literally just check the docstring for _testDeferredFunctionRuns ๐Ÿ’… This version tests with a Method ๐Ÿฆ‹

Parameters

  • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • options (argparse.Namespace, /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type: None

testDeferredFunctionRunsWithClassMethod(tmp_path, options)

Same deal, go read _testDeferredFunctionRuns ๐ŸŒธ This one tests with a Class Method โœจ

Parameters

  • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • options (argparse.Namespace, /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type: None

testDeferredFunctionRunsWithLambda(tmp_path, options)

Refer to the docstring in _testDeferredFunctionRuns again, bestie ๐Ÿซถ This version tests with a Lambda ๐Ÿ“

Parameters

  • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • options (argparse.Namespace, /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type: None

testDeferredFunctionRunsWithFailures(options, tmp_path)

Okay this one is a whole saga ๐Ÿ˜ญ It creates 2 non local files to use as flags ๐Ÿšฉ Then it makes a job that registers a function that deletes one non local file. If that file exists, the job SIGKILLs itself ๐Ÿ’€ If it doesn't exist, the job registers a second deferred function that deletes the second non local file, and then it exits normally.

Initially the first file exists, so the job should SIGKILL itself and neither deferred function will run (in fact, the second should not even be registered) ๐Ÿ™ˆ On the restart, the first deferred function should run and the first file should not exist, but the second one should. We assert the presence of the second, then register the second deferred function and exit normally. At the end of the test, neither file should exist โœจ

Incidentally, this also tests for multiple registered deferred functions, and the case where a deferred function fails (since the first file doesn't exist on the retry) ๐Ÿ‘‘

Parameters

  • options (argparse.Namespace, /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)
  • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

Return type: None

testNewJobsCanHandleOtherJobDeaths(options, tmp_path)

Main character energy ๐Ÿฆ‹ We start by making 2 non-local files, then 2 jobs. The first job registers a deferred job to delete the second non-local file, deletes the first non-local file, and then kills itself ๐Ÿ’€

The second job waits for the first file to be deleted, then sleeps for a few seconds, then spawns a child. The child of the second does nothing. However, starting it should handle the untimely demise of the first job and run the registered deferred function that deletes the first file ๐Ÿ˜ญ We assert the absence of the two files at the end of the run ๐Ÿซถ

Parameters

  • options (argparse.Namespace, /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)
  • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

Return type: None

testBatchSystemCleanupCanHandleWorkerDeaths(options, tmp_path)

Okay so we make some non-local files ๐Ÿงš Then a job registers a deferred function to delete the file, and then kills its worker ๐Ÿ’€

We assert that the file is missing after the pipeline fails, because we're using a single-machine batch system, and the leader's batch system cleanup will find and run the deferred function. Iykyk ๐Ÿ”ฅ

Parameters

  • options (argparse.Namespace, /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)
  • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

Return type: None


๐Ÿงช toil.test.src.dockerCheckTest

๐ŸŽ€ Classes ๐ŸŽ€

  • DockerCheckTest โ€” Tests checking whether a docker image exists or not. ๐Ÿณ

๐ŸŒˆ Module Contents ๐ŸŒˆ

class toil.test.src.dockerCheckTest.DockerCheckTest(methodName='runTest')

Bases: toil.test.ToilTest

Tests checking whether a docker image exists or not. ๐Ÿ’–

  • testOfficialUbuntuRepo() โ€” Image exists, so this should pass โœ…
  • testBroadDockerRepo() โ€” Image exists, so this should pass โœ…
  • testBroadDockerRepoBadTag() โ€” Bad tag, so this should raise ๐Ÿ’€
  • testNonexistentRepo() โ€” Bad image, so this should raise ๐Ÿ’€
  • testToilQuayRepo() โ€” Image exists, should pass โœ…
  • testBadQuayRepoNTag() โ€” Bad repo and tag, this should raise ๐Ÿ’€
  • testBadQuayRepo() โ€” Bad repo, this should raise ๐Ÿ’€
  • testBadQuayTag() โ€” Bad tag, this should raise ๐Ÿ’€
  • testGoogleRepo() โ€” Image exists, should pass โœ…
  • testBadGoogleRepo() โ€” Bad repo and tag, this should raise ๐Ÿ’€
  • testApplianceParser() โ€” Tests that a specified appliance is parsed correctly ๐Ÿง

๐Ÿงช toil.test.src.environmentTest

๐Ÿ’œ Attributes ๐Ÿ’œ

  • logger

๐Ÿฆ‹ Classes ๐Ÿฆ‹

  • EnvironmentTest โ€” Test to make sure that Toil's environment variable save and restore system (environment.pickle) works. ๐ŸŒท

๐ŸŒธ Functions ๐ŸŒธ

  • signal_leader(job) โ€” Make a file in the file store that the leader can see ๐Ÿ‘€
  • check_environment(job, try_name) โ€” Fail if the test environment is wrong ๐Ÿšจ
  • wait_a_bit(job) โ€” Toil job that waits โณ
  • check_environment_repeatedly(job) โ€” Toil job that checks the environment, waits, and checks it again, as
  • main([options]) โ€” Run the actual workflow with the given options ๐Ÿš€

โœจ Module Contents โœจ

class toil.test.src.environmentTest.logger
class toil.test.src.environmentTest.EnvironmentTest(methodName='runTest')

Bases: toil.test.ToilTest

Test to make sure that Toil's environment variable save and restore system (environment.pickle) works ๐Ÿ’…

The environment should be captured once at the start of the workflow, and should be sent through based on that, not based on the leader's current environment when the job is launched. Bestie, that's the whole point ๐Ÿซถ

  • test_environment()
toil.test.src.environmentTest.signal_leader(job)

Make a file in the file store that the leader can see ๐Ÿ‘€

toil.test.src.environmentTest.check_environment(job, try_name)

Fail if the test environment is wrong ๐Ÿšจ

Parameters

  • try_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
toil.test.src.environmentTest.wait_a_bit(job)

Toil job that waits โณ

โœจ toil.test.src.environmentTest.check_environment_repeatedly(job) โœจ

Okay so this is a Toil job ๐Ÿ’… It checks the environment, waits, and then checks it again, as separate invocations. Main character energy ๐Ÿฆ‹

โœจ toil.test.src.environmentTest.main(options=None) โœจ

bestie, this one runs the actual workflow with whatever options you hand it ๐ŸŽ€

Parameters

  • options (Optional[argparse.Namespace </usr/share/doc/python3/html/library/argparse.html#argparse.Namespace>]) ๐ŸŒธ

๐ŸŒธ toil.test.src.fileStoreTest ๐ŸŒธ

Attributes

  • testingIsAutomatic ๐Ÿฆ‹
  • logger ๐Ÿฆ‹

Classes

  • hidden โ€” hiding the abstract test classes from the Unittest loader so they can be inherited in different test suites for the different job stores ๐Ÿ™ˆ
  • NonCachingFileStoreTestWithFileJobStore โ€” abstract tests for the general functions in the non-caching file store ๐Ÿ’œ
  • CachingFileStoreTestWithFileJobStore โ€” abstract tests for the cache-related functions ๐Ÿ’œ
  • NonCachingFileStoreTestWithAwsJobStore โ€” abstract tests for the general functions in the non-caching file store ๐Ÿ’œ
  • CachingFileStoreTestWithAwsJobStore โ€” abstract tests for the cache-related functions ๐Ÿ’œ
  • NonCachingFileStoreTestWithGoogleJobStore โ€” abstract tests for the general functions in the non-caching file store ๐Ÿ’œ
  • CachingFileStoreTestWithGoogleJobStore โ€” abstract tests for the cache-related functions ๐Ÿ’œ

Module Contents

  • toil.test.src.fileStoreTest.testingIsAutomatic = True โœจ
  • toil.test.src.fileStoreTest.logger โœจ
  • class toil.test.src.fileStoreTest.hidden ๐Ÿ™ˆ Hiding the abstract test classes from the Unittest loader so it can be inherited in different test suites for the different job stores.
    • class AbstractFileStoreTest(methodName='runTest') ๐Ÿงš Bases: toil.test.ToilTest <#toil.test.ToilTest>

An abstract base class for testing the various general functions described in :class:toil.fileStores.abstractFileStore.AbstractFileStore ๐Ÿ’…

  • jobStoreType = None
  • setUp(): hook method for setting up the test fixture before exercising it ๐ŸŽ€
  • options(): mints a fresh options object with default settings and a fresh jobstore ๐Ÿ“
  • create_file(content, executable=False)
  • testToilIsNotBroken(): runs a simple DAG to test whether any features other than caching were broken ๐Ÿ”ฅ
  • testFileStoreLogging(): writes a couple of files to the jobstore, deletes a couple of them, then reads back the written and locally deleted files ๐ŸŒˆ
  • testFileStoreOperations(): writes a couple of files to the jobstore, deletes a couple of them, then reads back the written and locally deleted files ๐ŸŒˆ
  • testWriteReadGlobalFilePermissions(): makes sure uploaded files keep their file permissions when they get downloaded again. This checks that a written executable file stays executable after being read ๐Ÿซถ
  • testWriteExportFileCompatibility(): makes sure files created in a job keep their executable permissions when they're exported from the leader ๐Ÿซถ
  • testImportReadFileCompatibility(): makes sure files imported to the leader keep their executable permissions when they're read by the fileStore ๐Ÿซถ
  • testReadWriteFileStreamTextMode(): checks whether text mode is compatible with file streams ๐Ÿ’–
  • class AbstractNonCachingFileStoreTest(methodName='runTest') ๐Ÿงš Bases: AbstractFileStoreTest

Abstract tests for the general functions in :class:toil.fileStores.nonCachingFileStore.NonCachingFileStore. These tests are general enough that they can also be used for :class:toil.fileStores.CachingFileStore. ๐Ÿ‘‘

  • options(): mints a fresh options object with default settings and a fresh jobstore ๐Ÿ“
  • class AbstractCachingFileStoreTest(methodName='runTest') ๐Ÿงš Bases: AbstractFileStoreTest

Abstract tests for the cache-related functions in :class:toil.fileStores.cachingFileStore.CachingFileStore. ๐Ÿ‘‘

  • options(): mints a fresh options object with default settings and a fresh jobstore ๐Ÿ“
  • testExtremeCacheSetup(): tries to create the cache with a bad worker active, then has 10 child jobs try to run in the chain. This tests whether the cache gets created properly even when the job crashes randomly ๐Ÿ’€
  • testCacheEvictionPartialEvict(): makes sure cache eviction happens as expected. Two files (20MB and 30MB) get written sequentially into the job store in separate jobs. The cache max is force set to 50MB. A third job requests 10MB of disk, which requires evicting the 1st file. Checks that the behavior is as expected ๐Ÿ”ฅ
  • testCacheEvictionTotalEvict(): makes sure cache eviction happens as expected. Two files (20MB and 30MB) get written sequentially into the job store in separate jobs. The cache max is force set to 50MB. A third job requests 10MB of disk, which requires evicting the 1st file. Checks that the behavior is as expected ๐Ÿ”ฅ
  • testCacheEvictionFailCase(): makes sure cache eviction happens as expected. Two files (20MB and 30MB) get written sequentially into the job store in separate jobs. The cache max is force set to 50MB. A third job requests 10MB of disk, which requires evicting the 1st file. Checks that the behavior is as expected ๐Ÿ”ฅ
  • testAsyncWriteWithCaching(): makes sure async writing of files happens as expected. The first job forcefully modifies the cache size to 1GB. The second job asks for 1GB of disk and writes a 900MB file into the cache, then rewrites it to the job store. That triggers an async write, since the two unique jobstore IDs point to the same local file. The second write also isn't cached, because the first one already went into the cache and there "isn't enough space" for another. It immediately asserts that the second write isn't cached and is being asynchronously written to the job store. Getting the file from the jobstore afterwards should not fail ๐Ÿš€
  • testWriteNonLocalFileToJobStore(): writes a file that isn't in localTempDir to the job store. A file like that shouldn't be cached, so this checks that it isn't ๐Ÿ™ˆ
  • testWriteLocalFileToJobStore(): writes a file from localTempDir to the job store. Files like this get cached by default, so this checks that it is cached ๐Ÿง
โš ๏ธ Nothing on this page changes the facts. The fine print is still all here, bestie ๐Ÿ’–
  • testReadCacheMissFileFromJobStoreWithoutCachingReadFile(): reads a file from the file store that has no cached copy, doesn't cache it, and checks that the link count on the file is right ๐Ÿ”—
  • testReadCacheMissFileFromJobStoreWithCachingReadFile(): same cache miss, but this time the read file does get cached. The link count still has to check out ๐Ÿ’…
  • testReadCachHitFileFromJobStore(): reads a file that already has a cached copy and makes sure the link count is correct ๐ŸŒธ
  • testMultipleJobsReadSameCacheHitGlobalFile(): writes a local file to the job store (which adds a copy to the cache), then has 10 jobs read it. It asserts the cached file size never goes up, and that unused job-required disk space is always (a multiple of job reqs) - (number of current file readers * filesize). At the very end, the cache should show unused job-required space = 0 ๐Ÿ”ฅ
  • testMultipleJobsReadSameCacheMissGlobalFile(): writes a non-local file to the job store (so there's no cached copy), then has 10 jobs read it. Same vibes as the test above: cached file size never goes up, unused job-required disk space is always (a multiple of job reqs) - (number of current file readers * filesize), and at the end the cache shows unused job-required space = 0 ๐Ÿ’œ
  • testFileStoreExportFile()
  • testReturnFileSizes(): writes a couple of files, deletes a couple, then reads back the written and locally deleted files. The cache has to be in a valid state after every single step ๐Ÿงš
  • testReturnFileSizesWithBadWorker(): the same routine as testReturnFileSizes(), but with a bad worker in the mix. Cache has to stay valid after every step ๐Ÿ˜ญ
  • testControlledFailedWorkerRetry(): does a couple of job store operations, then dies on purpose. It checks that the restarted job is tracking values in the cache state file appropriately ๐Ÿฆ‹
  • testRemoveLocalMutablyReadFile(): if a mutably read file gets deleted by the user, that's ok โœจ
  • testRemoveLocalImmutablyReadFile(): if an immutably read file gets deleted by the user, that's not ok ๐Ÿ™ˆ
  • testDeleteLocalFile(): tests the deletion powers of deleteLocalFile ๐Ÿ“
  • testSimultaneousReadsUncachedStream(): throws a bunch of simultaneous read attempts at a file that was created via a stream straight into the job store ๐ŸŒˆ

๐ŸŽ€ toil.test.src.fileStoreTest.NonCachingFileStoreTestWithFileJobStore(methodName='runTest')

  • Bases: hidden

Abstract tests for the various functions in :class:toil.fileStores.nonCachingFileStore.NonCachingFileStore. These are general enough that you can also use them for :class:toil.fileStores.CachingFileStore. ๐Ÿ’–

  • jobStoreType = 'file'

๐ŸŽ€ toil.test.src.fileStoreTest.CachingFileStoreTestWithFileJobStore(methodName='runTest')

  • Bases: hidden

Abstract tests for the various cache-related functions in :class:toil.fileStores.cachingFileStore.CachingFileStore. โœจ

  • jobStoreType = 'file'

๐ŸŽ€ toil.test.src.fileStoreTest.NonCachingFileStoreTestWithAwsJobStore(methodName='runTest')

  • Bases: hidden

Abstract tests for the various functions in :class:toil.fileStores.nonCachingFileStore.NonCachingFileStore. These are general enough that you can also use them for :class:toil.fileStores.CachingFileStore. ๐ŸŒธ

  • jobStoreType = 'aws'

๐ŸŽ€ toil.test.src.fileStoreTest.CachingFileStoreTestWithAwsJobStore(methodName='runTest')

  • Bases: hidden

Abstract tests for the various cache-related functions in :class:toil.fileStores.cachingFileStore.CachingFileStore. ๐Ÿฆ‹

  • jobStoreType = 'aws'

๐ŸŽ€ toil.test.src.fileStoreTest.NonCachingFileStoreTestWithGoogleJobStore(methodName='runTest')

  • Bases: hidden

Abstract tests for the various functions in :class:toil.fileStores.nonCachingFileStore.NonCachingFileStore. These are general enough that you can also use them for :class:toil.fileStores.CachingFileStore. ๐Ÿ’œ

  • jobStoreType = 'google'

๐ŸŽ€ toil.test.src.fileStoreTest.CachingFileStoreTestWithGoogleJobStore(methodName='runTest')

  • Bases: hidden

Abstract tests for the various cache-related functions in :class:toil.fileStores.cachingFileStore.CachingFileStore. ๐Ÿ‘‘

  • jobStoreType = 'google'

๐Ÿฆ‹ toil.test.src.helloWorldTest

๐Ÿ’… Classes

  • HelloWorldTest: the legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ
  • HelloWorld: a class that represents a unit of work in Toil โญ
  • FollowOn: a class that represents a unit of work in Toil ๐Ÿซถ

๐Ÿงš Functions

  • childFn(job)

๐ŸŒˆ Module Contents

๐ŸŽ€ class toil.test.src.helloWorldTest.HelloWorldTest(methodName='runTest')

  • Bases: toil.test.ToilTest

This is the legacy common base class for Toil tests, so it's giving old school ๐Ÿ“œ New tests should be made in the pytest style and should not use this class.

Heads up bestie: new tests should be pytest-style, not this class. ๐Ÿ’€

When running tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files to go. The directory gets created if it doesn't exist yet. The path can be relative, in which case it's assumed to be relative to the project root. If TOIL_TEST_TEMP isn't defined, temporary files and directories get created in the system's default location for that kind of thing, and any temp files or directories left over from tests get removed automatically during tear down. If you do set TOIL_TEST_TEMP, left-over files won't be removed. ๐Ÿงน

  • testHelloWorld()

๐ŸŽ€ class toil.test.src.helloWorldTest.HelloWorld

  • Bases: toil.job.Job

A unit of work in Toil, bestie ๐Ÿง

  • run(fileStore): override this function to do the work and dynamically create successor jobs โšก
    • Parameters: fileStore, used to create local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“ฎ
    • Returns: the return value can be passed to other jobs using toil.job.Job.rv() ๐ŸŽ

๐ŸŽ€ toil.test.src.helloWorldTest.childFn(job)

๐ŸŽ€ class toil.test.src.helloWorldTest.FollowOn(fileId)

  • Bases: toil.job.Job

A unit of work in Toil, again ๐Ÿ”

  • fileId
  • run(fileStore): override this function to do the work and dynamically create successor jobs ๐Ÿ’ซ
    • Parameters: fileStore, used to create local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“ฎ
    • Returns: the return value can be passed to other jobs using toil.job.Job.rv() ๐ŸŽ

๐Ÿฆ‹ toil.test.src.importExportFileTest

๐Ÿ’… Classes

  • TestImportExportFile
  • RestartingJob: a class that represents a unit of work in Toil ๐ŸŒท

๐Ÿงš Functions

  • create_file(tmp_path, content[, executable])

๐ŸŒˆ Module Contents

๐ŸŽ€ toil.test.src.importExportFileTest.create_file(tmp_path, content, executable=False)

  • Parameters:
    • tmp_path (pathlib.Path)
    • content (str)
    • executable (bool)
  • Return type โ€” pathlib.Path ๐Ÿงš

okay so the return type is pathlib.Path, and then we're into the actual test class bestie ๐Ÿ’…

class toil.test.src.importExportFileTest.TestImportExportFile โœจ

  • message_portion_1 = 'What do you get when you cross a seal and a polar bear?' ๐Ÿฆญ this is the setup line of the joke
  • message_portion_2 = ' A polar bear.' ๐Ÿ˜ญ and this is the punchline
  • test_import_export_restart_true(tmp_path) ๐ŸŒธ
    • Parameters:
      • tmp_path (pathlib.Path)
    • Return type: None
  • test_import_export_restart_false(tmp_path) ๐Ÿฆ‹
    • Parameters:
      • tmp_path (pathlib.Path)
    • Return type: None
  • test_basic_import_export(tmp_path, subtests) ๐Ÿ’œ
    • Ensures that uploaded files preserve their file permissions when they're downloaded again. This one checks that an imported executable file stays executable after being exported, so no lost vibes ๐Ÿ”ฅ
    • Parameters:
      • tmp_path (pathlib.Path)
      • subtests (pytest.Subtests)
    • Return type: None

class toil.test.src.importExportFileTest.RestartingJob(msg_portion_file_id, trigger_file_id, message_portion_2) ๐Ÿ”ฅ

  • Bases: toil.job.Job
  • A Job is basically a unit of work in Toil, and this is one of them ๐Ÿ’…
  • Parameters:
    • msg_portion_file_id (str)
    • trigger_file_id (str)
    • message_portion_2 (str)
  • Attributes: msg_portion_file_id, trigger_file_id, message_portion_2 ๐Ÿงš
  • run(file_store) ๐Ÿ‘‘
    • Override this one to do the actual work and dynamically create successor jobs. It's giving main character energy ๐ŸŽ€
    • Parameters:
      • fileStore โ€” the thing you use to make local and globally sharable temporary files, and to send log messages to the leader process ๐Ÿ’–
      • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)
    • Returns: whatever you return can be handed off to other jobs using toil.job.Job.rv() โœจ
    • Return type: str

๐ŸŒธ toil.test.src.jobDescriptionTest

๐ŸŽ€ Classes

  • JobDescriptionTest โ€” the legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ

๐Ÿ’… Module Contents

  • class toil.test.src.jobDescriptionTest.JobDescriptionTest(methodName='runTest') ๐Ÿ’–
    • Bases: toil.test.ToilTest
    • This is the legacy common base class for Toil tests. Okay so, new tests should be written in the pytest style and should NOT use this class ๐Ÿ™…โ€โ™€๏ธ
    • When you're running tests you can optionally set the TOIL_TEST_TEMP environment variable to a directory where you want the temporary test files to go. It gets created if it doesn't exist yet. The path can be relative, in which case it's assumed to be relative to the project root ๐ŸŒˆ
    • If TOIL_TEST_TEMP isn't defined, temporary files and directories get created in the system's default location for that kind of stuff, and any leftover temporary files or directories from tests get removed automatically during tear down. Otherwise, the leftover files won't be removed ๐Ÿงน
    • setUp() ๐ŸŒท โ€” the hook method for setting up the test fixture before it gets exercised
    • tearDown() ๐ŸŒท โ€” the hook method for deconstructing the test fixture after testing it
    • testJobDescription() ๐Ÿงš โ€” tests the public interface of a JobDescription
    • testJobDescriptionSequencing() โญ

๐Ÿฆ‹ toil.test.src.jobEncapsulationTest

๐ŸŽ€ Classes

  • TestJobEncapsulation โ€” tests testing the EncapsulationJob class ๐Ÿ’œ

โœจ Functions

  • noOp() ๐Ÿซถ
  • encapsulatedJobFn(job, string, outFile) ๐Ÿซถ

๐Ÿ’… Module Contents

  • class toil.test.src.jobEncapsulationTest.TestJobEncapsulation ๐Ÿ”ฅ
    • Tests testing the EncapsulationJob class. Iconic ๐Ÿ‘‘
    • testEncapsulation(tmp_path) ๐Ÿ’–
      • Tests the Job.encapsulation method, which uses the EncapsulationJob class โœจ
      • Parameters:
        • tmp_path (pathlib.Path)
      • Return type: None
    • testAddChildEncapsulate() ๐Ÿฆ‹
      • Make sure that the encapsulate child doesn't have two parents with unique roots. Not me having to double check this ๐Ÿ’€
      • Return type: None
  • toil.test.src.jobEncapsulationTest.noOp() ๐ŸŒธ
    • Return type: None
  • toil.test.src.jobEncapsulationTest.encapsulatedJobFn(job, string, outFile) ๐Ÿงš
    • Parameters:
      • job (toil.job.Job)
      • string (str)
      • outFile (pathlib.Path)
    • Return type: toil.job.Promise

๐ŸŒˆ toil.test.src.jobFileStoreTest

๐Ÿ’œ Attributes

  • logger ๐Ÿชต
  • PREFIX_LENGTH ๐Ÿ“
  • fileStoreString ๐Ÿงต
  • streamingFileStoreString ๐ŸŒŠ

๐ŸŽ€ Classes

  • JobFileStoreTest โ€” tests testing the methods defined in :class:toil.fileStores.abstractFileStore.AbstractFileStore ๐Ÿ’…

โœจ Functions

  • fileTestJob(job, inputFileStoreIDs, testStrings, ...) โ€” a test job that exercises toil.fileStores.abstractFileStore.AbstractFileStore functions ๐Ÿ”ฅ
  • simpleFileStoreJob(job) ๐ŸŒธ
  • fileStoreChild(job, testID1, testID2) ๐Ÿฆ‹

๐Ÿ’… Module Contents

  • toil.test.src.jobFileStoreTest.logger ๐Ÿชต
  • toil.test.src.jobFileStoreTest.PREFIX_LENGTH = 200 ๐Ÿ“
  • class toil.test.src.jobFileStoreTest.JobFileStoreTest(methodName='runTest') ๐Ÿ’–
    • Bases: toil.test.ToilTest
    • Tests testing the methods defined in :class:toil.fileStores.abstractFileStore.AbstractFileStore ๐Ÿ’œ
    • testCachingFileStore() โœจ
    • testNonCachingFileStore() โœจ
    • testJobFileStore() ๐Ÿงš โ€” tests the case where about half the files are cached
    • testJobFileStoreWithBadWorker() ๐Ÿ˜ญ โ€” tests the case where about half the files are cached and the worker is randomly failing. Chaotic but make it make sense ๐Ÿ™ˆ

toil.test.src.jobFileStoreTest.fileTestJob(job, inputFileStoreIDs, testStrings, chainLength) Test job exercises toil.fileStores.abstractFileStore.AbstractFileStore functions

toil.test.src.jobFileStoreTest.fileStoreString = 'Testing writeGlobalFile'

toil.test.src.jobFileStoreTest.streamingFileStoreString = 'Testing writeGlobalFileStream'

toil.test.src.jobFileStoreTest.simpleFileStoreJob(job)

toil.test.src.jobFileStoreTest.fileStoreChild(job, testID1, testID2)

toil.test.src.jobServiceTest

Attributes โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ” โ”‚ logger โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜

Classes โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ TestJobService โ”‚ Tests testing the โ”‚ โ”‚ โ”‚ Job.Service class โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ TestPerfectServicet โ”‚ Tests testing the โ”‚ โ”‚ โ”‚ Job.Service class โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ ToyService โ”‚ Abstract class used to โ”‚ โ”‚ โ”‚ define the interface to a โ”‚ โ”‚ โ”‚ service. โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ ToySerializableService โ”‚ Abstract class used to โ”‚ โ”‚ โ”‚ define the interface to a โ”‚ โ”‚ โ”‚ service. โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Functions โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ serviceTest(job, outFile, โ”‚ Creates one service and โ”‚ โ”‚ messageInt) โ”‚ one accessing job, which โ”‚ โ”‚ โ”‚ communicate with two files โ”‚ โ”‚ โ”‚ to establish โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ serviceTestRecursive(job, โ”‚ Creates a chain of โ”‚ โ”‚ outFile, messages) โ”‚ services and accessing โ”‚ โ”‚ โ”‚ jobs, each paired โ”‚ โ”‚ โ”‚ together. โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ serviceTestParallelRecursive(job, โ”‚ Creates multiple chains of โ”‚ โ”‚ outFiles, messageBundles) โ”‚ services and accessing โ”‚ โ”‚ โ”‚ jobs. โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ serviceAccessor(job, โ”‚ Writes a random integer โ”‚ โ”‚ communicationFiles, outFile, ...) โ”‚ iinto the inJobStoreFileID โ”‚ โ”‚ โ”‚ file, then tries 10 times โ”‚ โ”‚ โ”‚ reading โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ fnTest(strings, outputFile) โ”‚ Function concatenates the โ”‚ โ”‚ โ”‚ strings together and โ”‚ โ”‚ โ”‚ writes them to the output โ”‚ โ”‚ โ”‚ file โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Module Contents toil.test.src.jobServiceTest.logger

class toil.test.src.jobServiceTest.TestJobService Tests testing the Job.Service class

testServiceSerialization(tmp_path) Tests that a service can receive a promise without producing a serialization error.

Parameters tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type None

testService(tmp_path, checkpoint=False) Tests the creation of a Job.Service with random failures of the worker.

Parameters

  • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • checkpoint (bool </usr/share/doc/python3/html/library/functions.html#bool>)

Return type None

testServiceDeadlock(tmp_path) Creates a job with more services than maxServices, checks that deadlock is detected.

Parameters tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type None

testServiceWithCheckpoints(tmp_path) Tests the creation of a Job.Service with random failures of the worker, making the root job use checkpointing to restart the subtree.

Parameters tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)

Return type None

testServiceRecursive(tmp_path, checkpoint=True) Tests the creation of a Job.Service, creating a chain of services and accessing jobs. Randomly fails the worker.

Parameters

  • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • checkpoint (bool </usr/share/doc/python3/html/library/functions.html#bool>)

Return type None

testServiceParallelRecursive(tmp_path, checkpoint=True) Tests the creation of a Job.Service, creating parallel chains of services and accessing jobs. Randomly fails the worker.

Parameters

  • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • checkpoint (bool </usr/share/doc/python3/html/library/functions.html#bool>)

Return type None

runToil(tmp_path, rootJob, retryCount=1, badWorker=0.5, badWorkedFailInterval=0.1, maxServiceJobs=sys.maxsize, deadlockWait=60, max_attempts=50)

Parameters

  • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • rootJob (toil.job.Job <#toil.job.Job>)
  • retryCount (int </usr/share/doc/python3/html/library/functions.html#int>)
  • badWorker (float </usr/share/doc/python3/html/library/functions.html#float>)
  • badWorkedFailInterval (float </usr/share/doc/python3/html/library/functions.html#float>)
  • maxServiceJobs (int </usr/share/doc/python3/html/library/functions.html#int>)
  • deadlockWait (int </usr/share/doc/python3/html/library/functions.html#int>)
  • max_attempts (int </usr/share/doc/python3/html/library/functions.html#int>)

Return type None

class toil.test.src.jobServiceTest.TestPerfectServicet Bases: TestJobService

Tests testing the Job.Service class

runToil(*args, **kwargs) Let us run all the tests in the other service test class, but without worker failures.

Parameters

  • args (Any)
  • kwargs (Any)

Return type None

toil.test.src.jobServiceTest.serviceTest(job, outFile, messageInt) Creates one service and one accessing job, which communicate with two files to establish that both run concurrently.

Parameters

  • job (toil.job.Job <#toil.job.Job>)
  • outFile (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • messageInt (int </usr/share/doc/python3/html/library/functions.html#int>)

Return type None

toil.test.src.jobServiceTest.serviceTestRecursive(job, outFile, messages) Creates a chain of services and accessing jobs, each paired together.

Parameters

  • job (toil.job.Job <#toil.job.Job>)
  • outFile (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • messages (list </usr/share/doc/python3/html/library/stdtypes.html#list>[int </usr/share/doc/python3/html/library/functions.html#int>])

Return type None

toil.test.src.jobServiceTest.serviceTestParallelRecursive(job, outFiles, messageBundles) Creates multiple chains of services and accessing jobs.

Parameters

  • job (toil.job.Job) ๐Ÿ’… The job that gets to hold the outFiles and messageBundles.
  • outFiles (list[pathlib.Path]) ๐Ÿ“‚ A list of paths for the output files.
  • messageBundles (list[list[int]]) ๐Ÿงš A list of lists, each holding ints.

Return type: None ๐Ÿซถ


toil.test.src.jobServiceTest.ToyService

class toil.test.src.jobServiceTest.ToyService(messageInt, *args, **kwargs)

Bases: toil.job.Job.Service โœจ

This is the blueprint for a service. You subclass it to make your own services ๐ŸŽ€. It never runs as a regular job, though. It runs inside a ServiceHostJob ๐Ÿฆ‹

Parameters

  • messageInt (int) ๐ŸŒธ
  • args (Any) ๐ŸŒˆ
  • kwargs (Any) ๐ŸŒˆ

Attribute: messageInt ๐Ÿ’œ

๐Ÿฆ‹ start(job)

Starts the service ๐Ÿš€

Parameters

  • job (toil.job.ServiceHostJob) โ€” The host job the service is running inside. You can use it to register deferred functions, or to grab the fileStore for making temporary files ๐Ÿงš

Returns

An object that tells jobs how to reach the service. It has to be pickleable, since jobs use it to access the service (see toil.job.Job.addService()) ๐Ÿ”ฅ

Return type: tuple[str, str] ๐Ÿ’–

๐Ÿฆ‹ stop(job)

Stops the service. This one can block until it's totally done, so no rushing ๐Ÿ›‘

Parameters

  • job (toil.job.Job) โ€” The underlying host job the service is running in. Same deal: use it to register deferred functions, or to access the fileStore for temporary files ๐ŸŒธ

Return type: None ๐Ÿซถ

๐Ÿฆ‹ check()

Checks that the service is still running ๐Ÿ‘€

Raises

  • exceptions.RuntimeError โ€” If the service failed, the service job gets labeled failed ๐Ÿ’€

Returns

True if the service is still running, otherwise False. If it returns False, the service job gets terminated and counts as a success โœจ

Important point, bestie: if the service job exits because of a failure, it should raise a RuntimeError. It should NOT return False! ๐Ÿ˜ญ๐Ÿšจ

Return type: Literal[True] ๐Ÿ’…

๐Ÿฆ‹ serviceWorker (static)

static serviceWorker(jobStore, terminate, error, inJobStoreID,
outJobStoreID, messageInt)

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore) ๐Ÿ—„๏ธ
  • terminate (threading.Event) ๐Ÿ›‘
  • error (threading.Event) โš ๏ธ
  • inJobStoreID (str) ๐Ÿฆ‹
  • outJobStoreID (str) ๐Ÿฆ‹
  • messageInt (int) ๐ŸŒธ

Return type: None ๐Ÿซถ


toil.test.src.jobServiceTest.serviceAccessor

toil.test.src.jobServiceTest.serviceAccessor(job, communicationFiles,
outFile, to_subtract)

This one writes a random integer into the inJobStoreFileID file. Then it tries 10 times to read from outJobStoreFileID to get a pair of integers. The first one should equal i, and the second one gets written into the outputFile ๐Ÿง 

Parameters

  • job (toil.job.ServiceHostJob) ๐Ÿงš
  • communicationFiles (tuple[str, str]) ๐Ÿ“จ
  • outFile (pathlib.Path) ๐Ÿ“‚
  • to_subtract (int) โž–

Return type: None ๐Ÿซถ


toil.test.src.jobServiceTest.ToySerializableService

class toil.test.src.jobServiceTest.ToySerializableService(messageInt,
*args, **kwargs)

Bases: toil.job.Job.Service โœจ

Same vibe as ToyService: it's the blueprint for a service you subclass ๐ŸŽ€. It doesn't run as a job either. It runs inside a ServiceHostJob ๐Ÿฆ‹

Parameters

  • messageInt (str) ๐ŸŒธ
  • args (Any) ๐ŸŒˆ
  • kwargs (Any) ๐ŸŒˆ

Attribute: messageInt ๐Ÿ’œ

๐Ÿฆ‹ start(job)

Starts the service ๐Ÿš€

Parameters

  • job (toil.job.Job) โ€” The underlying host job the service is running in. You can register deferred functions with it, or access the fileStore for temporary files ๐Ÿงš

Returns

An object that describes how to access the service. It must be pickleable, because jobs use it to reach the service (see toil.job.Job.addService()) ๐Ÿ”ฅ

Return type: str ๐Ÿ’–

๐Ÿฆ‹ stop(job)

Stops the service. This can block until it finishes ๐Ÿ›‘

Parameters

  • job (toil.job.Job) โ€” The underlying host job the service is running in. Use it to register deferred functions, or to access the fileStore for temporary files ๐ŸŒธ

Return type: None ๐Ÿซถ

๐Ÿฆ‹ check()

Checks that the service is still running ๐Ÿ‘€

Raises

  • exceptions.RuntimeError โ€” If the service failed, the service job gets labeled failed ๐Ÿ’€

Returns

True if the service is still running, otherwise False. If it's False, the service job gets terminated and counts as a success โœจ

Important point again, bestie: if the service job exits due to a failure, it should raise a RuntimeError, not return False! ๐Ÿ˜ญ๐Ÿšจ

Return type: Literal[True] ๐Ÿ’…


toil.test.src.jobServiceTest.fnTest

toil.test.src.jobServiceTest.fnTest(strings, outputFile)

This function smooshes the strings together and writes them to the output file ๐Ÿง

Parameters

  • strings (list[str]) ๐Ÿงต
  • outputFile (pathlib.Path) ๐Ÿ“‚

Return type: None ๐Ÿซถ


toil.test.src.jobTest

Classes ๐ŸŒˆ

  • TestJob โ€” Tests the job class ๐Ÿงช
  • TrivialService โ€” Abstract class used to define the interface to a service. Basically the same energy as the services above ๐Ÿฆ‹

More to come, so stay tuned! ๐Ÿ’–

โœจ FUNCTIONS โœจ

okay so bestie, these are the test helper functions ๐Ÿงš some of them have a description and some just... don't, so I'll tell you which is which:

  • simpleJobFn(job, value): no description on this one ๐Ÿคทโ€โ™€๏ธ
  • fn1Test(string, outputFile): this one tacks the next character onto the end of the given string. The description literally cuts off mid-sentence after "in the given" ๐Ÿ’€
  • fn2Test(pStrings, s, outputFile): this one glues together everything in pStrings, then s, in that exact order, and writes the result out. The description also stops mid-sentence after "writes the result to" ๐Ÿ˜ญ
  • trivialParent(job): no description ๐ŸŒธ
  • parent(job): no description ๐ŸŒธ
  • diamond(job): no description ๐ŸŒธ
  • child(job): no description ๐ŸŒธ
  • errorChild(job): no description ๐ŸŒธ

โœจ MODULE CONTENTS โœจ

๐Ÿฆ‹ class toil.test.src.jobTest.TestJob

This is where all the job class tests live. Tests the job class, obviously ๐Ÿ’…

๐Ÿ’œ testStatic(tmp_path)

Makes a DAG of jobs the non-dynamic way, then runs it. Here's the shape of it:

A -> F
\-------
B -> D  \
 \       \
  ------- C -> E

A follow-on is marked by ->.

  • Parameters
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • Return type
    • None

๐Ÿ’œ testStatic2(tmp_path)

Same vibe as testStatic: a non-dynamic DAG that gets built and run. Same diagram too, so you know the drill ๐Ÿซถ

A -> F
\-------
B -> D  \
 \       \
  ------- C -> E

A follow-on is marked by ->.

  • Parameters
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • Return type
    • None

๐Ÿ’œ testTrivialDAGConsistency(tmp_path)

No description here, but the params are the same as always ๐ŸŒˆ

  • Parameters
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • Return type
    • None

๐Ÿ’œ testDAGConsistency(tmp_path)

No description on this one either, bestie ๐Ÿ™ˆ

  • Parameters
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • Return type
    • None

๐Ÿ’œ testSiblingDAGConsistency(tmp_path)

A slightly spicier case ๐ŸŒถ๏ธ The stranded job's predecessors are siblings here, not parent and child.

  • Parameters
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • Return type
    • None

๐Ÿ’œ testDeadlockDetection()

This one randomly generates job graphs with all kinds of cycles in them and checks that each one throws an exception properly. It also checks that having multiple roots causes a deadlock exception ๐Ÿ”ฅ

  • Return type
    • None

๐Ÿ’œ testNewCheckpointIsLeafVertexNonRootCase(tmp_path, subtests)

This is the test for issue #1465, where checkpoint jobs that aren't leaf vertices were being identified as leaf vertices incorrectly ๐Ÿ˜ค It checks that new checkpoint jobs really are leaf vertices, starting from this baseline workflow:

Parent
  |
Child # Checkpoint=True
  • Parameters
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • subtests (pytest.Subtests)
  • Return type
    • None

๐Ÿ’œ testNewCheckpointIsLeafVertexRootCase(tmp_path, subtests)

This is the test for issue #1466, where detecting checkpoint jobs that aren't leaf vertices was skipping the workflow root job ๐Ÿ™ƒ It checks that a new checkpoint job is a leaf vertex, starting from a baseline workflow that's just one root job:

Root # Checkpoint=True
  • Parameters
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • subtests (pytest.Subtests)
  • Return type
    • None

๐Ÿ’œ runNewCheckpointIsLeafVertexTest(tmp_path, subtests, createWorkflowFn)

This runs the leaf vertex check for a checkpoint job using both valid and invalid cases. Slay the coverage ๐Ÿ’–

  • Parameters
    • createWorkflowFn (collections.abc.Callable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Callable>[[], tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[toil.job.Job <#toil.job.Job>, toil.job.Job <#toil.job.Job>]]). This is the function that makes a brand new workflow and hands back a tuple of:
      • 0. the workflow root job
      • 1. a checkpoint job to test inside that workflow
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • subtests (pytest.Subtests)
  • Return type
    • None

๐Ÿ’œ runCheckpointVertexTest(workflowRootJob, checkpointJob, tmp_path, checkpointJobService=None, checkpointJobChild=None, checkpointJobFollowOn=None, expectedException=None)

This tweaks the checkpoint job based on whatever you pass in, then runs the workflow and checks for the expected exception, if there is one โœจ

  • Parameters
    • workflowRootJob (toil.job.Job <#toil.job.Job>)
    • checkpointJob (toil.job.Job <#toil.job.Job>)
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
    • checkpointJobService (Optional[toil.job.Job.Service <#toil.job.Job.Service>])
    • checkpointJobChild (Optional[toil.job.Job <#toil.job.Job>])
    • checkpointJobFollowOn (Optional[toil.job.Job <#toil.job.Job>])
    • expectedException (Optional[type </usr/share/doc/python3/html/library/functions.html#type>[Exception </usr/share/doc/python3/html/library/exceptions.html#Exception>]])
  • Return type
    • None

๐Ÿ’œ testEvaluatingRandomDAG(tmp_path)

This randomly generates test input, then checks that the job graph runs successfully. It uses the existence of promises to validate the run ๐ŸŽ€

  • Parameters
    • tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • Return type
    • None

๐Ÿ’œ static getRandomEdge(nodeNumber)

A static helper that gives you a random edge ๐ŸŽฒ

  • Parameters
    • nodeNumber (int </usr/share/doc/python3/html/library/functions.html#int>)
  • Return type
    • tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[int </usr/share/doc/python3/html/library/functions.html#int>, int </usr/share/doc/python3/html/library/functions.html#int>]

๐Ÿ’œ static makeRandomDAG(nodeNumber)

Makes a random DAG with "nodeNumber" nodes, where every node is connected. The return value is a list of edges, each one shaped like (a, b), where a and b are integers >= 0 and < nodeNumber that refer to nodes, and the edge goes from a to b ๐Ÿงฉ

heads up bestie ๐Ÿ‘€ the words say "list" but the return type below says set. Both are in the original, so I'm flagging the mismatch and not picking one for you.
  • Parameters
    • nodeNumber (int </usr/share/doc/python3/html/library/functions.html#int>)
  • Return type
    • set </usr/share/doc/python3/html/library/stdtypes.html#set>[tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[int </usr/share/doc/python3/html/library/functions.html#int>, int </usr/share/doc/python3/html/library/functions.html#int>]]

๐Ÿ’œ static getAdjacencyList(nodeNumber, edges)

Builds an adjacency list representation of the edges ๐ŸŒธ

  • Parameters
    • nodeNumber (int </usr/share/doc/python3/html/library/functions.html#int>)
  • edges (set[tuple[int, int]]) ๐Ÿฆ‹ the set of int pairs that link the nodes together

Return type

list[set[int]] ๐Ÿ’–

reachable(node, adjacencyList) โœจ

Hunts down every node you can reach from this one, and yes, the node itself counts too ๐Ÿ’… It hands back a set of integers ๐ŸŒธ

Parameters

  • node (int)
  • adjacencyList (list[set[int]])

Return type

set[int]

addRandomFollowOnEdges(childAdjacencyList) ๐ŸŽ€

Adds random follow on edges to the graph, which is stored as an adjacency list ๐Ÿงš The follow on edges come back as a set, and their augmented edges get added right into the adjacency list โœจ

Parameters

  • childAdjacencyList (list[set[int]])

Return type

set[tuple[int, int]]

makeJobGraph(nodeNumber, childEdges, followOnEdges, outPath, addServices=True) ๐Ÿ‘‘

Converts a DAG into a job graph ๐ŸŒˆ childEdges and followOnEdges are the lists of child and followOn edges ๐Ÿซถ

Parameters

  • nodeNumber (int)
  • childEdges (set[tuple[int, int]])
  • followOnEdges (set[tuple[int, int]])
  • outPath (Optional[pathlib.Path])
  • addServices (bool)

Return type

toil.job.Job

isAcyclic(adjacencyList) ๐Ÿ’€

Returns true if there are any cycles in the graph, which is represented as an adjacency list ๐Ÿ”

Parameters

  • adjacencyList (list[set[int]])

Return type

bool

toil.test.src.jobTest.simpleJobFn(job, value) ๐Ÿงš

Parameters

  • job (toil.job.ServiceHostJob)
  • value (str)

Return type

None

toil.test.src.jobTest.fn1Test(string, outputFile) ๐Ÿฆ‹

This function appends the next character after the last character in the given string to the string, writes the string to a file, and returns it. For example, if the string is "AB", we write and return "ABC" ๐Ÿ’–

Parameters

  • string (str)
  • outputFile (toil.lib.misc.FileDescriptorOrPath)

Return type

str

toil.test.src.jobTest.fn2Test(pStrings, s, outputFile) ๐Ÿซถ

This function concatenates the strings in pStrings and s, in that order, and writes the result to the output file. It returns s โœจ

Parameters

  • pStrings (list[str])
  • s (str)
  • outputFile (pathlib.Path)

Return type

str

toil.test.src.jobTest.trivialParent(job) ๐ŸŒธ

Parameters

  • job (toil.job.Job)

Return type

None

toil.test.src.jobTest.parent(job) ๐Ÿ‘ช

Parameters

  • job (toil.job.Job)

Return type

None

toil.test.src.jobTest.diamond(job) ๐Ÿ’Ž

Parameters

  • job (toil.job.Job)

Return type

None

toil.test.src.jobTest.child(job) ๐Ÿ“

Parameters

  • job (toil.job.Job)

Return type

None

toil.test.src.jobTest.errorChild(job) ๐Ÿ™ˆ

Parameters

  • job (toil.job.Job)

Return type

NoReturn


class toil.test.src.jobTest.TrivialService(message, *args, **kwargs) ๐ŸŒท

Bases: toil.job.Job.Service ๐Ÿ‘‘

This is an abstract class used to define the interface to a service. You should subclass it yourself to define your own services ๐Ÿ’… It is not executed as a job. It runs inside a ServiceHostJob ๐Ÿ 

Parameters

  • message (str)
  • args (Any)
  • kwargs (Any)

message

start(job) ๐Ÿš€

Starts the service โœจ

Parameters

  • job (toil.job.ServiceHostJob): the underlying host job the service runs in. You can use it to register deferred functions, or to get at the fileStore for making temporary files ๐Ÿงš

Returns

An object describing how to access the service. It has to be pickleable, and jobs will use it to reach the service (see toil.job.Job.addService()) ๐Ÿฆ‹

Return type

str

stop(job) ๐Ÿ›‘

Stops the service. This function can block until it's totally done ๐Ÿ’€

Parameters

  • job (toil.job.ServiceHostJob): the underlying host job the service runs in. You can use it to register deferred functions, or to get at the fileStore for making temporary files ๐Ÿงš

Return type

None

check() ๐Ÿ”

Checks that the service is still running ๐Ÿ’–

Raises

  • exceptions.RuntimeError: if the service failed, this makes the service job get labeled failed ๐Ÿ˜ญ

Returns

True if the service is still running, else False. If it's False, the service job gets terminated and counts as a success ๐ŸŽ€

Important point: if the service job exits because of a failure, it should raise a RuntimeError, not return False! ๐Ÿšจ

Return type

bool

toil.test.src.miscTests ๐ŸŒˆ

Attributes โœจ

  • log (no value given)

โœจ Classes โœจ

okay so here's the lineup ๐Ÿ’–

  • TestMisc โ€” the grab bag ๐Ÿงบ home for miscellaneous tests that are too small to get their own test file โœจ
  • TestPanic โ€” (no description for this one ๐Ÿ™ˆ)

โœจ Module Contents โœจ

the log file is toil.test.src.miscTests.log ๐Ÿ“

๐Ÿฆ‹ class toil.test.src.miscTests.TestMisc

bestie, this is the misc class ๐ŸŽ€ it's for tests that are too small for their own file and don't fit neatly into any other test suite, so they live here ๐Ÿ’…

testIDStability()

  • Return type: None

testGetSizeOfDirectoryWorks(tmp_path)

this one is lowkey important ๐Ÿ˜ญ it checks that toil.common.getDirSizeRecursively never underestimates how much disk space you'll need ๐Ÿ’พ allocation is different on every system, so the computed number should always be equal to or slightly bigger than the creation value. the test makes a pile of random directories and randomly sized files, then runs getDirSizeRecursively on them to make sure it's giving the right vibes ๐Ÿ”ฅ

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: None

test_atomic_install(tmp_path)

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: None

test_atomic_install_dev()

  • Return type: None

test_atomic_context_ok(tmp_path)

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: None

test_atomic_context_error(tmp_path)

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: None

test_call_command_ok()

  • Return type: None

test_call_command_err()

  • Return type: None

๐Ÿงฏ class toil.test.src.miscTests.TestPanic

this class has no description, so we're just gonna vibe ๐Ÿซถ

test_panic_by_hand()

  • Return type: None

test_panic()

  • Return type: None

test_panic_with_secondary()

  • Return type: None

test_nested_panic()

  • Return type: None

try_and_panic_by_hand()

  • Return type: None

try_and_panic()

  • Return type: None

try_and_panic_with_secondary()

  • Return type: None

try_and_nested_panic_with_secondary()

  • Return type: None

โœจ toil.test.src.promisedRequirementTest โœจ

โœจ Attributes โœจ

  • log โ€” (blank, nothing to see here ๐Ÿ™ˆ)

โœจ Classes โœจ

  • AbstractPromisedRequirementsTest โ€” an abstract base class for testing Toil workflows with promised requirements ๐Ÿ’–
  • TestSingleMachinePromisedRequirements โ€” tests against the SingleMachine batch system ๐Ÿ”ฅ
  • TestMesosPromisedRequirements โ€” tests against the Mesos batch system ๐ŸŒˆ

โœจ Functions โœจ

  • maxConcurrency(job, cpuCount, filename, coresPerJob) โ€” returns the max number of concurrent tasks when you're using a PromisedRequirement instance ๐Ÿ‘‘
  • getOne() โ€” (no description ๐Ÿ™ˆ)
  • getThirtyTwoMb() โ€” (no description ๐Ÿ™ˆ)
  • logDiskUsage(job, funcName[, sleep]) โ€” logs the job's disk usage to master, then sleeps for however long you specified ๐Ÿ˜ด

โœจ Module Contents โœจ

the log file is toil.test.src.promisedRequirementTest.log ๐Ÿ“

๐ŸŒธ class toil.test.src.promisedRequirementTest.AbstractPromisedRequirementsTest

  • Bases: toil.test.batchSystems.batchSystemTest.AbstractBatchSystemJobTest <#toil.test.batchSystems.batchSystemTest.AbstractBatchSystemJobTest>

this is the abstract base class for testing Toil workflows with promised requirements, so it's the foundation everything else is built on ๐Ÿงฑ

testConcurrencyDynamic(tmp_path)

asserts that promised core resources get allocated properly when you're running a dynamic Toil workflow โœจ

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: None

testConcurrencyStatic(tmp_path)

same energy, but this time it asserts that promised core resources get allocated properly using a static DAG ๐Ÿ’…

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: None

getOptions(tempDir, caching=True)

configures the options for a Toil workflow and makes the job store ๐ŸŽ€

  • Parameter tempDir (str): path to the test directory
  • Returns a Toil options object ๐Ÿ’–
  • Parameters:
    • tempDir (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • caching (bool, /usr/share/doc/python3/html/library/functions.html#bool)
  • Return type: argparse.Namespace (/usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

getCounterPath(tempDir)

returns the path to a counter file ๐Ÿงš

  • Parameter tempDir: path to the test directory
  • Returns the path to the counter file
  • Parameters:
    • tempDir (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: pathlib.Path (/usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

testPromisesWithJobStoreFileObjects(tmp_path, caching=True)

okay this one is giving main character energy ๐Ÿ‘‘ it checks that FileID objects get pickled properly when they're used as return values from functions. then it makes sure lambdas of promised FileID objects can describe the requirements of a later job, which is a super common move in Toil scripts ๐Ÿ”ฅ returns None.

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • caching (bool, /usr/share/doc/python3/html/library/functions.html#bool)
  • Return type: None

testPromisesWithNonCachingFileStore(tmp_path)

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: None

testPromiseRequirementRaceStatic(tmp_path)

checks for a race condition when you're using promised requirements together with child job functions ๐Ÿ˜ญ we do not want race conditions, bestie ๐Ÿ™…โ€โ™€๏ธ

  • Parameters:
    • tmp_path (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type: None

toil.test.src.promisedRequirementTest.maxConcurrency(job, cpuCount, filename, coresPerJob)

Okay bestie, this one is the MVP ๐Ÿ‘‘ It hands back the max number of concurrent tasks when you're using a PromisedRequirement instance to allocate cores per job โœจ

Parameters

  • cpuCount (int, /usr/share/doc/python3/html/library/functions.html#int) โ€” number of available cpus ๐Ÿซถ
  • filename (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path) โ€” path to counter file ๐Ÿฆ‹
  • coresPerJob (int, /usr/share/doc/python3/html/library/functions.html#int) โ€” number of cores assigned to each job ๐Ÿ’œ
  • job (toil.job.Job) ๐ŸŒธ

Returns โ€” max concurrency value per CPU ๐Ÿ’–

Return type โ€” list[toil.job.Promise] (list: /usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿ“

toil.test.src.promisedRequirementTest.getOne()

Iconic, it just returns an int ๐Ÿ’…

Return type โ€” int (/usr/share/doc/python3/html/library/functions.html#int)

toil.test.src.promisedRequirementTest.getThirtyTwoMb()

This one gives you a str back, no cap ๐Ÿงš

Return type โ€” str (/usr/share/doc/python3/html/library/stdtypes.html#str)

toil.test.src.promisedRequirementTest.logDiskUsage(job, funcName, sleep=0)

Okay so this one logs the job's disk usage to master and then naps for whatever amount of time you give it ๐Ÿ˜ด๐ŸŒˆ

Returns โ€” job function's disk usage โœจ

Parameters

  • job (toil.job.JobFunctionWrappingJob) ๐ŸŽ€
  • funcName (str, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’œ
  • sleep (int, /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿ™ˆ

Return type โ€” int (/usr/share/doc/python3/html/library/functions.html#int)

class toil.test.src.promisedRequirementTest.TestSingleMachinePromisedRequirements

Bases: AbstractPromisedRequirementsTest ๐ŸŒธ

This class is the test suite that runs against the SingleMachine batch system ๐Ÿ’–

  • getBatchSystemName() โ€” Return type: (str (/usr/share/doc/python3/html/library/stdtypes.html#str), AbstractBatchSystem) โœจ
  • tearDown() โ€” Return type: None ๐Ÿซถ

class toil.test.src.promisedRequirementTest.TestMesosPromisedRequirements

Bases: AbstractPromisedRequirementsTest, toil.batchSystems.mesos.test.MesosTestSupport ๐Ÿ”ฅ

This one is the Mesos batch system test suite, and it's giving main character energy ๐Ÿ‘‘

  • mesos_support() โ€” Return type: collections.abc.Generator (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator)[None] ๐Ÿงš
  • getOptions(tempDir, caching=True) โ€” Okay this one configures options for the Toil workflow and makes the job store ๐Ÿ’… Here's the docstring, verbatim: :param str tempDir: path to test directory and :return: Toil options object ๐ŸŒˆ

Parameters

  • tempDir (pathlib.Path, /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path) ๐Ÿฆ‹
  • caching (bool, /usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’œ

Return type โ€” argparse.Namespace (/usr/share/doc/python3/html/library/argparse.html#argparse.Namespace) โœจ

  • getBatchSystemName() โ€” Return type: (str (/usr/share/doc/python3/html/library/stdtypes.html#str), AbstractBatchSystem) ๐Ÿ“

๐ŸŒธ toil.test.src.promisesTest ๐ŸŒธ

Classes

  • CachedUnpicklingJobStoreTest โ€” Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ
  • ChainedIndexedPromisesTest โ€” Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ
  • PathIndexingPromiseTest โ€” Test support for indexing promises of arbitrarily nested data structures of lists, dicts and ๐Ÿฆ‹

Functions

  • parent(job) ๐Ÿงš
  • child() ๐Ÿงš
  • a(job) ๐Ÿงš
  • b(job) ๐Ÿงš
  • c() ๐Ÿงš
  • d(job) ๐Ÿงš
  • e() ๐Ÿงš

Module Contents

  • toil.test.src.promisesTest.CachedUnpicklingJobStoreTest(methodName='runTest') โ€” Bases: toil.test.ToilTest ๐Ÿ’–

Legacy common base class for Toil tests. Okay so, new tests should be made in the 'pytest' style and not use this class, bestie ๐Ÿ™…โ€โ™€๏ธ

When you run tests you can optionally set the TOIL_TEST_TEMP environment variable to the path of a directory where you want temporary test files placed. The directory gets created if it doesn't exist. The path can be relative, in which case it's relative to the project root. If TOIL_TEST_TEMP isn't defined, temp files and directories get created in the system's default location for such files, and any temp files or directories left over from tests get removed automatically during tear down. Otherwise, left-over files will not be removed ๐Ÿซถ

  • test() โ€” Runs two identical Toil workflows with different job store paths ๐Ÿ”ฅ
  • toil.test.src.promisesTest.parent(job) ๐ŸŒˆ
  • toil.test.src.promisesTest.child() ๐ŸŒˆ
  • toil.test.src.promisesTest.ChainedIndexedPromisesTest(methodName='runTest') โ€” Bases: toil.test.ToilTest ๐Ÿ’…

Legacy common base class for Toil tests. New tests should be made in the 'pytest' style and not use this class ๐Ÿ™…โ€โ™€๏ธ

Same vibe with the env var: optionally set TOIL_TEST_TEMP to a directory for temporary test files. The directory gets created if it doesn't exist. The path may be relative, in which case it's assumed to be relative to the project root. If TOIL_TEST_TEMP is not defined, temporary files and directories get created in the system's default location for such files, and any temporary files or directories left over from tests will be removed automatically during tear down. Otherwise, left-over files will not be removed ๐Ÿฆ‹

  • test() ๐ŸŽ€
  • toil.test.src.promisesTest.a(job) ๐Ÿงš
  • toil.test.src.promisesTest.b(job) ๐Ÿงš
  • toil.test.src.promisesTest.c() ๐Ÿงš
  • toil.test.src.promisesTest.PathIndexingPromiseTest(methodName='runTest') โ€” Bases: toil.test.ToilTest ๐ŸŒธ

Test support for indexing promises of arbitrarily nested data structures of lists, dicts and tuples, or any other object supporting the __getitem__() protocol. Bestie, this one is a whole vibe ๐Ÿ’œ

  • test() โœจ
  • toil.test.src.promisesTest.d(job) ๐Ÿงš
  • toil.test.src.promisesTest.e() ๐Ÿงš

๐ŸŒˆ toil.test.src.realtimeLoggerTest ๐ŸŒˆ

Classes

  • RealtimeLoggerTest โ€” Legacy common base class for Toil tests ๐Ÿ•ฐ๏ธ
  • MessageDetector โ€” Detect the secret message and set a flag ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • LogTest โ€” Class represents a unit of work in toil ๐Ÿ’–

Module Contents

  • toil.test.src.realtimeLoggerTest.RealtimeLoggerTest(methodName='runTest') โ€” Bases: toil.test.ToilTest ๐Ÿ’œ

Legacy common base class for Toil tests. New tests should be made in the 'pytest' style and not use this class. Periodt ๐Ÿ’…

When you run tests, you can optionally set the TOIL_TEST_TEMP environment variable ๐Ÿงš to the path of a directory where your temporary test files should go ๐Ÿ’–. If that directory doesn't exist yet, it gets created for you โœจ. The path can be relative, and if it is, it's counted from the project root ๐ŸŒธ. If TOIL_TEST_TEMP isn't defined, temp files and directories land in your system's default spot for that stuff, and any leftover temp files or directories from tests get cleaned up automatically during tear down ๐Ÿงน. If you do set it, leftover files stick around and don't get removed ๐Ÿ‘€.

testRealtimeLogger() ๐ŸŽ€

๐Ÿ’Œ class toil.test.src.realtimeLoggerTest.MessageDetector

Bases: logging.StreamHandler </usr/share/doc/python3/html/library/logging.handlers.html#logging.StreamHandler> ๐Ÿฆ‹

This class is all about detecting the secret message ๐Ÿคซ and setting a flag when it shows up ๐Ÿšฉ.

  • detected = False
  • overLogged = False

๐Ÿ’ฌ emit(record)

Emit a record. ๐Ÿ“

If a formatter is specified, it gets used to format the record. The record is then written to the stream with a trailing newline. If exception information is present, it's formatted with traceback.print_exception and tacked onto the stream. If the stream has an 'encoding' attribute, that's what decides how the output gets written to the stream. Iykyk ๐Ÿ’…

๐Ÿ’– class toil.test.src.realtimeLoggerTest.LogTest

Bases: toil.job.Job <#toil.job.Job> โœจ

Class represents a unit of work in toil. ๐Ÿ“

๐Ÿ› ๏ธ run(fileStore)

Override this function to perform work and dynamically create successor jobs. Main character energy ๐Ÿ‘‘

Parameters

  • fileStore -- Used to create local and globally sharable temporary files and to send log messages to the leader process. ๐Ÿ“ฌ

Returns: the return value of the function can be passed to other jobs by means of toil.job.Job.rv() <#toil.job.Job.rv>. ๐ŸŽ


๐ŸŒˆ toil.test.src.regularLogTest

๐Ÿงพ Attributes

  • logger

๐Ÿ“š Classes

  • RegularLogTest

๐ŸŒธ Module Contents

toil.test.src.regularLogTest.logger

๐ŸŒท class toil.test.src.regularLogTest.RegularLogTest

  • testLogToMaster() โ€” Return type: None ๐Ÿ’œ
  • testWriteLogs(tmp_path) โ€” Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿงช
  • testWriteGzipLogs(tmp_path) โ€” Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿ—œ๏ธ
  • testMultipleLogToMaster() โ€” Return type: None ๐Ÿ”
  • testRegularLog() โ€” Return type: None ๐Ÿฅฐ

๐Ÿฆ‹ toil.test.src.resourceTest

๐Ÿงธ Classes

  • TestResource โ€” Test module descriptors and resources derived from them. ๐ŸŽ€

๐Ÿช„ Functions

  • tempFileContaining(directory, content[, suffix]) โ€” Write a file with the given contents, and keep it on disk as long as the context is active. ๐Ÿ“„

๐ŸŒธ Module Contents

โœจ toil.test.src.resourceTest.tempFileContaining(directory, content, suffix='')

Write a file with the given contents, and keep it on disk as long as the context is active. :param str content: The contents of the file. :param str suffix: The extension to use for the temporary file. ๐Ÿ—‚๏ธ

Parameters

  • directory (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>)
  • content (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
  • suffix (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str> ๐Ÿ’ซ

๐Ÿซง class toil.test.src.resourceTest.TestResource

Test module descriptors and resources derived from them. ๐ŸŒท

  • testStandAlone(tmp_path) โ€” Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿงโ€โ™€๏ธ
  • testPackage(tmp_path) โ€” Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿ“ฆ
  • testVirtualEnv(tmp_path) โ€” Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿ
  • testStandAloneInPackage(tmp_path) โ€” Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿงฉ
  • testBuiltIn() โ€” Return type: None ๐Ÿ 
  • testNonPyStandAlone(tmp_path) โ€” Asserts that Toil enforces the user script to have a .py or .pyc extension, because that's the only way auto-deployment can re-import the module on a worker. See <https://github.com/BD2KGenomics/toil/issues/631> and <https://github.com/BD2KGenomics/toil/issues/858>. ๐Ÿšซ
Heads up bestie: a user script must end in .py or .pyc or auto-deployment can't re-import it on a worker ๐Ÿ˜ญ

Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿ’…


๐Ÿ‘ toil.test.src.restartDAGTest

๐Ÿ“Œ Attributes

  • logger

๐ŸŽ€ Classes

  • TestRestartDAG โ€” Tests that restarted job DAGs don't run children of jobs that failed in the first run till the parent completes successfully in the restart. ๐Ÿ”„

๐Ÿง Functions

  • passingFn(job[, file]) โ€” This function is guaranteed to pass, because it does nothing out of the ordinary. โœ…
  • failingFn(job, failType, file) โ€” This function is guaranteed to fail via a raised assertion, or an os.kill. ๐Ÿ’ฅ

๐ŸŒผ Module Contents

toil.test.src.restartDAGTest.logger

๐ŸŒบ class toil.test.src.restartDAGTest.TestRestartDAG

Tests that restarted job DAGs don't run children of jobs that failed in the first run till the parent completes successfully in the restart. ๐Ÿซถ

  • testRestartedWorkflowSchedulesCorrectJobsOnFailedParent(tmp_path) โ€” Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿ—“๏ธ
  • testRestartedWorkflowSchedulesCorrectJobsOnKilledParent(tmp_path) โ€” Parameters: tmp_path (pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>). Return type: None ๐Ÿ”ช

๐ŸŒŸ toil.test.src.restartDAGTest.passingFn(job, file=None)

This function is guaranteed to pass, because it does nothing out of the ordinary. โœ…

If "file" is provided, it will be created. ๐Ÿ“

Parameters

  • file (Optional[pathlib.Path </usr/share/doc/python3/html/library/pathlib.html#pathlib.Path>]) -- The path of a file that must be created if provided. ๐Ÿ—ƒ๏ธ
  • job (toil.job.Job <#toil.job.Job>) ๐Ÿงƒ

Return type: None ๐Ÿซง

๐Ÿ’ฅ toil.test.src.restartDAGTest.failingFn(job, failType, file)

This function is guaranteed to fail via a raised assertion, or an os.kill ๐Ÿ˜ญ

Parameters

  • job (toil.job.Job, see #toil.job.Job) โ€” the Job itself ๐Ÿ’…
  • failType (str, see /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” 'raise' or 'kill ๐Ÿ’ฅ
  • file (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path) โ€” the path of a file that must be created ๐Ÿ“

Return type: None ๐Ÿซถ


๐ŸŽ€ toil.test.src.resumabilityTest

Classes

Functions

  • parent(job) โ€” sets up a bunch of dummy child jobs, plus a bad job that needs to be restarted as the follow-on ๐ŸŒธ
  • chaining_parent(job) โ€” sets up a failing job for something to chain to ๐Ÿฆ‹
  • goodChild(job) โ€” does nothing. Literally nothing. Iconic ๐Ÿ˜ด
  • badChild(job) โ€” fails the first time it's run, then succeeds the second time ๐Ÿ™ˆ

Module Contents

  • toil.test.src.resumabilityTest.TestResumability โ€” the class again, same issue link: https://github.com/BD2KGenomics/toil/issues/808 โœจ
    • test(tmp_path) โ€” checks that a toil workflow which fails once can be resumed without a NoSuchJobException ๐Ÿงช
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
    • test_chaining(tmp_path) โ€” checks that a job which is chained to and fails can resume and succeed ๐Ÿ”—
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
  • toil.test.src.resumabilityTest.parent(job) โ€” sets up a bunch of dummy child jobs, and a bad job that needs to be restarted as the follow-on ๐ŸŒŸ
    • Parameters: job (toil.job.Job, see #toil.job.Job)
    • Return type: None
  • toil.test.src.resumabilityTest.chaining_parent(job) โ€” sets up a failing job to chain to ๐Ÿฆ‹
    • Parameters: job (toil.job.Job, see #toil.job.Job)
    • Return type: None
  • toil.test.src.resumabilityTest.goodChild(job) โ€” does nothing ๐Ÿ˜ด
    • Parameters: job (toil.job.Job, see #toil.job.Job)
    • Return type: None
  • toil.test.src.resumabilityTest.badChild(job) โ€” fails the first time it's run, succeeds the second time ๐Ÿ™ˆ
    • Parameters: job (toil.job.JobFunctionWrappingJob, see #toil.job.JobFunctionWrappingJob)
    • Return type: None

๐Ÿงš toil.test.src.retainTempDirTest

Classes

  • TestCleanWorkDir โ€” tests testing :class:toil.fileStores.abstractFileStore.AbstractFileStore ๐Ÿงน

Functions

  • tempFileTestJob(job) ๐Ÿ“
  • tempFileTestErrorJob(job) ๐Ÿ“

Module Contents

  • toil.test.src.retainTempDirTest.TestCleanWorkDir โ€” tests testing :class:toil.fileStores.abstractFileStore.AbstractFileStore ๐Ÿ’…
    • testNever(tmp_path)
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
    • testAlways(tmp_path)
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
    • testOnErrorWithError(tmp_path)
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
    • testOnErrorWithNoError(tmp_path)
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
    • testOnSuccessWithError(tmp_path)
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
    • testOnSuccessWithSuccess(tmp_path)
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
  • toil.test.src.retainTempDirTest.tempFileTestJob(job) ๐Ÿ“
    • Parameters: job (toil.job.JobFunctionWrappingJob, see #toil.job.JobFunctionWrappingJob)
    • Return type: None
  • toil.test.src.retainTempDirTest.tempFileTestErrorJob(job) ๐Ÿ“
    • Parameters: job (toil.job.JobFunctionWrappingJob, see #toil.job.JobFunctionWrappingJob)
    • Return type: None

๐ŸŒˆ toil.test.src.systemTest

Classes

  • TestSystem โ€” tests various assumptions about the operating system's behavior ๐Ÿ–ฅ๏ธ

Module Contents

  • toil.test.src.systemTest.TestSystem โ€” tests various assumptions about the operating system's behavior ๐Ÿง 
    • testAtomicityOfNonEmptyDirectoryRenames(tmp_path) โ€” checks how directory renames behave when the directory isn't empty ๐Ÿ“‚
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None

๐Ÿฆ‹ toil.test.src.threadingTest

Attributes

  • log ๐Ÿ“œ

Classes

  • TestThreading โ€” tests Toil's threading and synchronization tools ๐Ÿ”’

Module Contents

  • toil.test.src.threadingTest.log โ€” the log attribute ๐Ÿ“œ
  • toil.test.src.threadingTest.TestThreading โ€” tests Toil's threading and synchronization tools ๐Ÿ”’
    • testGlobalMutexOrdering(tmp_path) โ€” the global mutex ordering test, no cap ๐Ÿ”
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
    • testLastProcessStanding(tmp_path) โ€” the last-process-standing test ๐Ÿ†
      • Parameters: tmp_path (pathlib.Path, see /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None

๐Ÿฆ‹ toil.test.src.toilContextManagerTest ๐Ÿฆ‹

๐Ÿ“ Classes

               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
               โ”‚ ToilContextManagerTest โ”‚ Legacy common base class   โ”‚
               โ”‚                        โ”‚ for Toil tests.            โ”‚
               โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
               โ”‚ HelloWorld             โ”‚ Class represents a unit of โ”‚
               โ”‚                        โ”‚ work in toil.              โ”‚
               โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
               โ”‚ FollowOn               โ”‚ Class represents a unit of โ”‚
               โ”‚                        โ”‚ work in toil.              โ”‚
               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โœจ Functions โœจ

                                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”
                                โ”‚ childFn(job) โ”‚   โ”‚
                                โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜

๐Ÿ’… Module Contents ๐Ÿ’…

๐Ÿ’– class toil.test.src.toilContextManagerTest.ToilContextManagerTest(methodName='runTest')

Bases: toil.test.ToilTest <#toil.test.ToilTest>

okay so this is the legacy common base class for Toil tests ๐Ÿ™ˆ It's giving old-school, so new tests should be made in the pytest style and not use this class, bestie ๐Ÿ’œ

When running tests you can optionally set the TOIL_TEST_TEMP environment variable to a path where you want your temp test files to live ๐ŸŒธ The directory gets created if it doesn't exist yet. The path can be relative, and if it is, it's measured from the project root. If TOIL_TEST_TEMP isn't set, temp files and directories go into the system's default spot for that stuff, and any leftovers get cleaned up automatically during tear down โœจ If you do set it, left-over files stick around and won't be removed.

  • setUp() โ€” Hook method for setting up the test fixture before exercising it.
  • tearDown() โ€” Hook method for deconstructing the test fixture after testing it.
  • testContextManger()
  • testNoContextManger()
  • testExportAfterFailedExport()

๐Ÿงš class toil.test.src.toilContextManagerTest.HelloWorld

Bases: toil.job.Job <#toil.job.Job>

Class represents a unit of work in toil. It's your little job bestie ๐Ÿซถ

  • run(fileStore) โ€” Override this function to perform work and dynamically create successor jobs.
    • Parameters: fileStore โ€” used to create local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“
    • Returns: The return value of the function can be passed to other jobs by means of toil.job.Job.rv() <#toil.job.Job.rv>. ๐Ÿฆ‹

โœจ toil.test.src.toilContextManagerTest.childFn(job)

๐ŸŒˆ class toil.test.src.toilContextManagerTest.FollowOn(fileId)

Bases: toil.job.Job <#toil.job.Job>

Class represents a unit of work in toil. Another job, another vibe ๐Ÿ’…

  • fileId
  • run(fileStore) โ€” Override this function to perform work and dynamically create successor jobs.
    • Parameters: fileStore โ€” used to create local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“
    • Returns: The return value of the function can be passed to other jobs by means of toil.job.Job.rv() <#toil.job.Job.rv>. ๐Ÿฆ‹

๐ŸŒธ toil.test.src.userDefinedJobArgTypeTest ๐ŸŒธ

๐Ÿ“ Classes

             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
             โ”‚ UserDefinedJobArgTypeTest โ”‚ Test for issue #423 (Toil  โ”‚
             โ”‚                           โ”‚ can't unpickle classes     โ”‚
             โ”‚                           โ”‚ defined in user scripts)   โ”‚
             โ”‚                           โ”‚ and variants               โ”‚
             โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
             โ”‚ JobClass                  โ”‚ Class represents a unit of โ”‚
             โ”‚                           โ”‚ work in toil.              โ”‚
             โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
             โ”‚ Foo                       โ”‚                            โ”‚
             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โœจ Functions โœจ

                           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”
                           โ”‚ jobFunction(job, level, โ”‚   โ”‚
                           โ”‚ foo)                    โ”‚   โ”‚
                           โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”ค
                           โ”‚ main()                  โ”‚   โ”‚
                           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜

๐Ÿ’… Module Contents ๐Ÿ’…

๐Ÿ’œ class toil.test.src.userDefinedJobArgTypeTest.UserDefinedJobArgTypeTest(methodName='runTest')

Bases: toil.test.ToilTest <#toil.test.ToilTest>

This is the test for issue #423 (Toil can't unpickle classes defined in user scripts) and all the variants of that drama ๐Ÿ˜ญ The issue lives here: https://github.com/BD2KGenomics/toil/issues/423

  • setUp() โ€” Hook method for setting up the test fixture before exercising it.
  • testJobFunction() โ€” Test with first job being a function.
  • testJobClass() โ€” Test with first job being an instance of a class.
  • testJobFunctionFromMain() โ€” Test with first job being a function defined in __main__.
  • testJobClassFromMain() โ€” Test with first job being an instance of a class defined in __main__.

๐Ÿฆ‹ class toil.test.src.userDefinedJobArgTypeTest.JobClass(level, foo)

Bases: toil.job.Job <#toil.job.Job>

Class represents a unit of work in toil. Main character job ๐Ÿ‘‘

  • level
  • foo
  • run(fileStore) โ€” Override this function to perform work and dynamically create successor jobs.
    • Parameters: fileStore โ€” used to create local and globally sharable temporary files and to send log messages to the leader process ๐Ÿ“
    • Returns: The return value of the function can be passed to other jobs by means of toil.job.Job.rv() <#toil.job.Job.rv>. ๐Ÿฆ‹

โœจ toil.test.src.userDefinedJobArgTypeTest.jobFunction(job, level, foo)

๐ŸŒˆ class toil.test.src.userDefinedJobArgTypeTest.Foo

  • original_id
  • assertIsCopy()

๐Ÿ’– toil.test.src.userDefinedJobArgTypeTest.main()


๐Ÿงš toil.test.src.workerTest ๐Ÿงš

๐Ÿ“ Classes

                     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                     โ”‚ WorkerTests โ”‚ Test miscellaneous units โ”‚
                     โ”‚             โ”‚ of the worker.           โ”‚
                     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ’… Module Contents ๐Ÿ’…

๐ŸŒธ class toil.test.src.workerTest.WorkerTests(methodName='runTest')

Bases: toil.test.ToilTest <#toil.test.ToilTest>

Tests miscellaneous units of the worker. Small but mighty ๐Ÿ”ฅ

  • setUp() โ€” Hook method for setting up the test fixture before exercising it.
  • testNextChainable() โ€” Make sure chainable and non-chainable jobs are identified correctly. โœ…

๐ŸŒˆ toil.test.utils ๐ŸŒˆ

๐Ÿ’… Submodules ๐Ÿ’…

๐Ÿฆ‹ toil.test.utils.toilDebugTest ๐Ÿฆ‹

โœจ Attributes โœจ

                                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”
                                   โ”‚ logger โ”‚   โ”‚
                                   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”˜

๐Ÿ“ Classes

                     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                     โ”‚ TestDebugJob โ”‚ Test the toil debug-job โ”‚
                     โ”‚              โ”‚ command.                โ”‚
                     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โœจ Functions โœจ

okay bestie, here's the squad of helper functions in this module ๐Ÿ’…

  • workflow_debug_jobstore(tmp_path)
  • testJobStoreContents(tmp_path) โ€” a test that checks toilDebugFile.printContentsOfJobStore() ๐Ÿซถ
  • fetchFiles(symLink, jobStoreDir, outputDir) โ€” the fn that powers testFetchJobStoreFiles() and testFetchJobStoreFilesWSymlinks() โœจ
  • testFetchJobStoreFiles(tmp_path) โ€” checks toilDebugFile.fetchJobStoreFiles() with symlinks ๐Ÿฆ‹

โœจ Module Contents โœจ

๐ŸŒธ toil.test.utils.toilDebugTest.logger

๐Ÿงš toil.test.utils.toilDebugTest.workflow_debug_jobstore(tmp_path)

  • Parameters
    • tmp_path (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type
    • pathlib.Path (/usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

๐Ÿ’œ toil.test.utils.toilDebugTest.testJobStoreContents(tmp_path)

Tests toilDebugFile.printContentsOfJobStore(), and bestie, the vibe is so specific ๐Ÿ™ˆ It runs a workflow that imports 'B.txt' and 'mkFile.py' into the jobStore. Then 'A.txt', 'C.txt', and 'ABC.txt' get created. The test makes sure all of these contents are actually found in the jobStore and printed. Main character energy โœจ

  • Parameters
    • tmp_path (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type
    • None

This is the helper fn for testFetchJobStoreFiles() and testFetchJobStoreFilesWSymlinks() ๐Ÿซถ It runs a workflow that imports 'B.txt' and 'mkFile.py' into the jobStore, then creates 'A.txt', 'C.txt', and 'ABC.txt'. After that, it grabs a list of those files, copies them from the jobStore into the output directory, confirms they're all there, and then deletes them. Iconic behaviour, no notes ๐Ÿ’…

  • Parameters
    • symLink (bool: /usr/share/doc/python3/html/library/functions.html#bool)
    • jobStoreDir (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • outputDir (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type
    • None

๐Ÿฆ‹ toil.test.utils.toilDebugTest.testFetchJobStoreFiles(tmp_path)

Tests toilDebugFile.fetchJobStoreFiles() symlinks, and it's giving organised โœจ

  • Parameters
    • tmp_path (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • Return type
    • None

๐Ÿ‘‘ class toil.test.utils.toilDebugTest.TestDebugJob

Tests for the toil debug-job command ๐Ÿ”ฅ

  • test_run_job(tmp_path)
    • Makes sure we can use toil debug-job to try running a job in-process. Lowkey the main event ๐ŸŽ€
    • Parameters: tmp_path (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • Return type: None
  • test_print_job_info(tmp_path)
    • Makes sure we can use --printJobInfo to pull up info on a job from a job store ๐Ÿ’–
    • Parameters: tmp_path (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • Return type: None
  • test_retrieve_task_directory(tmp_path)
    • Makes sure we can use --retrieveTaskDirectory to grab the input files for a job ๐Ÿงš
    • Parameters: tmp_path (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • Return type: None

โœจ toil.test.utils.toilKillTest โœจ

๐ŸŽ€ Attributes

  • logger
  • pkg_root

๐ŸŒท Classes

  • TestToilKill โ€” a set of test cases for "toil kill" ๐Ÿ’…
  • TestToilKillWithAWSJobStore โ€” a set of test cases for "toil kill" using the AWS job store โ˜๏ธ

๐Ÿซถ Module Contents

  • toil.test.utils.toilKillTest.logger
  • toil.test.utils.toilKillTest.pkg_root = b'.'
  • class toil.test.utils.toilKillTest.TestToilKill
    • Bases: _ToilKillTest
    • test_cwl_toil_kill(tmp_path)
      • Tests "toil kill" on a CWL workflow with a 100 second sleep. Bestie, that's a whole vibe ๐Ÿ˜ญ
      • Parameters: tmp_path (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
      • Return type: None
  • class toil.test.utils.toilKillTest.TestToilKillWithAWSJobStore
    • Bases: _ToilKillTest
    • test_cwl_toil_kill()
      • Tests "toil kill" on a CWL workflow with a 100 second sleep, but this time with the AWS job store ๐ŸŒˆ
      • Return type: None

โœจ toil.test.utils.utilsTest โœจ

๐ŸŒธ Attributes

  • logger

๐Ÿงš Classes

  • TestUtils โ€” tests the utilities Toil ships with, like stats and status, working together with restart functionality ๐Ÿ’–
  • RunTwoJobsPerWorker โ€” runs a child job with the same resources as itself, so the jobs get chained onto the same worker ๐Ÿ”ฅ

๐Ÿฆ‹ Functions

  • unsortedFile(tmp_path)
  • correctSort(unsortedFile)
  • printUnicodeCharacter()

๐Ÿ’œ Module Contents

  • toil.test.utils.utilsTest.logger
  • unsortedFile(tmp_path)
    • Parameters: tmp_path (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • Return type: collections.abc.Generator (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator) of pathlib.Path (/usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
  • correctSort(unsortedFile)
    • Parameters: unsortedFile (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)
    • Return type: list (/usr/share/doc/python3/html/library/stdtypes.html#list) of str (/usr/share/doc/python3/html/library/stdtypes.html#str)
  • class toil.test.utils.utilsTest.TestUtils
    • Tests the utilities Toil ships with, like stats and status, in conjunction with restart functionality. The vibes are immaculate ๐ŸŒˆ
    • N: int = 1000 (/usr/share/doc/python3/html/library/functions.html#int)
    • property toilMain: str (/usr/share/doc/python3/html/library/stdtypes.html#str)
      • Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)
    • cleanCommand(jobstore)
      • Parameters: jobstore (pathlib.Path: /usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

Okay, the function right above this one hands back a list[str], so you get a list of strings, bestie ๐Ÿ’…

statsCommand(jobstore) ๐Ÿ“Š

This one only needs a single thing:

  • jobstore (pathlib.Path)

And it gives you back a list[str]. Simple, slay ๐Ÿ’–

statusCommand(jobstore, failIfNotComplete=False) ๐Ÿฆ‹

Two params here, and one of them has a default:

  • jobstore (pathlib.Path)
  • failIfNotComplete (bool)

It also returns a list[str] ๐ŸŒธ

test_config_functionality(tmp_path) ๐Ÿงช

This test is lowkey a vibe check on the config file. It makes sure that creating the config file and reading it back actually works ๐Ÿ™ˆ

  • tmp_path (pathlib.Path)

Return type: None

testAWSProvisionerUtils() โ˜๏ธ

This one is a whole main character moment ๐Ÿ‘‘ It runs a bunch of the cluster utilities back to back, in this order:

  1. Launches a cluster with custom tags.
  2. Verifies the tags exist.
  3. ssh's into the cluster.
  4. Does some weird string comparisons ๐Ÿซ 
  5. Makes certain that TOIL_WORKDIR is set as expected in the ssh'ed cluster.
  6. Rsyncs a file and verifies it exists on the leader.
  7. Destroys the cluster.

Returns: nothing documented here, just the return type below.

Return type: None

testUtilsSort(tmp_path, unsortedFile, correctSort) ๐Ÿ”ฅ

This one tests the status and stats commands of the toil command line utility, using the sort example with the --restart flag. Iconic ๐Ÿ“

  • tmp_path (pathlib.Path)
  • unsortedFile (pathlib.Path)
  • correctSort (list[str])

Return type: None

testUtilsStatsSort(tmp_path, unsortedFile, correctSort) ๐Ÿ“ˆ

This one checks the stats commands on a complete run of the stats test. Very thorough, very on brand ๐Ÿ’œ

  • tmp_path (pathlib.Path)
  • unsortedFile (pathlib.Path)
  • correctSort (list[str])

Return type: None

testUnicodeSupport(tmp_path) ๐ŸŒˆ

  • tmp_path (pathlib.Path)

Return type: None

testMultipleJobsPerWorkerStats(tmp_path) ๐Ÿงš

This one covers the case where multiple jobs run on 1 worker. The goal is to make sure that every single job reports its data back, no one gets left on read ๐Ÿ“ฌ

  • tmp_path (pathlib.Path)

Return type: None

check_status(jobstore, status, status_fn, process=None, seconds=20) โฑ๏ธ

Here's the full parameter lineup:

  • jobstore (pathlib.Path)
  • status (str)
  • status_fn (collections.abc.Callable[[str], str])
  • process (Optional[subprocess.Popen[Any]])
  • seconds (int), which defaults to 20

Return type: None

testGetPIDStatus(tmp_path, unsortedFile) ๐Ÿ†”

This test makes sure that ToilStatus.getPIDStatus() behaves the way it's supposed to ๐Ÿซถ

  • tmp_path (pathlib.Path)
  • unsortedFile (pathlib.Path)

Return type: None

testGetStatusFailedToilWF(tmp_path, unsortedFile) ๐Ÿ’€

This one checks that ToilStatus.getStatus() acts right with a failing Toil workflow. Now, you could totally call this workflow by importing it and calling its main function. But if you did that, you'd lose the chance to test the 'RUNNING' functionality of getStatus(), and that's the whole point ๐Ÿ˜ค

  • tmp_path (pathlib.Path)
  • unsortedFile (pathlib.Path)

Return type: None

testGetStatusFailedCWLWF(tmp_path) ๐Ÿ”ฅ

Same energy as the one above, but this time it checks that ToilStatus.getStatus() behaves with a failing CWL workflow.

  • tmp_path (pathlib.Path)

Return type: None

testGetStatusSuccessfulCWLWF(tmp_path) โœจ

The happy path! This checks that ToilStatus.getStatus() behaves as expected with a successful CWL workflow ๐ŸŽ€

  • tmp_path (pathlib.Path)

Return type: None

testPrintJobLog(tmp_path, monkeypatch) ๐Ÿ“œ

This one tests that ToilStatus.printJobLog() can read the log from a failed command without throwing a fit ๐Ÿ’…

  • tmp_path (pathlib.Path)
  • monkeypatch (pytest.MonkeyPatch)

Return type: None

testRestartAttribute(tmp_path) ๐Ÿฆ‹

Okay, this one is the most dramatic test in the bunch ๐Ÿ˜ญ The job store should only get destroyed once we actually see a successful workflow run. So the test simulates a workflow that fails and then tries to resume without restart(). In that situation, the job store has to stick around until restart() is called. No early deletions, no cap.

  • tmp_path (pathlib.Path)

Return type: None

toil.test.utils.utilsTest.printUnicodeCharacter() ๐ŸŒธ

This function is all about the unicode vibes โœจ

Return type: None

class toil.test.utils.utilsTest.RunTwoJobsPerWorker ๐Ÿงƒ

class toil.test.utils.utilsTest.RunTwoJobsPerWorker(memory=None, cores=None, disk=None, accelerators=None, preemptible=None, preemptable=None, unitName='', checkpoint=False, displayName='', descriptionClass=None, local=None, files=None)

Bases: toil.job.Job

This class runs a child job with the same resources as itself, in an attempt to chain the jobs onto the same worker. It's giving teamwork ๐Ÿซถ

Here's everything it takes in:

  • memory (Optional[ParseableIndivisibleResource])
  • cores (Optional[ParseableDivisibleResource])
  • disk (Optional[ParseableIndivisibleResource])
  • accelerators (Optional[ParseableAcceleratorRequirement])
  • preemptible (Optional[ParseableFlag])
  • preemptable (Optional[ParseableFlag])
  • unitName (Optional[str])
  • checkpoint (Optional[bool])
  • displayName (Optional[str])
  • descriptionClass (Optional[type])
  • local (Optional[bool])
  • files (Optional[set[toil.fileStores.FileID]])

run(fileStore) ๐ŸŒŸ

This is the method you override when you want to do the actual work and dynamically spin up successor jobs. Bestie, this is where the magic happens โœจ

  • fileStore (toil.fileStores.abstractFileStore.AbstractFileStore) โ€” this is what you use to create local and globally sharable temporary files, and to send log messages to the leader process ๐Ÿ“ฌ

Okay, that's the whole vibe for this part! ๐Ÿ’œ

  • Returns โ€” okay so the return value of the function is giving handoff energy ๐ŸŽ€. You can pass it along to other jobs with toil.job.Job.rv() โœจ, no cap.
  • Return type โ€” None ๐Ÿ™ˆ

๐ŸŒธ toil.test.wdl

๐Ÿงš Submodules

  • toil.test.wdl.wdltoil_test

๐ŸŒธ toil.test.wdl.wdltoil_test

๐Ÿ”ฅ Attributes

  • logger
  • WDL_CONFORMANCE_TEST_REPO
  • WDL_CONFORMANCE_TEST_COMMIT
  • WDL_CONFORMANCE_TESTS_UNSUPPORTED_BY_TOIL
  • WDL_UNIT_TESTS_UNSUPPORTED_BY_TOIL

๐Ÿ‘‘ Classes

  • TestWDLConformance โ€” WDL conformance tests for Toil. ๐Ÿซถ
  • TestWDL โ€” Tests for Toil's MiniWDL-based implementation. ๐Ÿ’…
  • TestWDLToilBench โ€” Tests for Toil's MiniWDL-based implementation that don't run workflows. ๐Ÿงช

๐Ÿ’œ Functions

  • wdl_conformance_test_repo(tmp_path)

๐ŸŒˆ Module Contents

The logger, just vibing:

toil.test.wdl.wdltoil_test.logger

The constants are the main characters here, so here they are exactly as written:

toil.test.wdl.wdltoil_test.WDL_CONFORMANCE_TEST_REPO = 'https://github.com/DataBiosphere/wdl-conformance-tests.git'
toil.test.wdl.wdltoil_test.WDL_CONFORMANCE_TEST_COMMIT = '46b5f85ee38ec60d0b8b9c35928b5104a2af83d5'
toil.test.wdl.wdltoil_test.WDL_CONFORMANCE_TESTS_UNSUPPORTED_BY_TOIL = [16, 21, 64, 77]
toil.test.wdl.wdltoil_test.WDL_UNIT_TESTS_UNSUPPORTED_BY_TOIL = [14, 19, 52, 58, 59, 66, 67, 68, 69, 87, 97, 105, 107, 108, 109, 110, 120, 131, 134, 144]

Now the helper function. It's giving fixture energy ๐Ÿงš:

  • toil.test.wdl.wdltoil_test.wdl_conformance_test_repo(tmp_path) โ€” yep, a fixture ๐ŸŒธ
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • collections.abc.Generator[pathlib.Path]

๐Ÿ’– class toil.test.wdl.wdltoil_test.TestWDLConformance

WDL conformance tests for Toil. The whole class is a total slay ๐Ÿ’…

  • check(p) โ€” make sure a call finished, or explain why it didn't ๐Ÿ™ˆ
    • Parameters
      • p (subprocess.CompletedProcess[bytes])
    • Return type
      • None
  • test_unit_tests_v11(wdl_conformance_test_repo) ๐Ÿฆ‹
    • Parameters
      • wdl_conformance_test_repo (pathlib.Path)
    • Return type
      • None
  • test_conformance_tests_v10(wdl_conformance_test_repo) ๐Ÿฆ‹
    • Parameters
      • wdl_conformance_test_repo (pathlib.Path)
    • Return type
      • None
  • test_conformance_tests_v11(wdl_conformance_test_repo) ๐Ÿฆ‹
    • Parameters
      • wdl_conformance_test_repo (pathlib.Path)
    • Return type
      • None
  • test_conformance_tests_development(wdl_conformance_test_repo) ๐Ÿฆ‹
    • Parameters
      • wdl_conformance_test_repo (pathlib.Path)
    • Return type
      • None
  • test_conformance_tests_integration(wdl_conformance_test_repo) ๐Ÿฆ‹
    • Parameters
      • wdl_conformance_test_repo (pathlib.Path)
    • Return type
      • None

๐Ÿ’œ class toil.test.wdl.wdltoil_test.TestWDL

Tests for Toil's MiniWDL-based implementation. Main character behavior, bestie ๐Ÿ‘‘

  • base_command โ€” the attribute, no extra notes needed ๐Ÿ“
  • test_MD5sum(tmp_path) โ€” checks that Toil gives the same outputs as the known good ones from WDL's GATK tutorial #1 ๐Ÿงš
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_url_to_file(tmp_path) โ€” checks that web URL strings can be turned into usable Files ๐ŸŒˆ
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_string_file_coercion(tmp_path) โ€” checks that input Files can be turned into strings and back again ๐Ÿซถ
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_gather(tmp_path) โ€” checks files that share a name but come from different scatter tasks ๐Ÿฆ‹
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_wait(tmp_path) โ€” checks whether Bash wait works inside WDL scripts โณ
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_restart(tmp_path) โ€” checks that a WDL workflow can be restarted and still finish successfully ๐Ÿ”
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_workflow_file_deletion(tmp_path) โ€” checks whether Toil can delete non-output outputs at the very end of a workflow ๐Ÿ—‘๏ธ
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_all_call_outputs(tmp_path) โ€” checks whether Toil can collect all call outputs from a workflow that doesn't expose them ๐Ÿ“ฆ
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_croo_detection(tmp_path) โ€” checks whether Toil can detect Cromwell Output Organizer workflows and do something sensible with them ๐Ÿง 
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_caching(tmp_path) โ€” checks whether Toil can cache task runs ๐Ÿ’พ
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None
  • test_url_to_optional_file(tmp_path, httpserver) โ€” checks that missing and error-producing URLs are handled correctly for optional File? values ๐Ÿ™ˆ
    • Parameters
      • tmp_path (pathlib.Path)
      • httpserver (pytest_httpserver.HTTPServer)
    • Return type
      • None
  • test_missing_output_directory(tmp_path) โ€” checks whether Toil can run a WDL workflow into a new directory ๐ŸŒธ
    • Parameters
      • tmp_path (pathlib.Path)
    • Return type
      • None

โœจ test_miniwdl_self_test(tmp_path, extra_args=None) โœจ

okay so this one checks that the MiniWDL self test actually runs and spits out the output it's supposed to ๐Ÿงช๐Ÿ’–

  • Parameters
    • tmp_path (pathlib.Path)
    • extra_args (Optional[list[str]])
  • Return type: None

โœจ test_miniwdl_self_test_by_reference(tmp_path) โœจ

bestie, this one makes sure the MiniWDL self test still works when the input files come in as URL references instead of local copies ๐Ÿ”—๐Ÿฆ‹

  • Parameters
    • tmp_path (pathlib.Path)
  • Return type: None

โœจ test_dockstore_trs(tmp_path, extra_args=None) โœจ

this one runs the Dockstore TRS check ๐ŸŒˆ

  • Parameters
    • tmp_path (pathlib.Path)
    • extra_args (Optional[list[str]])
  • Return type: None

โœจ test_dockstore_metrics_publication(tmp_path, extra_args=None) โœจ

and this one checks that Dockstore metrics publication works ๐Ÿ“Š๐Ÿ”ฅ

  • Parameters
    • tmp_path (pathlib.Path)
    • extra_args (Optional[list[str]])
  • Return type: None

โœจ test_giraffe_deepvariant(tmp_path) โœจ

this is the big one, so bring snacks ๐Ÿฟ๐Ÿ˜ญ It checks that Giraffe and GPU DeepVariant both run. Heads up, this could take 25 minutes โฐ

  • Parameters
    • tmp_path (pathlib.Path)
  • Return type: None

โœจ test_giraffe(tmp_path) โœจ

checks that Giraffe runs ๐Ÿฆ’ Fair warning, this could take 12 minutes. We scale it down, but it still needs lots of memory, so it's giving memory-hungry ๐Ÿง ๐Ÿ’€

  • Parameters
    • tmp_path (pathlib.Path)
  • Return type: None

โœจ test_gs_uri(tmp_path) โœจ

this one makes sure Toil can actually reach Google Storage URIs โ˜๏ธ๐Ÿ’œ

  • Parameters
    • tmp_path (pathlib.Path)
  • Return type: None

โœจ test_check(tmp_path) โœจ

and last but not least, this one checks that Toil's lint check works ๐Ÿงนโœจ

  • Parameters
    • tmp_path (pathlib.Path)
  • Return type: None

โœจ class toil.test.wdl.wdltoil_test.TestWDLToilBench(methodName='runTest') โœจ

Bases: unittest.TestCase

this class is the MiniWDL-based implementation tests that don't actually run workflows ๐ŸŽ€ Basically the no-workflow-needed squad ๐Ÿ’…

โœจ test_coalesce() โœจ

checks whether WDLSectionJob can coalesce WDL decls ๐Ÿงฉ

This is a white box test, so it'll need to be changed or removed if the WDL interpreter changes. Heads up, bestie ๐Ÿ‘€
  • Return type: None

โœจ make_string_expr(to_parse, expr_type=WDL.Expr.String) โœจ

parses pseudo-WDL so we can test whitespace removal ๐Ÿซง

  • Parameters
    • to_parse (str)
    • expr_type (type[WDL.Expr.String])
  • Return type: WDL.Expr.String

โœจ test_choose_human_readable_directory() โœจ

makes sure we pick sensible directories for files, and that they don't collide with each other ๐Ÿ“๐ŸŒธ

  • Return type: None

โœจ test_uri_packing() โœจ

makes sure Toil's URI packing carries through all the info it needs ๐ŸŽ

  • Return type: None

โœจ test_disk_parse() โœจ

makes sure the disk parsing is correct ๐Ÿ’พโœจ

  • Return type: None

toil.test.wdl.wdltoil_test_kubernetes

Attributes

  • logger

Classes

  • WDLKubernetesClusterTest โ€” ensures WDL works on the Kubernetes batchsystem ๐Ÿงš

Module Contents

toil.test.wdl.wdltoil_test_kubernetes.logger

โœจ class toil.test.wdl.wdltoil_test_kubernetes.WDLKubernetesClusterTest(name) โœจ

Bases: toil.test.provisioners.clusterTest.AbstractClusterTest

this is the Kubernetes batchsystem check, and it makes sure WDL works there ๐Ÿ‘‘

  • Parameters
    • name (str)

Here are the class attributes:

  • clusterName = 'wdl-integration-test-'
  • leaderNodeType = 't2.medium'
  • instanceTypes = ['t2.medium']
  • clusterType = 'kubernetes'

setUp()

set-up for the test ๐Ÿ› ๏ธ You have to override this and call this method, and you also have to set self.jobStore, or it won't work ๐Ÿ™ˆ

  • Return type: None

launchCluster()

launches the cluster ๐Ÿš€

  • Return type: None

test_wdl_kubernetes_cluster()

checks that a WDL workflow works on a Kubernetes cluster ๐ŸŽ€ It launches a cluster with 1 worker, then runs a WDL workflow that does an image pull on that worker ๐Ÿณ :return:

  • Return type: None

Attributes

  • logger ๐Ÿ“
  • MT ๐Ÿง
  • pneeds_rsync3 ๐Ÿ”„
  • pneeds_online ๐ŸŒ
  • pneeds_aws_s3 ๐Ÿชฃ
  • pneeds_aws_ec2 ๐Ÿ’ป
  • pneeds_gridengine ๐Ÿ“
  • pneeds_torque ๐ŸŒช๏ธ
  • pneeds_kubernetes โ˜ธ๏ธ
  • pneeds_mesos ๐ŸŒฟ
  • pneeds_slurm ๐ŸŒ
  • pneeds_lsf ๐Ÿงƒ
  • pneeds_docker ๐Ÿณ
  • pneeds_local_cuda ๐ŸŸข
  • pneeds_docker_cuda ๐ŸŸฉ
  • pneeds_cwl ๐Ÿ“œ
  • pneeds_wdl ๐Ÿงฌ
  • pneeds_wes_server ๐Ÿ–ฅ๏ธ
  • pintegrative ๐Ÿซถ
  • pslow ๐Ÿข
  • methodNamePartRegex ๐Ÿ”

โœจ Exceptions โœจ

okay so this is where the error classes live ๐Ÿ’€ bestie, these are the ones you'll want to know about when things go sideways ๐Ÿซถ

  • ProxyConnectionError โ€” ๐Ÿšจ the common base class for all exceptions, so it's the big-picture one that everything else in the family is built on ๐Ÿ‘‘

๐ŸŽ€ Classes ๐ŸŽ€

these are the test classes, and they're giving old school meets new school ๐Ÿฆ‹

  • ToilTest โ€” ๐Ÿ•ฐ๏ธ the legacy common base class for Toil tests, so it's the OG that a lot of testing stuff grew out of ๐Ÿ’œ
  • ApplianceTestSupport โ€” ๐Ÿณ a Toil test that runs a user script on a minimal cluster of appliance containers, which is lowkey iconic for testing a whole workflow in a tiny mini-cluster ๐Ÿงš

โœจ Functions โœจ

okay so this is the little toolbox of test helpers ๐Ÿงฐ bestie, and these are the ones you slap on your tests to decide when they're allowed to run ๐Ÿ’…

  • get_data(filename) โ€” gives you back an absolute path ๐Ÿ—บ๏ธ to a file that lives inside this package
  • get_temp_file([suffix, rootDir]) โ€” hands you a string representing a temporary file ๐Ÿซถ but ngl, YOU have to delete it yourself because it won't clean up after you ๐Ÿ’€

The needs_* ones are the gatekeepers ๐Ÿšชโœจ each one goes above test classes or methods and only lets them run when their requirement is there.

  • needs_env_var(var_name[, comment]) โ€” use it as a decorator ๐ŸŒธ so the test only runs if the given โ€ฆ
  • needs_rsync3(test_item) โ€” decorate any classes or methods that depend on features from rsync version 3.0.0+ ๐Ÿฆ‹
  • needs_online(test_item) โ€” use it as a decorator ๐Ÿ’œ to run only if we're meant to talk to the Internet ๐ŸŒˆ
  • needs_aws_s3(test_item) โ€” use it as a decorator ๐Ÿชฃ to run only if AWS S3 is usable
  • needs_aws_ec2(test_item) โ€” use it as a decorator โ˜๏ธ to run only if AWS EC2 is usable
  • needs_aws_batch(test_item) โ€” use it as a decorator ๐Ÿ“ to run only if AWS Batchโ€ฆ
  • needs_google_storage(test_item) โ€” use it as a decorator ๐Ÿซง to run only if Googleโ€ฆ
  • needs_google_project(test_item) โ€” use it as a decorator ๐Ÿ’– to run only if we have a Google Cloud project set
  • needs_gridengine(test_item) โ€” use it as a decorator ๐Ÿงš to run only if GridEngine is installed
  • needs_torque(test_item) โ€” use it as a decorator ๐ŸŒธ to run only if PBS/Torque is installed
  • needs_kubernetes_installed(test_item) โ€” use it as a decorator โญ to run only if Kubernetes is installed
  • needs_kubernetes(test_item) โ€” use it as a decorator ๐Ÿ‘‘ to run only if Kubernetes is installed and configured
  • needs_mesos(test_item) โ€” use it as a decorator ๐Ÿ”ฅ to run only if Mesos is installed
  • needs_slurm(test_item) โ€” use it as a decorator โœจ to run only if Slurm is installed
  • needs_htcondor(test_item) โ€” use a decorator ๐Ÿฆ‹ before test classes or methods to run only if the HTCondor is installed
  • needs_lsf(test_item) โ€” use it as a decorator ๐ŸŽ€ to only run them if LSF is installed
  • needs_java(test_item) โ€” use it as a test decorator โ˜• to run only if java is installed
  • needs_docker(test_item) โ€” use it as a decorator ๐Ÿณ to only run them ifโ€ฆ
  • needs_singularity(test_item) โ€” use it as a decorator ๐Ÿซถ to only run them ifโ€ฆ
  • needs_singularity_or_docker(test_item) โ€” use it as a decorator ๐Ÿ’… to only run them ifโ€ฆ
  • needs_local_cuda(test_item) โ€” use it as a decorator ๐Ÿ™ˆ before test classes or methods toโ€ฆ
heads up bestie ๐Ÿฅบ the original page cuts off mid-sentence on a bunch of these (needs_env_var, needs_aws_batch, needs_google_storage, needs_docker, needs_singularity, needs_singularity_or_docker, needs_local_cuda), so I kept them exactly as they end. no guessing, no cap ๐Ÿซถ

โ€ฆokay so the row above wraps up with test classes or methods to only run them if ๐Ÿ‘€

  • needs_docker_cuda(test_item) โ€” slap this decorator on test classes or methods and they'll only run them if ๐ŸŽฎ (the original cuts off right there, bestie ๐Ÿ’€)
  • needs_encryption(test_item) โ€” decorator that only lets tests run if PyNaCl is installed ๐Ÿ”
  • needs_cwl(test_item) โ€” decorator for test classes or methods that only runs them if CWLTool is installed ๐Ÿงฉ
  • needs_wdl(test_item) โ€” decorator for test classes or methods that only runs them if miniwdl is installed ๐ŸŒŠ
  • needs_server(test_item) โ€” decorator for test classes or methods that only runs them if Connexion is installed. ๐Ÿ›ฐ๏ธ
  • needs_celery_broker(test_item) โ€” decorator for test classes or methods that runs them only if RabbitMQ is set up to take Celery jobs ๐Ÿ‡
  • needs_wes_server(test_item) โ€” decorator for test classes or methods that runs them only if a WES (the page cuts off here too ๐Ÿ˜ญ)
  • needs_local_appliance(test_item) โ€” decorator for test classes or methods that only runs them if (and yep, it ends there ๐Ÿซ )
  • needs_fetchable_appliance(test_item) โ€” decorator for test classes or methods that only runs them if (same story, cut off ๐Ÿซ )
  • integrative(test_item) โ€” use this to decorate integration tests so they get skipped during regular builds ๐Ÿ™ˆ
  • slow(test_item) โ€” use this decorator to flag tests that are slow and not critical ๐Ÿข
  • timeLimit(seconds) โ€” use this to cap how long a function is allowed to run โฑ๏ธ
  • make_tests(generalMethod, targetClass, **kwargs) โ€” this one dynamically generates test methods, using generalMethod as a template. Each (and that's where the original stops ๐Ÿ’…)

๐Ÿ“ฆ Package Contents

๐Ÿ’ฅ exception toil.test.ProxyConnectionError

  • Bases: BaseException (/usr/share/doc/python3/html/library/exceptions.html#BaseException)
  • It's the common base class for all exceptions, so it's giving foundation vibes ๐Ÿงฑ

๐Ÿ“ toil.test.logger

  • Just the name, no extra details, bestie ๐Ÿคทโ€โ™€๏ธ

๐Ÿ—‚๏ธ toil.test.get_data(filename)

  • Returns an absolute path for a file from this package ๐Ÿ—บ๏ธ
  • Parameters
    • filename (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type
    • contextlib.AbstractContextManager (/usr/share/doc/python3/html/library/contextlib.html#contextlib.AbstractContextManager) wrapping pathlib.Path (/usr/share/doc/python3/html/library/pathlib.html#pathlib.Path)

๐Ÿงช class toil.test.ToilTest(methodName='runTest')

  • Bases: unittest.TestCase (/usr/share/doc/python3/html/library/unittest.html#unittest.TestCase)
  • This is the legacy common base class for Toil tests. New tests should be written in the 'pytest' style and not use this class. ๐Ÿ™…โ€โ™€๏ธ
  • When running tests you can optionally set the TOIL_TEST_TEMP environment variable to a directory where you want temporary test files to go ๐Ÿ“‚. The directory gets created if it doesn't exist. A relative path is treated as relative to the project root. If TOIL_TEST_TEMP isn't defined, temp files and directories land in the system's default location, and any leftovers from tests get removed automatically during tear down ๐Ÿงน. If you did set it, leftover files will not be removed.

setup_method(method)

  • Parameters
    • method (Any)
  • Return type
    • None

classmethod setUpClass()

  • Hook method for setting up the class fixture before running the tests in the class ๐Ÿ› ๏ธ
  • Return type
    • None

classmethod tearDownClass()

  • Hook method for deconstructing the class fixture after running all the tests in the class ๐Ÿงฝ
  • Return type
    • None

setUp()

  • Hook method for setting up the test fixture before exercising it ๐ŸŽฌ
  • Return type
    • None

tearDown()

  • Hook method for deconstructing the test fixture after testing it ๐Ÿงผ
  • Return type
    • None

classmethod awsRegion()

  • Picks an appropriate AWS region. It uses us-west-2 unless you're running on EC2, in which case it uses the region where the instance is located ๐ŸŒŽ
  • Return type
    • str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŒ€ toil.test.MT

  • Just the name again, nothing else to see here ๐Ÿซถ

๐ŸŽŸ๏ธ toil.test.get_temp_file(suffix='', rootDir=None)

  • Returns a string representing a temporary file. You have to delete it manually ๐Ÿ—‘๏ธ
  • Parameters
    • suffix (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
    • rootDir (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type
    • str (/usr/share/doc/python3/html/library/stdtypes.html#str)

๐ŸŒฑ toil.test.needs_env_var(var_name, comment=None)

  • Use as a decorator before test classes or methods to run them only if the given environment variable is set. You can add a comment saying what the variable should be set to ๐Ÿ’ก
  • Parameters
    • var_name (str, /usr/share/doc/python3/html/library/stdtypes.html#str)
    • comment (Optional[str], /usr/share/doc/python3/html/library/stdtypes.html#str)
  • Return type
    • Callable[[MT], MT]

๐Ÿฆ‹ toil.test.needs_rsync3(test_item)

  • Decorate classes or methods that depend on any features from rsync version 3.0.0+ ๐Ÿขโœจ
  • It's necessary because utilsTest.testAWSProvisionerUtils() uses the option --protect-args, which is only available in rsync 3 ๐Ÿซ 

Okay so bestie, this is the part where we slap decorators on our tests and they only run when the right stuff is actually installed ๐Ÿ’…๐Ÿงš

toil.test.needs_rsync3(test_item)

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_rsync3 ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_online(test_item)

Use this as a decorator above test classes or methods and they'll only run if we're meant to talk to the Internet ๐ŸŒโœจ

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_aws_s3(test_item)

Decorator alert ๐Ÿšจ Put this on your tests and they'll only run if AWS S3 is usable. It's giving storage vibes ๐Ÿชฃ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_aws_s3 ๐Ÿฆ‹ (listed on its own, no description given)

toil.test.needs_aws_ec2(test_item)

Same energy as S3, but make it EC2. These tests only run if AWS EC2 is usable ๐Ÿ–ฅ๏ธ๐Ÿ’œ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_aws_ec2 ๐Ÿฆ‹ (listed on its own, no description given)

toil.test.needs_aws_batch(test_item)

Only runs if AWS Batch is usable. Batch-processing iconic behavior ๐Ÿ‘‘

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_google_storage(test_item)

This one's a whole mood ๐ŸŒˆ It only runs if Google Cloud is installed AND we ought to be able to reach public Google Storage URIs. Lowkey the most specific check ever ๐Ÿ˜ญ

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_google_project(test_item)

Only runs if we have a Google Cloud project set. No project, no party ๐ŸŽ€

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_gridengine(test_item)

Only runs if GridEngine is installed. Literally the vibe check for schedulers ๐Ÿ”ฅ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_gridengine ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_torque(test_item)

Only runs if PBS/Torque is installed. Ate, left no crumbs ๐Ÿ’…

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_torque ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_kubernetes_installed(test_item)

Only runs if Kubernetes is installed. That's it, that's the check ๐Ÿงš

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_kubernetes(test_item)

A step up from the last one: these only run if Kubernetes is installed AND configured. Main character energy ๐Ÿ‘‘

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_kubernetes ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_mesos(test_item)

Only runs if Mesos is installed. Okay, iconic ๐ŸŒธ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_mesos ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_slurm(test_item)

Only runs if Slurm is installed. Another HPC queen showing up ๐Ÿ‘ธ๐Ÿ’œ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_slurm ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_htcondor(test_item)

Use a decorator here (yes, just "a" decorator ๐Ÿ™ˆ) and the tests only run if HTCondor is installed.

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_lsf(test_item)

Put this on classes or methods and they'll only run if LSF is installed ๐Ÿฆ‹

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_lsf ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_java(test_item)

Use this as a test decorator and it runs only if java is installed. Simple, no drama ๐Ÿซถ

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_docker(test_item)

Only runs if docker is installed AND docker-based tests are enabled. Both boxes gotta be checked, bestie ๐Ÿณ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_docker ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_singularity(test_item)

Only runs if singularity is installed. Container energy ๐Ÿ“ฆโœจ

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_singularity_or_docker(test_item)

Lowkey the flexible one ๐Ÿฆ‹ These run if docker is installed AND docker-based tests are enabled, OR if Singularity is installed. Either one is giving enough.

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_local_cuda(test_item)

Only runs if there's a CUDA setup that cwltool can read (i.e. it's providing userspace nvidia-smi). If it's there, we're good ๐Ÿ’š

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_local_cuda ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_docker_cuda(test_item)

Only runs if a CUDA setup is available through Docker. GPU slay through containers ๐ŸŽฎ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_docker_cuda ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_encryption(test_item)

Only runs if PyNaCl is installed and configured. Locked and loaded ๐Ÿ”

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_cwl(test_item)

Only runs if CWLTool is installed and configured. CWL besties, this one's for you ๐Ÿซถ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_cwl ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_wdl(test_item)

Only runs if miniwdl is installed and configured. WDL gang, you're up ๐Ÿงš

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_wdl ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_server(test_item)

Only runs if Connexion is installed. Server stuff, sorted โœจ

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_celery_broker(test_item)

Use this to run only if RabbitMQ is set up to take Celery jobs. Bunny and celery, a power couple ๐Ÿฐ๐Ÿฅฌ

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_wes_server(test_item)

Only runs if a WES server is available to run against. No server, no test, periodt ๐Ÿ™…โ€โ™€๏ธ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pneeds_wes_server ๐ŸŒธ (listed on its own, no description given)

toil.test.needs_local_appliance(test_item)

Only runs if the Toil appliance Docker image is downloaded. We love a local copy ๐Ÿ’–

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.needs_fetchable_appliance(test_item)

Only runs if the Toil appliance Docker image is able to be downloaded from the Internet. Not downloaded yet? Doesn't matter as long as it's fetchable ๐ŸŒ

  • Parameters: test_item (MT)
  • Return type: MT

toil.test.integrative(test_item)

Use this to decorate integration tests so they get skipped during regular builds ๐Ÿ™ˆ Lowkey the best way to keep builds snappy.

We call something an integration test if A) it involves other, non-Toil software components that we develop and/or B) it has a higher cost, whether that's time or money ๐Ÿ’ธ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pintegrative ๐ŸŒธ (listed on its own, no description given)

toil.test.slow(test_item)

Use this decorator to flag tests that are slow and not critical. These get skipped if TOIL_TEST_QUICK is true ๐Ÿข๐Ÿ’œ

  • Parameters: test_item (MT)
  • Return type: MT
  • toil.test.pslow ๐ŸŒธ (listed on its own, no description given)
  • toil.test.methodNamePartRegex ๐ŸŒธ (listed on its own, no description given)

toil.test.timeLimit(seconds)

Use this to limit how long a function is allowed to run โณ If the function takes more than the specified amount of time, it raises an exception. Credit where it's due: the approach is from http://stackoverflow.com/a/601168.

  • Parameters: seconds (int) (/usr/share/doc/python3/html/library/functions.html#int) โ€” maximum allowable time, in seconds
  • Return type: collections.abc.Generator[None, None, None] (/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Generator)

Watch this ๐Ÿ‘€

>>> import time
>>> with timeLimit(2):
...    time.sleep(1)
>>> import time
>>> with timeLimit(1):
...    time.sleep(2)
Traceback (most recent call last):
    ...
RuntimeError: Timed out

The first one finishes in time, so it's all good โœจ The second one takes too long and gets a RuntimeError: Timed out ๐Ÿ’€

toil.test.make_tests(generalMethod, targetClass, **kwargs)

This one's a test-generating machine ๐Ÿญ It builds test methods dynamically, using generalMethod as the template. Every generated function is one unique combo of parameters applied to generalMethod, and each parameter gets a matching string that names the method. The generated functions follow the naming scheme test_[generalMethodName]___[firstParamaterName]_[someValueName]__[secondParamaterName]_...

The arguments after generalMethodName should be one or more dictionaries shaped like {str : type, ...}, where the key is the name of the value. Those names show up in the method name to represent which values got passed for each parameter in generalMethod.

The generated method names list parameters in lexicographic order by parameter name, so they come out tidy ๐Ÿงน๐Ÿ’…

  • Parameters:
    • generalMethod (Callable[[Any], Any]) โ€” A method that will be parameterized with values passed as kwargs. Note that the generalMethod must be a regular method ๐Ÿซถ
  • targetClass (Optional[Callable[[Any], Any]]) โ€” ๐ŸŽฏ This is the class the generated test methods get bound to. If you don't pass one, the class of the generalMethod is assumed to be the target.
  • kwargs (Any) โ€” a series of dictionaries that define values and their names, where each keyword is the name of a parameter in generalMethod. ๐Ÿ’–

Return type: None ๐Ÿ’…

>>> class Foo:
...     def has(self, num, letter):
...         return num, letter
...
...     def hasOne(self, num):
...         return num

>>> class Bar(Foo):
...     pass

>>> make_tests(Foo.has, Bar, num={'one':1, 'two':2}, letter={'a':'a', 'b':'b'})

>>> b = Bar()

Okay so, num comes lexicographically before letter, which is why it shows up first in the generated method names. ๐Ÿ‘€

>>> assert b.test_has__letter_a__num_one() == b.has(1, 'a')

>>> assert b.test_has__letter_b__num_one() == b.has(1, 'b')

>>> assert b.test_has__letter_a__num_two() == b.has(2, 'a')

>>> assert b.test_has__letter_b__num_two() == b.has(2, 'b')

>>> f = Foo()

>>> hasattr(f, 'test_has__num_one__letter_a')  # should be false because Foo has no test methods
False

๐Ÿฆ‹ class toil.test.ApplianceTestSupport(methodName='runTest')

Bases: ToilTest ๐ŸŒธ

A Toil test that runs a user script on a minimal cluster of appliance containers. i.e. one leader container and one worker container. โœจ

๐Ÿงต class Appliance(outer, mounts, cleanMounts=False)

Bases: toil.lib.threading.ExceptionalThread ๐Ÿซถ

This is a thread whose join() method re-raises exceptions that happened during run(). join() is idempotent, but the exception only gets raised during the first join() call that actually manages to join the thread. If join() times out, no exception gets re-raised, even if one might already have happened in run(). ๐Ÿ˜ญ

When you subclass this thread, override tryRun() instead of run(). ๐Ÿ’œ

>>> def f():
...     assert 0
>>> t = ExceptionalThread(target=f)
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

>>> class MyThread(ExceptionalThread):
...     def tryRun( self ):
...         assert 0
>>> t = MyThread()
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

Parameters ๐ŸŽ€

  • outer (ApplianceTestSupport)
  • mounts (dict[str, str])
  • cleanMounts (bool)

Attributes ๐Ÿงš

  • lock
  • outer
  • mounts
  • cleanMounts = False
  • containerName = ''
  • popen: subprocess.Popen[bytes] | None = None

Methods ๐Ÿ’…

  • __enter__() โ€” Return type: typing_extensions.Self.
  • __exit__(exc_type, exc_val, exc_tb) โ€” Parameters:
    • exc_type (type[BaseException])
    • exc_val (Exception)
    • exc_tb (Any)

Return type: Literal[False].

  • tryRun() โ€” Return type: None. This is the one you override when subclassing. ๐Ÿ”ฅ
  • runOnAppliance(*args, **kwargs) โ€” Parameters:
    • args (str)
    • kwargs (Any)

Return type: None.

  • writeToAppliance(path, contents) โ€” Parameters:
    • path (str)
    • contents (Any)

Return type: None.

  • deployScript(path, packagePath, script) โ€” Deploys a Python module on the appliance. โœจ Parameters:
    • path (str) โ€” the path (absolute, or relative to the WORDIR of the appliance container) to the root of the package hierarchy where the given module should be placed. The given directory should be on the Python path.
    • packagePath (str) โ€” the desired fully qualified module name (dotted form) of the module.
    • script (str|callable) โ€” the contents of the Python module. If a callable is given, its source code will be extracted. This is a convenience that lets you embed user scripts into test code as nested functions. ๐Ÿงธ

Return type: None.

๐ŸŒˆ class LeaderThread(outer, mounts, cleanMounts=False)

Bases: Appliance ๐Ÿ‘‘

This is a thread whose join() method re-raises exceptions that happened during run(). join() is idempotent, but the exception only gets raised during the first join() call that actually manages to join the thread. If join() times out, no exception gets re-raised, even if one might already have happened in run(). ๐Ÿ˜ญ

When you subclass this thread, override tryRun() instead of run(). ๐Ÿ’œ

>>> def f():
...     assert 0
>>> t = ExceptionalThread(target=f)
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

>>> class MyThread(ExceptionalThread):
...     def tryRun( self ):
...         assert 0
>>> t = MyThread()
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

Parameters ๐ŸŽ€

  • outer (ApplianceTestSupport)
  • mounts (dict[str, str])
  • cleanMounts (bool)

๐Ÿ“ class WorkerThread(outer, mounts, numCores)

Bases: Appliance ๐ŸŒธ

This is a thread whose join() method re-raises exceptions that happened during run(). join() is idempotent, but the exception only gets raised during the first join() call that actually manages to join the thread. If join() times out, no exception gets re-raised, even if one might already have happened in run(). ๐Ÿ˜ญ

When you subclass this thread, override tryRun() instead of run(). ๐Ÿ’œ

>>> def f():
...     assert 0
>>> t = ExceptionalThread(target=f)
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

>>> class MyThread(ExceptionalThread):
...     def tryRun( self ):
...         assert 0
>>> t = MyThread()
>>> t.start()
>>> t.join()
Traceback (most recent call last):
...
AssertionError

Parameters ๐ŸŽ€

  • outer (ApplianceTestSupport)
  • mounts (dict[str, str])
  • numCores (int)

Attributes ๐Ÿงš

  • numCores

๐Ÿ’– toil.toilState

โœจ Attributes โœจ

  • logger ๐Ÿชต (the one attribute listed here)

๐ŸŽ€ Classes ๐ŸŽ€

  • ToilState โ€” holds the leader's scheduling information ๐Ÿ’…

๐Ÿฆ‹ Module Contents ๐Ÿฆ‹

toil.toilState.logger

class toil.toilState.ToilState(jobStore)

Okay so ToilState is the leader's scheduling brain ๐Ÿง , but it only keeps the stuff that does not need to be persisted back to the JobStore (like info on completed and outstanding predecessors) ๐Ÿซถ

It holds the true single copies of all the JobDescription objects that the Leader and ServiceManager use. The leader and service manager shouldn't do their own load() and update() calls on the JobStore. They go through this class, bestie ๐Ÿ’…

Everything in the leader references JobDescriptions by ID ๐Ÿ†”. It only holds JobDescription objects, not Job objects, and those JobDescription objects only exist in single copies โœจ

Parameters:

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)

Attributes:

  • bus โ€” listed with no type or description, so it's a total mystery ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • successor_to_predecessors โ€” dict[str, set[str]] ๐ŸŒธ
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#set
  • successorCounts โ€” dict[str, int] ๐Ÿ”ข
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/functions.html#int
  • service_to_client โ€” dict[str, str] ๐Ÿงš
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str
  • servicesIssued โ€” dict[str, set[str]] ๐ŸŽ€
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/stdtypes.html#set
  • jobs_issued โ€” set[str] ๐Ÿฆ‹
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#set, /usr/share/doc/python3/html/library/stdtypes.html#str
  • totalFailedJobs โ€” set[str] ๐Ÿ’€
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#set, /usr/share/doc/python3/html/library/stdtypes.html#str
  • hasFailedSuccessors โ€” set[str] ๐Ÿ™ˆ
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#set, /usr/share/doc/python3/html/library/stdtypes.html#str
  • failedSuccessors โ€” set[str] ๐Ÿ˜ญ
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#set, /usr/share/doc/python3/html/library/stdtypes.html#str
  • jobsToBeScheduledWithMultiplePredecessors โ€” set[str] ๐Ÿ”ฅ
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#set, /usr/share/doc/python3/html/library/stdtypes.html#str

Methods:

load_workflow(rootJob, jobCache=None)

load_workflow(rootJob, jobCache=None)

Loads the whole workflow rooted at the given job ๐ŸŒณ. If any jobs get loaded that have updated and need the leader to deal with them, JobUpdatedMessage messages get sent to the message bus ๐Ÿ“จ

The jobCache is a map from jobStoreID to JobDescription or None. It's used to speed up building the state when loading initially from the JobStore, and it is not preserved afterwards ๐Ÿƒโ€โ™€๏ธ

  • rootJob (toil.job.JobDescription) โ€” the description for the root job of the workflow being run
  • jobCache (Optional[dict[str, toil.job.JobDescription]]) โ€” a dict to cache downloaded job descriptions in, keyed by ID
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str

Return type: None

job_exists(job_id)

job_exists(job_id)

Checks if the given job exists right now ๐Ÿ‘€. It returns True if the job exists right now, and False if it hasn't been created or it has been deleted elsewhere.

Heads up: it doesn't guarantee the job will or won't be gettable, especially if you're racing another process or if it's still cached ๐Ÿ™ˆ
  • job_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type: bool

  • docs: /usr/share/doc/python3/html/library/functions.html#bool

get_job(job_id)

get_job(job_id)

Gets the one true copy of the JobDescription with the given ID ๐Ÿ‘‘

  • job_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type: toil.job.JobDescription

commit_job(job_id)

commit_job(job_id)

Saves back any modifications made to a JobDescription (one retrieved from get_job()) ๐Ÿ’พ

  • job_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type: None

delete_job(job_id)

delete_job(job_id)

Destroys a JobDescription ๐Ÿ’ฅ. This may raise an exception if the job could not be cleaned up (i.e. files belonging to it failed to delete).

  • job_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type: None

reset_job(job_id)

reset_job(job_id)

Discards any local modifications to a JobDescription ๐Ÿงน. This will make modifications from other hosts visible.

  • job_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type: None

reset_job_expecting_change(job_id, timeout)

reset_job_expecting_change(job_id, timeout)

Discards any local modifications to a JobDescription ๐Ÿงน, and makes modifications from other hosts visible. It will wait for up to timeout seconds for a modification (or deletion) from another host to actually become visible โณ

It always replaces the JobDescription with what is stored in the job store, even if no modification ends up being visible. It returns True if an update was detected in time, and False otherwise.

  • job_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str
  • timeout (float)
    • docs: /usr/share/doc/python3/html/library/functions.html#float

Return type: bool

  • docs: /usr/share/doc/python3/html/library/functions.html#bool

successors_pending(predecessor_id, count)

successors_pending(predecessor_id, count)

Remembers that the given job has the given number more pending successors ๐Ÿ“ˆ (ones that have not yet succeeded or failed).

  • predecessor_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str
  • count (int)
    • docs: /usr/share/doc/python3/html/library/functions.html#int

Return type: None

successor_returned(predecessor_id)

successor_returned(predecessor_id)

Remembers that the given job has one fewer pending successor ๐Ÿ“‰, because one has either succeeded or failed.

  • predecessor_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type: None

count_pending_successors(predecessor_id)

count_pending_successors(predecessor_id)

Counts the number of pending successors of the given job ๐Ÿ”ข. Pending successors are the ones that have not yet succeeded or failed.

  • predecessor_id (str)
    • docs: /usr/share/doc/python3/html/library/stdtypes.html#str

Return type: int

  • docs: /usr/share/doc/python3/html/library/functions.html#int

๐ŸŒธ toil.utils

๐Ÿงš Submodules ๐Ÿงš

๐ŸŒˆ toil.utils.toilClean

Delete a job store used by a previous Toil workflow invocation ๐Ÿงน

โœจ Attributes โœจ

  • logger ๐Ÿชต

๐ŸŽ€ Functions ๐ŸŽ€

  • main()

๐Ÿฆ‹ Module Contents ๐Ÿฆ‹

toil.utils.toilClean.logger

toil.utils.toilClean.main()

Return type: None


๐ŸŒˆ toil.utils.toilConfig

Create a config file with all default Toil options โš™๏ธ

โœจ Attributes โœจ

  • logger ๐Ÿชต

๐ŸŽ€ Functions ๐ŸŽ€

  • main()

๐Ÿฆ‹ Module Contents ๐Ÿฆ‹

toil.utils.toilConfig.logger

toil.utils.toilConfig.main()

Return type: None


๐ŸŒˆ toil.utils.toilDebugFile

Debug tool for copying files contained in a toil jobStore ๐Ÿ›๐Ÿซถ

โœจ Attributes โœจ

okay so the first thing on the list is the logger attribute ๐Ÿ’… that's the whole entry, no extra details, bestie ๐Ÿซถ

๐ŸŒธ Functions ๐ŸŒธ

  • fetchJobStoreFiles(jobStore, options) โ€” Takes a list of file names as glob patterns, searches for these within a
  • printContentsOfJobStore(job_store[, job_id]) โ€” Fetch a list of all files contained in the job store if nameOfJob is not
  • main() โ€” no description given ๐Ÿ™ˆ

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.utils.toilDebugFile.logger โœจ

๐Ÿฆ‹ toil.utils.toilDebugFile.fetchJobStoreFiles(jobStore, options)

Okay this one is giving file-hunter energy ๐Ÿ”ฅ It takes a list of file names written as glob patterns, searches for them within a given directory, and tries to grab every file it finds and copy it into options.localFilePath.

Parameters

  • jobStore (toil.jobStores.fileJobStore.FileJobStore, link target #toil.jobStores.fileJobStore.FileJobStore) โ€” a fileJobStore object ๐Ÿ’–
  • options.fetch โ€” the list of file glob patterns to look for in the jobStore and copy into options.localFilePath ๐Ÿงš
  • options.localFilePath โ€” the local directory you're copying files into ๐Ÿ“
  • options.jobStore โ€” the path to the jobStore directory ๐Ÿ—‚๏ธ
  • options (argparse.Namespace, docs: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type

None ๐Ÿค

๐Ÿฆ‹ toil.utils.toilDebugFile.printContentsOfJobStore(job_store, job_id=None)

Okay so this one has two modes, and it's lowkey iconic. If nameOfJob isn't declared, it fetches a list of all files in the job store. If it is declared, it only prints out the names of files for that specific job that it can find a match for. It also creates a log file of these file names in the current directory ๐Ÿ“

Parameters

  • job_store (toil.jobStores.fileJobStore.FileJobStore, link target #toil.jobStores.fileJobStore.FileJobStore) โ€” the job store you're asking for files from ๐ŸŒˆ
  • job_id (Optional[str], docs: /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” defaults to None, which prints out all files in the jobStore. If you specify one, it prints every jobStore file that job has written to the jobStore ๐Ÿซถ

Return type

None ๐Ÿค

๐Ÿฆ‹ toil.utils.toilDebugFile.main()

Return type

None ๐Ÿค


๐Ÿงš toil.utils.toilDebugJob ๐Ÿงš

Debug tool for running a toil job locally. Super helpful when you need to see what's happening without the whole cluster drama ๐Ÿซ 

โœจ Attributes โœจ

  • logger โœจ

๐Ÿ’… Functions ๐Ÿ’…

  • main() โ€” no description given

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.utils.toilDebugJob.logger โœจ

๐Ÿฆ‹ toil.utils.toilDebugJob.main()

Return type

None ๐Ÿค


๐Ÿ’€ toil.utils.toilDestroyCluster ๐Ÿ’€

Okay this one is literally the cleanup crew ๐Ÿงน It terminates the specified cluster and its associated resources. Bye bye, cluster ๐Ÿ‘‹

โœจ Attributes โœจ

  • logger โœจ

๐Ÿ’… Functions ๐Ÿ’…

  • main() โ€” no description given

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.utils.toilDestroyCluster.logger โœจ

๐Ÿฆ‹ toil.utils.toilDestroyCluster.main()

Return type

None ๐Ÿค


๐Ÿ”ฅ toil.utils.toilKill ๐Ÿ”ฅ

Kills rogue toil processes. Main character energy for villain-arc processes ๐Ÿ’€

โœจ Attributes โœจ

  • logger โœจ

๐Ÿ’… Functions ๐Ÿ’…

  • main() โ€” no description given

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.utils.toilKill.logger โœจ

๐Ÿฆ‹ toil.utils.toilKill.main()

Return type

None ๐Ÿค


๐Ÿš€ toil.utils.toilLaunchCluster ๐Ÿš€

Launches a toil leader instance with the specified provisioner. It's giving "let's get this party started" ๐ŸŽ‰

โœจ Attributes โœจ

  • build_tag_dict_from_env ๐Ÿท๏ธ
  • logger โœจ

๐Ÿ’… Functions ๐Ÿ’…

  • create_tags_dict(tags) โ€” no description given
  • main() โ€” no description given

๐ŸŽ€ Module Contents ๐ŸŽ€

๐ŸŒˆ toil.utils.toilLaunchCluster.build_tag_dict_from_env

Type: dict[str, str] (docs for dict: /usr/share/doc/python3/html/library/stdtypes.html#dict; docs for str: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’œ

  • toil.utils.toilLaunchCluster.logger โœจ

๐Ÿฆ‹ toil.utils.toilLaunchCluster.create_tags_dict(tags)

Parameters

  • tags (list[str], docs for list: /usr/share/doc/python3/html/library/stdtypes.html#list; docs for str: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

dict[str, str] (docs for dict: /usr/share/doc/python3/html/library/stdtypes.html#dict; docs for str: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿค

๐Ÿฆ‹ toil.utils.toilLaunchCluster.main()

Return type

None ๐Ÿค


๐Ÿ› ๏ธ toil.utils.toilMain ๐Ÿ› ๏ธ

๐Ÿ’… Functions ๐Ÿ’…

  • main() โ€” no description given
  • get_or_die(module, name) โ€” Get an object from a module or complain that it is missing. ๐Ÿ™…โ€โ™€๏ธ
  • loadModules() โ€” no description given
  • printHelp(modules) โ€” no description given
  • printVersion() โ€” no description given

๐ŸŽ€ Module Contents ๐ŸŽ€

๐Ÿฆ‹ toil.utils.toilMain.main()

Return type

None ๐Ÿค

๐Ÿฆ‹ toil.utils.toilMain.get_or_die(module, name)

Get an object from a module or complain that it is missing. Literally the bouncer of imports ๐Ÿง

Parameters

  • module (types.ModuleType, docs: /usr/share/doc/python3/html/library/types.html#types.ModuleType)
  • name (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type

Any ๐Ÿค

๐Ÿฆ‹ toil.utils.toilMain.loadModules()

Return type

dict[str, types.ModuleType] (docs for dict: /usr/share/doc/python3/html/library/stdtypes.html#dict; docs for str: /usr/share/doc/python3/html/library/stdtypes.html#str; docs for types.ModuleType: /usr/share/doc/python3/html/library/types.html#types.ModuleType) ๐Ÿค

๐Ÿฆ‹ toil.utils.toilMain.printHelp(modules)

Parameters

  • modules (dict[str, types.ModuleType], docs for dict: /usr/share/doc/python3/html/library/stdtypes.html#dict; docs for str: /usr/share/doc/python3/html/library/stdtypes.html#str; docs for types.ModuleType: /usr/share/doc/python3/html/library/types.html#types.ModuleType)

Return type

None ๐Ÿค

๐Ÿฆ‹ toil.utils.toilMain.printVersion()

Return type

None ๐Ÿค


๐Ÿ’– toil.utils.toilRsyncCluster ๐Ÿ’–

Rsyncs into the toil appliance container running on the leader of the cluster. It's basically sliding into the leader's DMs ๐Ÿ“ฌ

โœจ Attributes โœจ

  • logger โœจ

๐Ÿ’… Functions ๐Ÿ’…

  • main() โ€” no description given

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.utils.toilRsyncCluster.logger โœจ

๐Ÿฆ‹ toil.utils.toilRsyncCluster.main()

Return type

None ๐Ÿค

โœจ toil.utils.toilServer โœจ

okay so this is the CLI entry point for the Toil servers ๐Ÿ’– it's giving main character energy in the utils folder ๐Ÿ‘‘

โœจ Attributes โœจ

  • logger โ€” the page leaves the description blank ๐Ÿ™ˆ

๐Ÿงš Functions ๐Ÿงš

  • main() โ€” no description given ๐Ÿ™ˆ

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.utils.toilServer.logger
  • toil.utils.toilServer.main()
    • Return type None

โœจ toil.utils.toilSshCluster โœจ

this one lets you SSH into the toil appliance container running on the leader of your cluster ๐Ÿฆ‹ bestie this is so useful ngl ๐Ÿซถ

โœจ Attributes โœจ

  • logger โ€” no description given ๐Ÿ™ˆ

๐Ÿงš Functions ๐Ÿงš

  • have_ipv6() โ€” gives back True if the IPv6 loopback interface is useable ๐ŸŒˆ
  • main() โ€” no description given ๐Ÿ™ˆ

๐ŸŽ€ Module Contents ๐ŸŽ€

  • toil.utils.toilSshCluster.logger
  • toil.utils.toilSshCluster.have_ipv6()
    • gives back True if the IPv6 loopback interface is useable ๐ŸŒˆ
    • Return type bool </usr/share/doc/python3/html/library/functions.html# bool>
  • toil.utils.toilSshCluster.main()
    • Return type None

โœจ toil.utils.toilStats โœจ

this one crunches the stats for a given Toil workflow and reports them back ๐Ÿ“Š the numbers are literally everything ๐Ÿ’…

โœจ Attributes โœจ

  • logger โ€” no description given ๐Ÿ™ˆ
  • CATEGORIES โ€” no description given ๐Ÿ™ˆ
  • CATEGORY_UNITS โ€” no description given ๐Ÿ™ˆ
  • TITLES โ€” no description given ๐Ÿ™ˆ
  • TIME_CATEGORIES โ€” no description given ๐Ÿ™ˆ
  • SPACE_CATEGORIES โ€” no description given ๐Ÿ™ˆ
  • COMPUTED_CATEGORIES โ€” no description given ๐Ÿ™ˆ
  • LONG_FORMS โ€” no description given ๐Ÿ™ˆ
  • sort_category_choices โ€” no description given ๐Ÿ™ˆ
  • sort_field_choices โ€” no description given ๐Ÿ™ˆ

๐ŸŒธ Classes ๐ŸŒธ

  • ColumnWidths โ€” a convenience object that stores the width of columns for printing ๐ŸŽ€ it helps make things pretty โœจ

โœจ Functions โœจ

okay bestie, this is the big table of helper functions ๐ŸŽ€ they all exist to make the stats printout look gorgeous, and ngl that's a whole vibe ๐Ÿ’…

  • pad_str(s[, field]) โ€” pads the start of a string with spaces, but only if it actually needs it ๐ŸŒธ
  • pretty_space(k[, field, alone]) โ€” takes k as kibibytes and hands back a nicely formatted string โœจ
  • pretty_time(t[, field, unit, alone]) โ€” takes t as seconds and gives you a cute formatted string back ๐Ÿฆ‹
  • report_unit(unit) โ€” formats a unit name so it's display-ready ๐Ÿ’–
  • report_time(t, options[, field, unit, alone]) โ€” given t seconds, reports back the correct format as a string โฑ๏ธ
  • report_space(k, options[, field, unit, alone]) โ€” given k kibibytes, reports back the correct format as a string ๐Ÿ’พ
  • report_number(n[, field, nan_value]) โ€” given a number, reports back the correct format as a string ๐Ÿ”ข
  • report(v, category, options[, field, alone]) โ€” reports a value of the given category, formatted as a string ๐ŸŽ€
  • sprint_tag(key, tag, options[, columnWidths]) โ€” generates a pretty-print-ready string from a JTTag() ๐Ÿงš
  • decorate_title(category, title, options) โ€” adds extra bits to the category titles ๐Ÿ‘‘
  • decorate_subheader(category, columnWidths, options) โ€” slaps a marker on the correct field if the TITLE is the one being sorted on ๐Ÿ”ฅ
  • get(tree, name) โ€” returns a float value attribute NAME from TREE ๐ŸŒˆ
  • sort_jobs(jobTypes, options) โ€” returns jobTypes, all sorted and ready to go โญ
  • report_pretty_data(root, worker, job, job_types, options) โ€” prints out the important bits ๐Ÿซถ
  • compute_column_widths(job_types, worker, job, options) โ€” returns a ColumnWidths() object with the correct max widths ๐Ÿ“
  • update_column_widths(tag, cw, options) โ€” updates the column width attributes for this tag's fields ๐Ÿ’…
  • build_element(element, items, item_name, defaults) โ€” creates an element for output ๐Ÿ“
  • create_summary(element, containingItems, ...) โ€” figures out how many jobs (or contained items) ran on each worker (or containing item) ๐Ÿงฎ
  • get_stats(jobStore) โ€” sums together all the stats information in the job store ๐Ÿ’œ
  • process_data(config, stats) โ€” collates the stats and reports them ๐Ÿ“Š
  • report_data(tree, options) โ€” no description given here, so I'm not guessing ๐Ÿ™ˆ
  • add_stats_options(parser) โ€” also no description given, mystery energy ๐Ÿ™ˆ
  • main() โ€” reports stats on the workflow, use it with the --stats option to toil ๐Ÿ‘‘

โœจ Module Contents โœจ

okay, the module contents are giving organised chaos ๐Ÿ’œ

  • toil.utils.toilStats.logger
  • toil.utils.toilStats.CATEGORIES = ['time', 'clock', 'wait', 'memory', 'disk']
  • toil.utils.toilStats.CATEGORY_UNITS
  • toil.utils.toilStats.TITLES
  • toil.utils.toilStats.TIME_CATEGORIES
  • toil.utils.toilStats.SPACE_CATEGORIES
  • toil.utils.toilStats.COMPUTED_CATEGORIES
  • toil.utils.toilStats.LONG_FORMS

๐ŸŽ€ class toil.utils.toilStats.ColumnWidths

this is the convenience object that stores the width of columns for printing, so everything looks pretty ๐ŸŒธ

  • categories = ['time', 'clock', 'wait', 'memory', 'disk']
  • fields_count = ['count', 'min', 'med', 'ave', 'max', 'total']
  • fields = ['min', 'med', 'ave', 'max', 'total']
  • data: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, int </usr/share/doc/python3/html/library/functions.html#int>]
  • title(category) โ€” returns the total printed length of this category item โœจ
    • Parameters
      • category (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • Return type
      • int </usr/share/doc/python3/html/library/functions.html#int>
  • get_width(category, field) ๐Ÿฆ‹
    • Parameters
      • category (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
      • field (str </usr/share/doc/python3/html/library/stdtypes.html#str>)
    • Return type
      • int </usr/share/doc/python3/html/library/functions.html#int>
  • set_width(category, field, width) ๐Ÿ’–
    • Parameters

Parameters

  • category (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • field (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • width (int: /usr/share/doc/python3/html/library/functions.html#int)

Return type: None

report()

Return type: None


๐ŸŒธ toil.utils.toilStats.pad_str(s, field=None)

okay so this one just pads the front of a string with spaces, but only if it actually needs them ๐Ÿ’…

Parameters

  • s (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • field (Optional[int]: /usr/share/doc/python3/html/library/functions.html#int)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿฆ‹ toil.utils.toilStats.pretty_space(k, field=None, alone=False)

Given k as kibibytes, this gives you back a nicely formatted string. the vibe is immaculate โœจ

Parameters

  • k (float: /usr/share/doc/python3/html/library/functions.html#float)
  • field (Optional[int]: /usr/share/doc/python3/html/library/functions.html#int)
  • alone (bool: /usr/share/doc/python3/html/library/functions.html#bool)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿงš toil.utils.toilStats.pretty_time(t, field=None, unit='s', alone=False)

this one takes t in seconds and serves it back looking gorgeous ๐Ÿ’– the unit defaults to 's' so you're set unless you say otherwise

Parameters

  • t (float: /usr/share/doc/python3/html/library/functions.html#float)
  • field (Optional[int]: /usr/share/doc/python3/html/library/functions.html#int)
  • unit (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • alone (bool: /usr/share/doc/python3/html/library/functions.html#bool)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐ŸŽ€ toil.utils.toilStats.report_unit(unit)

formats a unit name so it looks presentable on screen ๐Ÿซถ

Parameters

  • unit (str: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


โญ toil.utils.toilStats.report_time(t, options, field=None, unit='s', alone=False)

Given t seconds, this reports back the correct formatted string. it's the main character of time formatting, no cap ๐Ÿ‘‘

Parameters

  • t (float: /usr/share/doc/python3/html/library/functions.html#float)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)
  • field (Optional[int]: /usr/share/doc/python3/html/library/functions.html#int)
  • unit (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • alone (bool: /usr/share/doc/python3/html/library/functions.html#bool)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ’œ toil.utils.toilStats.report_space(k, options, field=None, unit='KiB', alone=False)

Given k kibibytes, this reports back the correct formatted string. the unit defaults to 'KiB' ๐Ÿ“

If unit is set to B, it converts to KiB first. so that's one extra step it takes for you, bestie ๐Ÿ™ˆ

Parameters

  • k (float: /usr/share/doc/python3/html/library/functions.html#float)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)
  • field (Optional[int]: /usr/share/doc/python3/html/library/functions.html#int)
  • unit (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • alone (bool: /usr/share/doc/python3/html/library/functions.html#bool)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐ŸŒˆ toil.utils.toilStats.report_number(n, field=None, nan_value='NaN')

given a number, this hands back a nicely formatted string ๐Ÿ”ฅ

if n is a NaN or None, it uses nan_value to represent it instead. the default is 'NaN', so no drama ๐Ÿ’€

Parameters

  • n (Union[int, float, None]: /usr/share/doc/python3/html/library/functions.html#int, /usr/share/doc/python3/html/library/functions.html#float)
  • field (Optional[int]: /usr/share/doc/python3/html/library/functions.html#int)
  • nan_value (str: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ’… toil.utils.toilStats.report(v, category, options, field=None, alone=False)

Reports a value of the given category, formatted as a string. it's giving organized ๐ŸŽ€

it uses the given field width if one is set. if alone is set, the field is being formatted outside a table and might need a unit ๐Ÿฆ‹

Parameters

  • v (float: /usr/share/doc/python3/html/library/functions.html#float)
  • category (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)
  • field (Optional[int]: /usr/share/doc/python3/html/library/functions.html#int)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐ŸŒธ toil.utils.toilStats.sprint_tag(key, tag, options, columnWidths=None)

this one generates a pretty-print ready string from a JTTag() โœจ

Parameters

  • key (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • tag (toil.lib.expando.Expando: #toil.lib.expando.Expando)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)
  • columnWidths (Optional[ColumnWidths]: #toil.utils.toilStats.ColumnWidths)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿงš toil.utils.toilStats.decorate_title(category, title, options)

this adds extra bits to the category titles so everything reads cleanly ๐Ÿซถ

units get added to the title if they won't show up in the formatted values. and if the title is the one being sorted on, it gets a marker so you can spot it instantly ๐Ÿ‘‘

Parameters

  • category (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • title (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿฆ‹ toil.utils.toilStats.decorate_subheader(category, columnWidths, options)

Adds a marker to the correct field if the title is sorted on. it's all about being precise bestie ๐Ÿ’–

Parameters

  • category (str: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • columnWidths (ColumnWidths: #toil.utils.toilStats.ColumnWidths)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ“ toil.utils.toilStats.get(tree, name)

returns a float value for the attribute name from tree ๐Ÿ’…

Parameters

  • tree (toil.lib.expando.Expando: #toil.lib.expando.Expando)
  • name (str: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: float (/usr/share/doc/python3/html/library/functions.html#float)


๐Ÿ‘‘ toil.utils.toilStats.sort_jobs(jobTypes, options)

returns jobTypes all sorted, iconic behaviour ๐Ÿ”ฅ

Parameters

  • jobTypes (list[Any]: /usr/share/doc/python3/html/library/stdtypes.html#list)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type: list[Any] (/usr/share/doc/python3/html/library/stdtypes.html#list)


๐Ÿ’– toil.utils.toilStats.report_pretty_data(root, worker, job, job_types, options)

this one prints out the important bits ๐ŸŒˆ it's the whole highlight reel

Parameters

  • root (toil.lib.expando.Expando: #toil.lib.expando.Expando)
  • worker (toil.lib.expando.Expando: #toil.lib.expando.Expando)
  • job (toil.lib.expando.Expando: #toil.lib.expando.Expando)
  • job_types (list[Any]: /usr/share/doc/python3/html/library/stdtypes.html#list)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type: str (/usr/share/doc/python3/html/library/stdtypes.html#str)


โœจ toil.utils.toilStats.compute_column_widths(job_types, worker, job, options)

Returns a ColumnWidths() object with the correct max widths. the widths are locked in and ready to slay ๐Ÿ’…

Parameters

  • job_types (list[Any]: /usr/share/doc/python3/html/library/stdtypes.html#list)
  • worker (toil.lib.expando.Expando: #toil.lib.expando.Expando)
  • job (toil.lib.expando.Expando: #toil.lib.expando.Expando)
  • options (argparse.Namespace: /usr/share/doc/python3/html/library/argparse.html#argparse.Namespace)

Return type: ColumnWidths (#toil.utils.toilStats.ColumnWidths)


๐Ÿซถ toil.utils.toilStats.update_column_widths(tag, cw, options)

updates the column width attributes for this tag's fields, so every column stays in its lane ๐ŸŽ€

Parameters

  • tag (toil.lib.expando.Expando) ๐Ÿ’–
  • cw (ColumnWidths) โœจ
  • options (argparse.Namespace) ๐ŸŒธ

Return type: None ๐ŸŽ€

toil.utils.toilStats.build_element(element, items, item_name, defaults)

Okay so this one makes a brand new element for the output. It's literally the blank canvas for your stats ๐ŸŽจ๐Ÿ’…

Parameters

  • element (toil.lib.expando.Expando)
  • items (list[toil.job.Job])
  • item_name (str)
  • defaults (dict[str, float])

Return type: toil.lib.expando.Expando ๐Ÿ‘‘

toil.utils.toilStats.create_summary(element, containingItems, containingItemName, count_contained)

This is the one that figures out how many jobs (or contained items) ran on each worker (or containing item). It's giving math-brain energy ๐Ÿง ๐Ÿฆ‹

It also sticks a bunch of xxx_number_per_xxx stats into element to describe all of that. Iconic โœจ

Parameters

  • count_contained (Callable[[toil.lib.expando.Expando], int]) โ€” the function that maps from a containing item to the number of contained items ๐Ÿ”ข
  • element (toil.lib.expando.Expando)
  • containingItems (list[toil.lib.expando.Expando])
  • containingItemName (str)

Return type: None ๐Ÿ’–

toil.utils.toilStats.get_stats(jobStore)

Bestie, this one adds together all the stats info sitting in the job store. ๐Ÿ“Š

What you get back is one single object holding lists of the values from every summed object. Main character energy ๐Ÿ‘‘

Parameters

  • jobStore (toil.jobStores.abstractJobStore.AbstractJobStore)

Return type: toil.lib.expando.Expando ๐ŸŒธ

toil.utils.toilStats.process_data(config, stats)

This one collates the stats and reports them. Literally the glow-up moment ๐Ÿ’ซ

Parameters

  • config (toil.common.Config)
  • stats (toil.lib.expando.Expando)

Return type: toil.lib.expando.Expando ๐Ÿฆ‹

toil.utils.toilStats.report_data(tree, options)

Okay this one takes your tree and your options and reports on them. Quick and clean ๐Ÿงš

Parameters

  • tree (toil.lib.expando.Expando)
  • options (argparse.Namespace)

Return type: None ๐Ÿซถ

toil.utils.toilStats.sort_category_choices

The valid sort categories are ['time', 'clock', 'wait', 'memory', 'disk', 'alpha', 'count']. Choose wisely, babe ๐Ÿ’…

toil.utils.toilStats.sort_field_choices

The valid sort fields are ['min', 'med', 'ave', 'max', 'total']. Pick your fave ๐Ÿ“

toil.utils.toilStats.add_stats_options(parser)

This one adds the stats options onto your parser. Super simple, no notes ๐ŸŽ€

Parameters

  • parser (argparse.ArgumentParser)

Return type: None โœจ

toil.utils.toilStats.main()

Reports stats on the workflow. Use it with the --stats option to toil, and you're set ๐Ÿ“ˆ๐Ÿ”ฅ

Return type: None ๐Ÿ’œ


๐Ÿฆ‹ toil.utils.toilStatus

Tool for reporting on job status. It's the one who keeps you in the loop ๐Ÿ‘€

Attributes

  • logger

Classes

  • ToilStatus โ€” Tool for reporting on job status. ๐Ÿงš

Functions

  • main() โ€” Reports the state of a Toil workflow. ๐ŸŒˆ

Module Contents

toil.utils.toilStatus.logger ๐ŸŒธ

class toil.utils.toilStatus.ToilStatus(jobStoreName, specifiedJobs=None)

Tool for reporting on job status. This is literally the whole reason we're here ๐Ÿ’–

Parameters

  • jobStoreName (str)
  • specifiedJobs (Optional[list[str]])

Attributes

  • jobStoreName
  • jobStore
  • message_bus_path

Prints a dot output graph representing the workflow. Very visual, very aesthetic ๐ŸŽจ

Return type: None

printJobLog()

Takes a list of jobs, finds their log files, and prints them to the terminal. Log dive ๐Ÿ•ต๏ธโ€โ™€๏ธ

Return type: None

printJobChildren()

Takes a list of jobs and prints their successors. Family tree vibes ๐ŸŒณ

Return type: None

printAggregateJobStats(properties, childNumber)

Prints each job's ID, log file, remaining tries, and other properties. It's a whole vibe check ๐Ÿ”

Parameters

  • properties (list[set[str]]) โ€” a set of string flag names for each job in self.jobsToReport ๐Ÿท๏ธ
  • childNumber (list[int]) โ€” a list of child counts for each job in self.jobsToReport ๐Ÿ”ข

Return type: None

report_on_jobs()

Gathers information about jobs, like their child jobs and status. Lowkey the most useful one ๐Ÿ“‹

Returns jobStats: a dict containing some lists of jobs by category, plus some lists of job properties for each job in self.jobsToReport ๐Ÿ’œ

Return type: dict[str, Any]

static getPIDStatus(jobStoreName)

Determines the status of a process with a particular local pid. It checks to see if a process exists or not. Simple and iconic ๐Ÿง 

Returns a string indicating the status of the PID of the workflow as stored in the jobstore ๐ŸŒŸ

Return type: str

Parameters

  • jobStoreName (str)

static getStatus(jobStoreName)

Determines the status of a workflow. If the jobstore doesn't exist yet, this returns 'QUEUED', assuming it hasn't been created yet. โณ

It checks for the existence of files created in toil.Leader.run(). In toil.Leader.run(), if a workflow completes with failed jobs, 'failed.log' is created. Otherwise, 'succeeded.log' is written. If neither of these exist, the leader is still running jobs ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

Heads up: the status comes back as one of ['COMPLETED', 'RUNNING', 'ERROR', 'QUEUED']. That's the whole list, no extras ๐Ÿ’€

Returns a string indicating the status of the workflow.

Return type: str

Parameters

  • jobStoreName (str)

Prints a list of the currently running jobs. Who's up? ๐Ÿƒโ€โ™€๏ธ

Return type: None

fetchRootJob()

Fetches the root job from the jobStore, the one that gives context for all the other jobs ๐Ÿ‘‘

It's exactly the same as the jobStore.loadRootJob() function. The only difference is the exit message if the root job isn't found. That message means the workflow finished successfully, so some stats can't really be gathered from it, like which jobs are left to run ๐ŸŽ‰

Raises JobException โ€” if the root job doesn't exist โŒ

Return type: toil.job.JobDescription

fetchUserJobs(jobs)

Takes a user-input array of jobs, verifies that they're in the jobStore, and returns the array of jobsToReport. ๐Ÿซถ

Parameters

  • jobs (list) โ€” a list of jobs to be verified โœ…

Returns jobsToReport: a list of jobs that are verified to be in the jobStore ๐Ÿ’–

Return type: list[toil.job.JobDescription] ๐ŸŽ€ that's the one from before, bestie ๐Ÿ’–

โœจ traverseJobGraph(rootJob, jobsToReport=None, foundJobStoreIDs=None) โœจ

Okay so this one goes hunting through the jobStore for every current job and hands them all back as an Array ๐Ÿ”๐Ÿ’…

Parameters

  • rootJob (toil.job.JobDescription) โ€” the root job of the workflow, aka where the whole story starts ๐ŸŒฑ
  • jobsToReport (list) โ€” a list of jobNodes that gets added to and then returned ๐Ÿงพ
  • foundJobStoreIDs (set) โ€” a set of jobStoreIDs that keeps track of every jobStoreID it's already spotted during the traversal ๐Ÿ‘€

Returns โ€” jobsToReport: the list of jobs currently in the job graph โœจ

Return type โ€” list[toil.job.JobDescription] ๐ŸŽ€

โœจ toil.utils.toilStatus.main() โœจ

Reports the state of a Toil workflow ๐Ÿ“Š basically the vibe check for your run ๐Ÿซถ

Return type โ€” None ๐Ÿ’€

โœจ toil.utils.toilUpdateEC2Instances โœจ

Updates Toil's internal list of EC2 instance types ๐Ÿฆ‹ so it stays up to date with the newest drops ๐Ÿ’œ

๐ŸŽ€ Attributes

  • logger

๐ŸŽ€ Functions

  • internet_connection() โ€” Returns True if there is an internet connection present, and False otherwise ๐ŸŒ
  • main()

๐ŸŽ€ Module Contents

toil.utils.toilUpdateEC2Instances.logger

toil.utils.toilUpdateEC2Instances.internet_connection() โ€” Returns True if there is an internet connection present, and False otherwise ๐ŸŒ

Return type โ€” bool ๐Ÿซถ

toil.utils.toilUpdateEC2Instances.main()

Return type โ€” None ๐Ÿ’€

โœจ toil.version โœจ

๐ŸŽ€ Attributes

  • baseVersion
  • cgcloudVersion
  • version
  • cacheTag
  • mainCacheTag
  • distVersion
  • exactPython
  • python
  • dockerTag
  • currentCommit
  • dockerRegistry
  • dockerName
  • dirty
  • cwltool_version

๐ŸŽ€ Module Contents

These are all the version details, bestie, so you can see exactly what build you're running ๐Ÿงš๐Ÿ’œ

toil.version.baseVersion = '9.1.2'

toil.version.cgcloudVersion = '1.6.0a1.dev393'

toil.version.version = '9.1.2-355b72ba0e425619c0367562caf2a337078dba65'

toil.version.cacheTag = 'cache-local-py3.13'

toil.version.mainCacheTag = 'cache-master-py3.13'

toil.version.distVersion = '9.1.2'

toil.version.exactPython = 'python3.13'

toil.version.python = 'python3.13'

toil.version.dockerTag = '9.1.2-355b72ba0e425619c0367562caf2a337078dba65-py3.13'

toil.version.currentCommit = '355b72ba0e425619c0367562caf2a337078dba65'

toil.version.dockerRegistry = 'quay.io/ucsc_cgl'

toil.version.dockerName = 'toil'

toil.version.dirty = False

toil.version.cwltool_version = '3.1.20250715140722'

โœจ toil.wdl โœจ

๐ŸŽ€ Submodules

  • toil.wdl.utils

๐ŸŽ€ Functions

  • get_version(iterable) โ€” Get the version of the WDL document ๐Ÿ“œ

๐ŸŽ€ Module Contents

toil.wdl.utils.get_version(iterable) โ€” Get the version of the WDL document ๐Ÿ“œ

Parameters

  • iterable (collections.abc.Iterable[str]) โ€” an iterable that contains the lines of a WDL document ๐Ÿงพ

Returns โ€” The WDL version used in the workflow ๐ŸŒธ

Return type โ€” str ๐ŸŽ€

โœจ toil.wdl.wdltoil โœจ

๐ŸŽ€ Attributes

  • logger
  • WDLINode
  • AnyINode
  • file_digest
  • WDLContext
  • F
  • WDLBindings
  • SHARED_PATH_ATTR

๐ŸŽ€ Exceptions

  • InsufficientMountDiskSpace โ€” Common base class for all non-exit exceptions ๐Ÿšจ

โœจ Classes โœจ

okay bestie, here's the whole WDL class lineup ๐Ÿ’…๐ŸŽ€ every one of these has its own vibe, so let's go:

  • INodeTransform โ€” a type for a function that takes a File or Directory and hands back a modified copy, or None ๐Ÿฆ‹
  • ReadableFileObj โ€” a protocol that's more specific than what file_digest takes as an argument ๐ŸŒธ
  • FileDigester โ€” a protocol for the features we need from hashlib.file_digest ๐Ÿ”ฅ
  • NonDownloadingSize โ€” a WDL size() implementation that avoids downloading files at all ๐Ÿงš
  • ToilWDLStdLibBase โ€” the standard library for WDL as run on Toil ๐Ÿ’–
  • ToilWDLStdLibWorkflow โ€” the standard library for workflow scope โœจ
  • ToilWDLStdLibTaskCommand โ€” the standard library to use inside a WDL task command evaluation ๐Ÿซถ
  • ToilWDLStdLibTaskOutputs โ€” the standard library for WDL as run on Toil, with additional ๐Ÿ“
  • WDLBaseJob โ€” the base job class for all WDL-related jobs, the OG of the group ๐Ÿ‘‘
  • WDLTaskWrapperJob โ€” a job that figures out the resources needed to run a WDL job ๐Ÿ’œ
  • WDLTaskJob โ€” a job that runs a WDL task ๐ŸŒˆ
  • WDLWorkflowNodeJob โ€” a job that evaluates a WDL workflow node ๐ŸŽ€
  • WDLWorkflowNodeListJob โ€” a job that evaluates a list of WDL workflow nodes, which are in the same ๐Ÿฆ‹
  • WDLCombineBindingsJob โ€” a job that collects the results from WDL workflow nodes and combines their ๐Ÿ’…
  • WDLWorkflowGraph โ€” represents a graph of WDL WorkflowNodes ๐ŸŒธ
  • WDLSectionJob โ€” a job that can create more graph for a section of the workflow ๐Ÿงš
  • WDLScatterJob โ€” a job that evaluates a scatter in a WDL workflow. Runs the body for each ๐Ÿ”ฅ
  • WDLArrayBindingsJob โ€” a job that takes all new bindings created in an array of input environments, ๐Ÿ’–
  • WDLConditionalJob โ€” a job that evaluates a conditional in a WDL workflow โœจ
  • WDLWorkflowJob โ€” a job that evaluates an entire WDL workflow ๐Ÿซถ
  • WDLOutputsJob โ€” a job which evaluates an outputs section for a workflow ๐Ÿ“
  • WDLStartJob โ€” a job that evaluates an entire WDL workflow, and returns the workflow outputs ๐Ÿ‘‘
  • WDLInstallImportsJob โ€” a class that represents a unit of work in toil ๐Ÿ’œ
  • WDLImportWrapper โ€” a job that organizes importing files on workers instead of the leader. Responsible for extracting filenames and metadata, ๐ŸŒˆ

โœจ Functions โœจ

the helper functions are small but mighty ๐Ÿฅน๐Ÿ’…

  • is_inode(value) โ€” determines if a WDL value is either a File or Directory ๐ŸŽ€
  • wdl_error_reporter(task[, exit, log]) โ€” runs code in a context where WDL errors get reported with pretty formatting ๐Ÿฆ‹
  • report_wdl_errors(task[, exit, log]): okay so this one is a decorator that slaps the given task message onto any WDL errors, periodt ๐ŸŽ€
  • toil_read_source(uri, path, importer): a MiniWDL read_source implementation that can use any ๐Ÿงš (the description literally cuts off right there, bestie ๐Ÿ’€)
  • virtualized_equal(value1, value2): checks whether two WDL values are equal once file virtualization is taken into account ๐Ÿฆ‹
  • combine_bindings(all_bindings): merges variable bindings from multiple predecessor tasks into one set for ๐ŸŒธ (this one also trails off, no cap)
  • log_bindings(log_function, message, all_bindings): logs bindings to the console, even if some of them are still promises ๐Ÿ“
  • get_supertype(types): finds the supertype that can hold values of all the given types ๐Ÿ‘‘
  • for_each_node(root): iterates over every WDL workflow node inside the given node, including inputs, ๐Ÿซถ (cut off again, we get it ๐Ÿ˜ญ)
  • recursive_dependencies(root): gets the combined workflow_node_dependencies of root and everything under ๐Ÿ’œ (you can feel the sentence getting away from it)
  • parse_disks(spec, disks_spec): parses a WDL disk spec into a disk mount specification ๐Ÿ’พ
  • pack_toil_uri(file_id, task_path, parent, file_basename): encodes a Toil file ID plus metadata about who wrote it as a URI ๐Ÿ”ฅ
  • unpack_toil_uri(toil_uri): unpacks a URI made by make_toil_uri ๐Ÿ“
  • clone_metadata(old_inode, new_inode): copies all Toil metadata from one WDL File/Directory to another โœจ
  • make_inode(example_inode, value, expr): makes a new File or Directory of the same type as the example, using the given arguments ๐ŸŒˆ
  • set_inode_value(inode, new_value): returns a copy of a WDL File/Directory with the value changed ๐Ÿ’…
  • set_inode_nonexistent(inode, nonexistent): returns a copy of a WDL File/Directory with the nonexistent flag changed ๐Ÿ™ˆ
  • get_inode_nonexistent(inode): returns the nonexistent flag for a File/Directory ๐Ÿ’–
  • set_inode_virtualized_value(inode, virtualized_value): returns a copy of a WDL File/Directory with the virtualized_value attribute set ๐Ÿฆ‹
  • get_inode_virtualized_value(inode): gets the virtualized storage location for a File/Directory ๐ŸŒธ
  • get_shared_fs_path(inode): if a File/Directory has a shared filesystem path, this grabs that path โญ
  • set_shared_fs_path(inode, path): returns a copy of the given File/Directory with a shared filesystem path attached ๐Ÿซถ
  • view_shared_fs_paths(bindings) โ€” ๐Ÿ—‚๏ธ Takes your WDL bindings and gives you back a copy where every file has its shared filesystem path as its value ๐Ÿ’–
  • poll_execution_cache(node, bindings) โ€” ๐Ÿ” Checks the cache and returns the cached result of calling this workflow or task, plus its key ๐Ÿ”‘
  • fill_execution_cache(cache_key, output_bindings, ...) โ€” ๐Ÿ’พ Stores the result of calling a workflow or task in the cache so it can be reused later โœจ
  • choose_human_readable_directory(root_dir, ...) โ€” ๐Ÿ“ Picks a nice, readable directory to save files from a task and source directory in ๐ŸŒธ
  • evaluate_decls_to_bindings(decls, all_bindings, ...[, ...]) โ€” ๐Ÿงฎ Evaluates decls using a given bindings environment and standard library. Main character energy ๐Ÿ‘‘
  • extract_inode_values(environment) โ€” ๐Ÿ“ฆ Grabs a list of every File or Directory object value in the given bindings ๐Ÿฆ‹
  • extract_inode_virtualized_values(environment) โ€” ๐Ÿช„ Grabs a list of all File/Directory object virtualized values in the bindings ๐Ÿงš
  • extract_toil_file_uris(environment) โ€” ๐Ÿ”— Pulls out the toilfile: URIs from the given bindings ๐Ÿ’œ
  • virtualize_inodes_in_bindings(environment, file_to_id, ...) โ€” ๐Ÿซถ Fills in the virtualized_value fields for File/Directory objects ๐ŸŒˆ
  • convert_remote_files(environment, file_source, task_path) โ€” ๐ŸŒ Resolves relative-URI files in the given environment and imports all of them. No cap, it's a whole glow-up ๐Ÿ”ฅ
  • evaluate_named_expression(context, name, ...) โ€” ๐Ÿท๏ธ Evaluates an expression when we already know its name ๐Ÿ’…
  • evaluate_decl(node, environment, stdlib) โ€” ๐Ÿง  Evaluates the expression of a declaration node, or raises an error if it can't ๐Ÿ’€
  • evaluate_call_inputs(context, expressions, ...[, ...]) โ€” ๐ŸŽ€ Evaluates a bunch of named expressions and turns them into a fresh set of bindings. inputs_dict is a mapping of (the original cuts off right there, bestie ๐Ÿ˜ญ)
  • evaluate_defaultable_decl(node, environment, stdlib) โ€” ๐Ÿ“ If the declaration's name is already defined in the environment, you get its value back. Otherwise, you get the evaluated expression โœจ
  • devirtualize_inodes(environment, stdlib) โ€” ๐Ÿฆ‹ Makes sure all the File values embedded in the given bindings point to files ๐ŸŒธ
  • virtualize_inodes(environment, stdlib[, enforce_existence]) โ€” ๐Ÿชž Makes sure all the File/Directory values embedded in the given bindings point to files ๐Ÿ’–
  • delete_dead_files(internal_bindings, ...) โ€” ๐Ÿ—‘๏ธ Deletes any files that are in the given bindings but not in the live list. Bye bye, files ๐Ÿ‘‹
  • all_parents(path) โ€” โฌ†๏ธ Yields all parents of the given path, all the way up to the filesystem root ๐ŸŒณ
  • add_paths(task_container, host_paths) โ€” ๐Ÿซง Based off of WDL.runtime.task_container.add_paths from miniwdl. Iykyk ๐Ÿ’œ

๐Ÿ’… Function Table (keep scrolling, bestie) ๐Ÿ’…

  • drop_if_missing(inode, standard_library) โ€” Returns None if a File/Directory doesn't exist, or its path if it does ๐Ÿฆ‹
  • missing_inode_dropper(standard_library) โ€” Gets you a function that nulls out missing File/Directory values ๐Ÿงš
  • drop_missing_files(environment, standard_library) โ€” Makes sure every File value embedded in the given bindings actually points to a file ๐Ÿ“
  • get_paths_in_bindings(environment) โ€” Grabs the paths of all Files and Directories in the bindings ๐ŸŒธ
  • map_over_inodes_in_bindings(environment, transform) โ€” Runs all File values embedded in the given bindings through the given transform โœจ
  • map_over_inodes_in_binding(binding, transform) โ€” Runs all File values' types and values embedded in the given binding's value through the given transform ๐Ÿ’œ
  • remove_expr_from_value(value) โ€” Removes the expression from a WDL value, bye bye ๐Ÿ‘‹
  • map_over_typed_value(value, transform) โ€” Applies a transform to a WDL value and every WDL value it contains ๐Ÿ“
  • map_over_typed_inodes_in_value(value, transform) โ€” Runs all File values embedded in the given value through the given transform ๐ŸŽ€
  • ensure_null_inodes_are_nullable(value, original_value, ...) โ€” Walks through all the nested values inside the given value and double-checks that the null values are valid ๐Ÿ™ˆ
  • make_root_job(target, inputs, inputs_search_path, ...) โ€” (No description was given for this one, so we're leaving it there, babe.) ๐Ÿซถ
  • main() โ€” The main event: a Toil workflow that interprets WDL input files ๐Ÿ‘‘

โœจ Module Contents โœจ

okay so this next bit is the actual inventory of the module, and it's giving "everything you need, all in one place" ๐Ÿ’–

  • toil.wdl.wdltoil.logger
  • toil.wdl.wdltoil.WDLINode
  • toil.wdl.wdltoil.AnyINode

๐Ÿฆ‹ class toil.wdl.wdltoil.INodeTransform

Bases: Protocol

This is a type for a function that takes a File or Directory and hands back a modified copy, or None.

ngl the typing here is a whole thing ๐Ÿ’€ If you write Callable[[AnyINode], AnyINode] as an argument type, your function becomes generic over the type variable, but that does not mean you're accepting a function that's generic over it too. So the module defines a more complicated type for functions that turn inodes into the same kind of inode. Main character energy ๐Ÿ‘‘

Its __call__ comes in two flavors:

__call__(__file: WDL.Value.File) -> WDL.Value.File | None
__call__(__directory: WDL.Value.Directory) -> WDL.Value.Directory | None

๐ŸŒˆ toil.wdl.wdltoil.is_inode(value)

This one checks whether a WDL value is a File or a Directory. It's a MyPy type guard, so if you wrap code in an if statement that calls it, MyPy gets convinced it's safe to treat whatever you passed in as a File-or-Directory. Iykyk ๐Ÿงš

  • Parameters
    • value (WDL.Value.Base)
  • Return type
    • typing_extensions.TypeGuard[WDLINode]

๐ŸŽ€ class toil.wdl.wdltoil.ReadableFileObj

Bases: Protocol

A protocol that's more specific than what file_digest takes as an argument, and it guarantees you get a read() method. Lowkey it's the bestie of the hashing world ๐Ÿซถ

It was going to extend the Typeshed protocol for hashlib, but those only get declared for 3.11+, so we're not doing that. Rip ๐Ÿ˜ญ

  • readinto(buf, /)
    • Parameters
      • buf (bytearray)
    • Return type
      • int
  • readable()
    • Return type
      • bool
  • read(number)
    • Parameters
      • number (int)
    • Return type
      • bytes

๐Ÿ“ class toil.wdl.wdltoil.FileDigester

Bases: Protocol

A protocol for just the features we need from hashlib.file_digest. Only the essentials, no notes ๐Ÿ’…

  • __call__(__f, __alg_name)
    • Parameters
      • __f (ReadableFileObj)
      • __alg_name (str)
    • Return type
      • hashlib._Hash

๐Ÿ”ฅ toil.wdl.wdltoil.file_digest: FileDigester

This is the file digester itself, typed as a FileDigester. Slay ๐Ÿ”ฅ

๐Ÿ’œ toil.wdl.wdltoil.WDLContext

The WDL context. Just sitting there being important ๐ŸŒธ

โš ๏ธ exception toil.wdl.wdltoil.InsufficientMountDiskSpace(mount_targets, desired_bytes, available_bytes)

Bases: Exception

This is the common base class for all non-exit exceptions. So when your mount doesn't have enough space, this is the drama ๐Ÿ˜ญ

  • Parameters
    • mount_targets (list[str])
    • desired_bytes (int)
    • available_bytes (int)

๐Ÿงš toil.wdl.wdltoil.wdl_error_reporter(task, exit=False, log=logger.critical)

This lets you run code in a context where WDL errors get reported with pretty formatting. Chef's kiss โœจ

  • Parameters
    • task (str)
    • exit (bool)
    • log (Callable[[str], None])
  • Return type
    • Generator[None]

๐ŸŒˆ toil.wdl.wdltoil.F

Just the F name, living its best life ๐Ÿฆ‹

๐ŸŒธ toil.wdl.wdltoil.report_wdl_errors(task, exit=False, log=logger.critical)

This creates a decorator that reports WDL errors with the task message you give it. You slap the decorator on a function, and if a WDL error happens, it says that it could not {task}. Super iconic, no notes ๐Ÿ’–

  • Parameters
    • task (str)
    • exit (bool)
    • log (Callable[[str], None])
  • Return type
    • Callable[[F], F]

๐Ÿ’– toil.wdl.wdltoil.toil_read_source(uri, path, importer)

okay so this one is a MiniWDL read_source function that can use any filename or URL Toil supports ๐ŸŒธ it's giving versatile โœจ and it has to be async because MiniWDL is going to await its result, so don't skip that part bestie ๐Ÿ’…

Parameters

  • uri (str) ๐Ÿงš
  • path (list[str]) ๐Ÿงš
  • importer (WDL.Tree.Document | None) ๐Ÿงš

Return type โ€” WDL.Tree.ReadSourceResult ๐ŸŽ€


๐Ÿ’œ toil.wdl.wdltoil.virtualized_equal(value1, value2)

this one checks if two WDL values are equal while accounting for file virtualization ๐Ÿฆ‹ main character energy for real. it treats virtualized and non-virtualized Files and Directories that point at the same underlying thing as equal, so no drama over that ๐Ÿซถ

Parameters

  • value1 (WDL.Value.Base) โ€” a WDL value ๐Ÿ’–
  • value2 (WDL.Value.Base) โ€” a WDL value ๐Ÿ’–

Returns โ€” whether the two values are equal with file and directory virtualization accounted for โœจ

Return type โ€” bool ๐Ÿ’…


๐ŸŒˆ toil.wdl.wdltoil.WDLBindings

just vibing here with no description at all ๐Ÿ™ˆ it's listed by itself, so consider it the mysterious one in the group chat ๐Ÿ‘‘


๐Ÿ”ฅ toil.wdl.wdltoil.combine_bindings(all_bindings)

this one takes variable bindings from multiple predecessor tasks and smooshes them into one set for the current task ๐Ÿซถ it's like merging everyone's notes before the group project is due ๐Ÿ“

Parameters

  • all_bindings (Sequence[WDLBindings]) ๐Ÿงš

Return type โ€” WDLBindings โœจ


๐Ÿฆ‹ toil.wdl.wdltoil.log_bindings(log_function, message, all_bindings)

this one logs bindings to the console, even if some of them are still promises ๐Ÿ”ฎ yes, we love a little chaos, but it all still gets logged ๐Ÿ’…

Parameters

  • log_function (Callable[Ellipsis, None]) โ€” the function you want to log with, like logger.info ๐Ÿ“ฃ
  • message (str) โ€” a message to log right before the bindings ๐Ÿ’ฌ
  • all_bindings (Sequence[toil.job.Promised[WDLBindings]]) โ€” a list of bindings or promises for bindings that you want logged ๐ŸŒธ

Return type โ€” None ๐Ÿซง


๐Ÿงš toil.wdl.wdltoil.get_supertype(types)

this one finds the supertype that can hold values of all the given types ๐Ÿ‘‘ it's the one type that's big enough to fit everybody, no cap ๐Ÿ“

Parameters

  • types (Sequence[WDL.Type.Base]) ๐Ÿงš

Return type โ€” WDL.Type.Base ๐Ÿ’–


๐ŸŒธ toil.wdl.wdltoil.for_each_node(root)

okay so this one is an iterator that goes through all WDL workflow nodes inside the given node ๐Ÿฆ‹ that includes inputs, internal nodes of conditionals and scatters, and gather nodes. literally everything, nobody gets left out ๐Ÿซถ

Parameters

  • root (WDL.Tree.WorkflowNode) ๐Ÿ’–

Return type โ€” Iterator[WDL.Tree.WorkflowNode] โœจ


๐Ÿ’œ toil.wdl.wdltoil.recursive_dependencies(root)

this one gathers up the combined workflow_node_dependencies of root and everything under it, but only the ones that aren't satisfied by something inside that same subtree ๐Ÿ”ฅ it's useful because section nodes can have internal nodes with dependencies that don't show up in the section node's own list, so this one catches them ๐Ÿซถ

Parameters

  • root (WDL.Tree.WorkflowNode) ๐Ÿ’–

Return type โ€” set[str] ๐ŸŽ€


๐ŸŽ€ toil.wdl.wdltoil.parse_disks(spec, disks_spec)

this one takes a WDL disk spec and turns it into a disk mount specification ๐Ÿ’… it hands back three things: the mount point (None if it was omitted or is local-disk), the number of units, and the size of each unit (like GB).

Parameters

  • spec (str) โ€” the disks spec you want to parse ๐Ÿ’–
  • disks_spec (list[WDL.Value.String] | str) โ€” the full disks spec as written in the WDL file. it's only there for better error messages, so it's not really doing the parsing ๐Ÿ™ˆ

Return type โ€” tuple[str | None, float, str] ๐Ÿฆ‹


๐Ÿซง toil.wdl.wdltoil.pack_toil_uri(file_id, task_path, parent, file_basename)

this one packs a Toil file ID plus info about who wrote the file into a URI ๐Ÿ”ฎ the URI always starts with the scheme in TOIL_URI_SCHEME, so you know what you're looking at โœจ

Parameters

  • parent (str) โ€” the bare path or URI to the parent of the file. only one unique value can be used for a given parent location ๐Ÿšจ it has to match the name parameter of toil.lib.directory.encode_directory(). it can be absolute or relative, but to avoid collisions it should only be relative for worker temp storage ๐ŸŒธ
  • file_id (toil.fileStores.FileID) ๐Ÿงš
  • task_path (str) ๐Ÿงš
  • file_basename (str) ๐Ÿงš

Return type โ€” str ๐Ÿ’–


๐ŸŒˆ toil.wdl.wdltoil.unpack_toil_uri(toil_uri)

the opposite of packing! this one unpacks a URI made by make_toil_uri ๐Ÿ™ˆ yes, that's what the docs say, iykyk ๐Ÿ’€

Returns โ€” you get back the FileID, source task, source parent path or URI, and basename, all in one go ๐ŸŽ

Parameters

  • toil_uri (str) ๐Ÿงš

Return type โ€” tuple[toil.fileStores.FileID, str, str, str] โœจ


โญ toil.wdl.wdltoil.SHARED_PATH_ATTR

a little constant that's set to '_shared_fs_path' ๐Ÿฆ‹ it's the attribute name we use for the shared filesystem path, so it's worth knowing ๐Ÿงš


๐Ÿ’… toil.wdl.wdltoil.clone_metadata(old_inode, new_inode)

this one copies all Toil metadata from one WDL File/Directory over to another ๐Ÿซถ total glow-up, nothing gets left behind ๐Ÿ’–

Parameters

  • old_inode (AnyINode) ๐Ÿงš
  • new_inode (AnyINode) ๐Ÿงš

Return type โ€” None ๐Ÿซง


๐Ÿฆ‹ toil.wdl.wdltoil.make_inode(example_inode, value, expr)

this one makes a brand new File or Directory that's the same type as the example, using the arguments you give it ๐ŸŒธ fun fact: we use this because MyPy can't tell that type(a)(args) has the same type as a when a is typed with a TypeVar. MyPy really be out here not understanding the assignment ๐Ÿ’€

Parameters

  • example_inode (AnyINode) ๐Ÿงš
  • value (str) ๐Ÿงš
  • expr (Optional[WDL.Expr.Base]) ๐Ÿงš

Return type โ€” AnyINode โœจ


๐Ÿ’– toil.wdl.wdltoil.set_inode_value(inode, new_value)

this one returns a copy of a WDL File/Directory with the value changed ๐Ÿ”ฅ and it keeps all the Toil metadata intact, so nothing gets lost in the shuffle ๐Ÿซถ

Parameters

  • inode (AnyINode) ๐Ÿงš
  • new_value (str) ๐Ÿงš

Return type โ€” AnyINode ๐Ÿ’…


๐ŸŽ€ toil.wdl.wdltoil.set_inode_nonexistent(inode, nonexistent)

this one returns a copy of a WDL File/Directory with the nonexistent flag changed ๐ŸŒˆ all Toil metadata gets preserved here too, we love consistency ๐Ÿ’œ

Parameters

  • inode (AnyINode) ๐Ÿงš
  • nonexistent (bool) ๐Ÿงš

Return type โ€” AnyINode ๐Ÿซง


๐Ÿงš toil.wdl.wdltoil.get_inode_nonexistent(inode)

this one gets the nonexistent flag for a File/Direcotry (yes, that's how it's spelled in the docs ๐Ÿ™ˆ) ๐ŸŒธ

Parameters

  • inode (WDLINode) ๐Ÿงš

Return type โ€” bool โœจ


๐Ÿ”ฎ toil.wdl.wdltoil.set_inode_virtualized_value(inode, virtualized_value)

this one returns a copy of a WDL File/Directory with the virtualized_value attribute set ๐Ÿฆ‹ all Toil metadata stays put, obviously ๐Ÿ’–

Parameters

  • inode (AnyINode) ๐Ÿงš
  • virtualized_value (str) ๐Ÿงš

Return type โ€” AnyINode ๐Ÿซถ


๐ŸŒธ toil.wdl.wdltoil.get_inode_virtualized_value(inode)

this one gets the virtualized storage location for a File/Directory ๐Ÿ’… it's the place it's actually stored behind the scenes ๐Ÿซง

Parameters

  • inode (WDLINode) ๐Ÿงš

Return type โ€” Optional[str] ๐ŸŽ€


๐Ÿ’œ toil.wdl.wdltoil.get_shared_fs_path(inode)

if a File/Directory has a shared filesystem path, this one gets that path for you ๐ŸŒˆ it'll be the path the File was first imported from, or the path it has in the call cache, so you know where it came from ๐Ÿซถ

Parameters

  • inode (WDLINode) ๐Ÿงš

Return type โ€” Optional[str] ๐Ÿ’–


๐Ÿ”ฅ toil.wdl.wdltoil.set_shared_fs_path(inode, path)

this one returns a copy of the given File/Directory with a shared filesystem path set ๐Ÿฆ‹ ideally this should be the path it was originally imported from, or the path it has in the call cache ๐ŸŒธ

Parameters

  • inode (AnyINode) ๐Ÿงš
  • path (str) ๐Ÿงš

Return type โ€” AnyINode โœจ


๐Ÿซง toil.wdl.wdltoil.view_shared_fs_paths(bindings)

given some WDL bindings, this one returns a copy where every file's value is its shared filesystem path ๐Ÿ”ฎ it's like a little filter that shows you the real addresses, periodt ๐Ÿ’…

Parameters

  • bindings (WDLBindings) ๐Ÿงš

Return type โ€” WDLBindings ๐ŸŽ€


๐Ÿ“ toil.wdl.wdltoil.poll_execution_cache(node, bindings)

this one checks the execution cache and returns the cached result of calling this workflow or task, along with its key ๐Ÿงš if the cache has no result for us, it returns None and the key, so we know to run it fresh ๐Ÿ’–

this one deals in un-namespaced bindings ๐Ÿ™ˆ

Parameters

  • node (Union[WDL.Tree.Workflow, WDL.Tree.Task]) ๐Ÿงš
  • bindings (WDLBindings) ๐Ÿงš

Return type โ€” tuple[WDLBindings | None, str] ๐Ÿ’… so you get bindings (or None) and a string, bestie ๐ŸŽ€


โœจ toil.wdl.wdltoil.fill_execution_cache โœจ

toil.wdl.wdltoil.fill_execution_cache(cache_key, output_bindings, file_store, wdl_options, miniwdl_logger=None, miniwdl_config=None)

Okay so this one caches the result of calling a workflow or task ๐Ÿ’พ๐Ÿ”ฅ It deals in un-namespaced bindings, so keep that in your back pocket ๐Ÿซถ

Parameters

  • cache_key (str) ๐Ÿ”‘
  • output_bindings (WDLBindings) ๐Ÿ“ฆ
  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore) ๐Ÿ—„๏ธ
  • wdl_options (WDLContext) โš™๏ธ
  • miniwdl_logger (Optional[logging.Logger]) ๐Ÿ“
  • miniwdl_config (Optional[WDL.runtime.config.Loader]) ๐Ÿงฉ

Returns โ€” possibly modified bindings to keep going with, which might reference the cache โœจ

Return type โ€” WDLBindings


โœจ toil.wdl.wdltoil.choose_human_readable_directory โœจ

toil.wdl.wdltoil.choose_human_readable_directory(root_dir, source_task_path, parent)

This one picks a good, human-friendly directory to save a task's files into, based on the source directory ๐ŸŒธ The directories involved might not exist yet, so don't panic if they're missing ๐Ÿ™ˆ

Parameters

  • root_dir (str) โ€” the directory the path will live under ๐Ÿก
  • source_task_path (str) โ€” the dotted WDL name of whatever made the file. We assume it's a valid filename component ๐Ÿงพ
  • parent (str) โ€” the directory path or parent URI the file came from. If it's a path, it can be absolute (on the worker or leader filesystem) or relative ๐Ÿ—บ๏ธ

Return type โ€” str


โœจ toil.wdl.wdltoil.evaluate_decls_to_bindings โœจ

toil.wdl.wdltoil.evaluate_decls_to_bindings(decls, all_bindings, standard_library, include_previous=False, drop_missing_files=False, expressions_are_defaults=False)

This one evaluates decls using a given bindings environment and standard library ๐Ÿง  It builds a brand-new bindings object that only holds the bindings from the decls you gave it. It also guarantees each decl can see the variables defined by the ones before it ๐Ÿซถ Main character sequencing, no cap ๐Ÿ‘‘

Parameters

  • all_bindings (WDLBindings) โ€” the environment to use when evaluating the decls ๐ŸŒˆ
  • decls (list[WDL.Tree.Decl]) โ€” the decls to evaluate ๐Ÿ“œ
  • standard_library (ToilWDLStdLibBase) โ€” the standard library ๐Ÿ“š
  • include_previous (bool) โ€” whether to carry the existing environment into the new one. This is False for outputs, where only the defined decls should show up ๐ŸŽฏ
  • drop_missing_files (bool) โ€” whether to coerce nonexistent files to null. The coerced elements get checked to make sure the transformation is valid. Right now this should only be turned on in output sections, see https://github.com/openwdl/wdl/issues/673#issuecomment-2248828116 ๐Ÿšจ
  • expressions_are_defaults (bool) โ€” if True, value expressions in decls are treated as default values, and any values already in the incoming environment can take precedence. If False, each decl is a fresh definition, and expressions are always evaluated and used ๐Ÿ’…

Returns โ€” a new bindings object โœจ

Return type โ€” WDLBindings


โœจ toil.wdl.wdltoil.NonDownloadingSize โœจ

class toil.wdl.wdltoil.NonDownloadingSize

Bases: WDL.StdLib._Size

This is a WDL size() implementation that avoids downloading files ๐Ÿ™…โ€โ™€๏ธ๐Ÿ“‰ Miniwdl's default one downloads the entire file just to get its size, which is not it for code running on the leader, since there might not be room to fit the whole file. So this class overrides the fancy class that does the work, letting it handle sizes for FileIDs using the size info Toil already stored ๐Ÿฆ‹


โœจ toil.wdl.wdltoil.extract_inode_values โœจ

toil.wdl.wdltoil.extract_inode_values(environment)

This one grabs a list of every File or Directory object value in the given bindings ๐Ÿ“‚

Parameters

  • environment (WDLBindings) ๐ŸŒ

Return type โ€” list[str]


โœจ toil.wdl.wdltoil.extract_inode_virtualized_values โœจ

toil.wdl.wdltoil.extract_inode_virtualized_values(environment)

Similar vibe, but this one gets the virtualized values of File/Directory objects in the bindings ๐Ÿช„ If a value hasn't been virtualized, it just won't show up in the list ๐Ÿ™ˆ

Parameters

  • environment (WDLBindings) ๐ŸŒ

Return type โ€” list[str]


โœจ toil.wdl.wdltoil.extract_toil_file_uris โœจ

toil.wdl.wdltoil.extract_toil_file_uris(environment)

This one gets the toilfile: URIs from the given bindings ๐Ÿ”— It checks every File in the bindings, and every file sitting inside a Directory in the bindings ๐Ÿ—‚๏ธ

Parameters

  • environment (WDLBindings) ๐ŸŒ

Return type โ€” Iterable[str]


โœจ toil.wdl.wdltoil.virtualize_inodes_in_bindings โœจ

toil.wdl.wdltoil.virtualize_inodes_in_bindings(environment, file_to_id, file_to_metadata, task_path)

This one fills in the virtualized_value fields for File/Directory objects ๐Ÿชžโœจ

Parameters

  • environment (WDLBindings) โ€” the bindings to evaluate on. This one is not modified ๐Ÿ›ก๏ธ
  • file_to_id (Dict[str, toil.fileStores.FileID]) โ€” maps an imported URI to the Toil FileID holding the data ๐Ÿ—๏ธ
  • file_to_metadata (Dict[str, toil.job.FileMetadata]) โ€” maps a WDL-level file value to metadata about the file, including the URI that would have been imported ๐Ÿท๏ธ
  • task_path (str) ๐Ÿงญ

Returns โ€” a new bindings object with the annotated File objects inside it ๐Ÿ’–

Return type โ€” WDLBindings


โœจ toil.wdl.wdltoil.convert_remote_files โœจ

toil.wdl.wdltoil.convert_remote_files(environment, file_source, task_path, search_paths=None, import_remote_files=True, execution_dir=None)

This one resolves relative-URI files in the given environment and imports all the files ๐ŸŒโœˆ๏ธ

Returns an environment where:

  • each File's value is set to the URI it was found at ๐Ÿ“
  • its virtualized value is set to whatever it was loaded into the filestore as (if applicable) ๐Ÿ“ฆ
  • its shared filesystem path is set if it came from the local filesystem ๐Ÿ 

Parameters

  • environment (WDLBindings) โ€” the bindings to evaluate on ๐ŸŒ
  • file_source (toil.jobStores.abstractJobStore.AbstractJobStore) โ€” the context to search for files with ๐Ÿ”
  • task_path (str) โ€” the dotted WDL name of the user-level code doing the importing (probably the workflow name) ๐Ÿ‘‘
  • search_paths (Optional[list[str]]) โ€” if set, tries resolving the input location relative to the URLs or directories in this list ๐Ÿงญ
  • import_remote_files (bool) โ€” if set, imports files from remote locations. Otherwise, the files stay as URI references ๐Ÿ“Ž
  • execution_dir (Optional[str]) ๐Ÿ“

Return type โ€” WDLBindings


โœจ toil.wdl.wdltoil.ToilWDLStdLibBase โœจ

class toil.wdl.wdltoil.ToilWDLStdLibBase(file_store, wdl_options, share_files_with=None)

Bases: WDL.StdLib.Base

The standard library implementation for WDL as run on Toil ๐Ÿ“š๐Ÿฉท

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore) ๐Ÿ—„๏ธ
  • wdl_options (WDLContext) โš™๏ธ
  • share_files_with (ToilWDLStdLibBase | None) ๐Ÿค

Attributes and properties

  • size โ€” the size attribute ๐Ÿ“
  • property execution_dir: str โ€” Return type str ๐Ÿ“‚
  • property task_path: str โ€” Return type str ๐Ÿงญ

get_local_paths() โ€” gets all the local paths of files devirtualized (or virtualized) through the stdlib ๐Ÿ—บ๏ธ Return type list[str] ๐ŸŒธ

classmethod devirtualize_to(filename, dest_dir, file_source,
wdl_options, devirtualized_to_virtualized,
virtualized_to_devirtualized, export=None)

Okay bestie, this one takes a WDL virtualized filename/URL and either downloads it or exports it into the given directory. ๐Ÿ“ฆโœจ

โš ๏ธ The dest_dir has to already exist before you call this! And no other devirtualize_to call can be writing into it at the same time, not even another workflow writing the same task to the same spot in the call cache. That's a hard no ๐Ÿ’€

It keeps sibling files as siblings and stops files with the same name from clobbering each other ๐Ÿซถ. It also keeps Files or Directories inside Directories in their proper place in the hierarchy. It gets called from inside this class for tasks, and statically at the end of the workflow for outputs. โœจ

It returns the local path to the file. If the file is already a local path, or it already has an entry in virtualized_to_devirtualized, that path gets reused instead of making a fresh copy in dest_dir. ๐Ÿฆ‹

The input filename might already be devirtualized, and if so, it should not be added to the cache. Main character restraint ๐Ÿ’…

๐Ÿ“‹ Parameters

  • wdl_options (WDLContext) โ€” WDL options to carry through.
  • export (bool | None) โ€” Always creates exported copies of files instead of views that a FileStore might clean up. (docs: /usr/share/doc/python3/html/library/functions.html#bool)
  • filename (str) (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • dest_dir (str) (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • file_source (toil.fileStores.abstractFileStore.AbstractFileStore | toil.common.Toil)
  • devirtualized_to_virtualized (dict[str, str]) (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • virtualized_to_devirtualized (dict[str, str]) (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)


๐ŸŒธ class toil.wdl.wdltoil.ToilWDLStdLibWorkflow

class toil.wdl.wdltoil.ToilWDLStdLibWorkflow(*args, **kwargs)

Bases: ToilWDLStdLibBase

This is the standard library implementation for workflow scope. ๐ŸŒˆ

It handles deduplicating files made by write_* calls at workflow scope with copies that are already in the call cache, so tasks that depend on them can also be fulfilled straight from the cache. Big brain energy ๐Ÿง ๐Ÿ’–

๐Ÿ“‹ Parameters

  • args (Any)
  • kwargs (Any)

๐Ÿงš class toil.wdl.wdltoil.ToilWDLStdLibTaskCommand

class toil.wdl.wdltoil.ToilWDLStdLibTaskCommand(file_store, container,
wdl_options)

Bases: ToilWDLStdLibBase

This is the standard library implementation you use inside a WDL task command evaluation. ๐ŸŽ€

Heads up: it expects every filename in variable bindings to be a container-side path. These are the "virtualized" filenames, while the "devirtualized" filenames are host-side paths. Keep those two straight or you'll be cooked ๐Ÿ’€

๐Ÿ“‹ Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)
  • container (WDL.runtime.task_container.TaskContainer)
  • wdl_options (WDLContext)

Member: container


๐Ÿ‘‘ class toil.wdl.wdltoil.ToilWDLStdLibTaskOutputs

class toil.wdl.wdltoil.ToilWDLStdLibTaskOutputs(file_store, stdout_path,
stderr_path, file_to_mountpoint, wdl_options, share_files_with=None)

Bases: ToilWDLStdLibBase, WDL.StdLib.TaskOutputs

This is the standard library implementation for WDL running on Toil, with extra functions that are only allowed in task output sections. ๐Ÿ”ฅ

๐Ÿ“‹ Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)
  • stdout_path (str) (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • stderr_path (str) (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • file_to_mountpoint (dict[str, str]) (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • wdl_options (WDLContext)
  • share_files_with (ToilWDLStdLibBase | None)

โœจ stdout_used()

Returns True if the WDL read the standard output. ๐Ÿ“ค

Return type: bool (docs: /usr/share/doc/python3/html/library/functions.html#bool)

โœจ stderr_used()

Returns True if the WDL read the standard error. ๐Ÿ“ฅ

Return type: bool (docs: /usr/share/doc/python3/html/library/functions.html#bool)


๐Ÿฆ‹ toil.wdl.wdltoil.evaluate_named_expression

toil.wdl.wdltoil.evaluate_named_expression(context, name, expected_type,
expression, environment, stdlib)

Evaluates an expression when you already know its name. Simple and iconic ๐ŸŒท

๐Ÿ“‹ Parameters

  • context (WDL.Error.SourceNode | WDL.Error.SourcePosition)
  • name (str) (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)
  • expected_type (WDL.Type.Base | None)
  • expression (WDL.Expr.Base | None)
  • environment (WDLBindings)
  • stdlib (WDL.StdLib.Base)

Return type: WDL.Value.Base


๐Ÿ“ toil.wdl.wdltoil.evaluate_decl

toil.wdl.wdltoil.evaluate_decl(node, environment, stdlib)

Evaluates the expression of a declaration node, or raises an error if it can't. ๐Ÿšซ

๐Ÿ“‹ Parameters

  • node (WDL.Tree.Decl)
  • environment (WDLBindings)
  • stdlib (WDL.StdLib.Base)

Return type: WDL.Value.Base


๐Ÿ’œ toil.wdl.wdltoil.evaluate_call_inputs

toil.wdl.wdltoil.evaluate_call_inputs(context, expressions, environment,
stdlib, inputs_dict=None)

Evaluates a whole batch of named expressions and turns them into a fresh set of bindings. ๐Ÿง

inputs_dict is a mapping of variable names to their expected type for the input decls in a task. Basically the cheat sheet for types ๐Ÿ“

๐Ÿ“‹ Parameters

  • context (WDL.Error.SourceNode | WDL.Error.SourcePosition)
  • expressions (dict[str, WDL.Expr.Base]) (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)
  • environment (WDLBindings)
  • stdlib (WDL.StdLib.Base)
  • inputs_dict (dict[str, WDL.Type.Base] | None) (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: WDLBindings


๐ŸŒˆ toil.wdl.wdltoil.evaluate_defaultable_decl

toil.wdl.wdltoil.evaluate_defaultable_decl(node, environment, stdlib)

If the declaration's name is already defined in the environment, this returns its value. Otherwise, it returns the evaluated expression. It's giving "use what you've got" ๐Ÿซถ

๐Ÿ“‹ Parameters

  • node (WDL.Tree.Decl)
  • environment (WDLBindings)
  • stdlib (WDL.StdLib.Base)

Return type: WDL.Value.Base


โญ toil.wdl.wdltoil.devirtualize_inodes

toil.wdl.wdltoil.devirtualize_inodes(environment, stdlib)

This makes sure every File value embedded in the given bindings points to a file that command line commands can actually reach. ๐Ÿ—๏ธ The same virtual file always maps to the same devirtualized filename, even when there are duplicates, so no mix-ups ๐Ÿ™ˆ

๐Ÿ“‹ Parameters

  • environment (WDLBindings)
  • stdlib (ToilWDLStdLibBase)

Return type: WDLBindings


๐Ÿซง toil.wdl.wdltoil.virtualize_inodes

toil.wdl.wdltoil.virtualize_inodes(environment, stdlib,
enforce_existence=True)

This makes sure every File/Directory value embedded in the given bindings points to a file that other machines can use. Multi-machine serve ๐ŸŒโœจ

๐Ÿ“‹ Parameters

  • environment (WDLBindings)
  • stdlib (ToilWDLStdLibBase)
  • enforce_existence (bool) (docs: /usr/share/doc/python3/html/library/functions.html#bool)

Return type: WDLBindings


๐Ÿ—‘๏ธ toil.wdl.wdltoil.delete_dead_files

toil.wdl.wdltoil.delete_dead_files(internal_bindings,
live_bindings_list, file_store)

Deletes any files that are in the given bindings but not in the live list. Bye bye, clutter ๐Ÿ‘‹๐Ÿ’…

It scans the virtualized values of File and Directory objects anywhere in the bindings. It only tries to delete leaf files, never whole directories, so your folders are safe ๐Ÿซถ

๐Ÿ“‹ Parameters

  • internal_bindings (WDLBindings)
  • live_bindings_list (list[WDLBindings]) (docs: /usr/share/doc/python3/html/library/stdtypes.html#list)
  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type: None


๐ŸŒŠ toil.wdl.wdltoil.all_parents

toil.wdl.wdltoil.all_parents(path)

Yields all parents of the given path, all the way up to the filesystem root. ๐ŸŒณ

All yielded parents end in "/". If the path is "/", it yields the path itself. Otherwise, if the path ends in "/", it does not yield the path itself. Tiny rules, big payoff ๐Ÿ’–

๐Ÿ“‹ Parameters

  • path (str) (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: Iterable[str] (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ’– toil.wdl.wdltoil.add_paths(task_container, host_paths)

okay so this one is the sorting hat for paths ๐Ÿงš It's based off WDL.runtime.task_container.add_paths from miniwdl, but it levels up. For every host path it comes up with a container path, then fills in input_path_map and input_path_map_rev on the TaskContainer so you can go host โ†’ container and container โ†’ host. โœจ

It also makes sure directories always end with a trailing slash, bestie. ๐Ÿ“

Here's the part that matters: File and Directory sibling constraints are a whole thing, so anything that's a child of something on the host has to stay a child of that same thing in the container. MiniWDL's add_paths didn't do this, so Toil fixes it. ๐Ÿซถ Directories sitting at the top of the included hierarchy also have to stay siblings if they were siblings originally. No drama allowed ๐Ÿ’…

๐Ÿ“ TODO: Maybe dedupe this with the CWL mount dedup code that's built around "nonredundant mounts"? But unlike that code, this one has to list every File or Directory mentioned in the input, even if a mount is redundant. Probably. The reason is that Toil isn't sure yet whether those mappings get used for reverse lookups. ๐Ÿคทโ€โ™€๏ธ

Parameters

  • task_container (WDL.runtime.task_container.TaskContainer)
  • host_paths (Iterable[str])

Return type

None


๐ŸŒธ toil.wdl.wdltoil.drop_if_missing(inode, standard_library)

This one's a bouncer ๐Ÿšช If the File or Directory doesn't exist, it returns None. If it does exist, it returns its path. Simple, iconic. ๐Ÿ™ˆ

Parameters

  • inode (WDLINode)
  • standard_library (ToilWDLStdLibBase)

Return type

WDLINode | None


๐Ÿฆ‹ toil.wdl.wdltoil.missing_inode_dropper(standard_library)

This one hands you a function that nulls out any missing File or Directory values ๐Ÿซง The function needs a standard library so it knows which current directory to use when it turns strings into paths. Very thoughtful of it, ngl. ๐Ÿ’œ

Parameters

  • standard_library (ToilWDLStdLibBase)

Return type

INodeTransform


๐Ÿ“ toil.wdl.wdltoil.drop_missing_files(environment, standard_library)

Okay so this one makes sure every File value stuffed inside the bindings either points to a file that actually exists, or is null. Zero ghost files allowed ๐Ÿ‘ป Heads up: the Files here must not be virtualized. โš ๏ธ

Parameters

  • environment (WDLBindings)
  • standard_library (ToilWDLStdLibBase)

Return type

WDLBindings


๐Ÿงš toil.wdl.wdltoil.get_paths_in_bindings(environment)

This one collects the paths of every File and Directory in the bindings and gives you back a list with no duplicates. Clean girl energy โœจ

๐Ÿ“ TODO: This is kinda duplicative with WDL.runtime.task._fspaths. Noted, bestie. ๐Ÿซถ

Parameters

  • environment (WDLBindings)

Return type

list[str]


๐ŸŽ€ toil.wdl.wdltoil.map_over_inodes_in_bindings(environment, transform)

Runs every File value in the bindings through your transformation function ๐Ÿ’… The transform is not allowed to mutate the original File, so don't you dare ๐Ÿ˜ค

๐Ÿ“ TODO: Swap this out for WDL.Value.rewrite_env_paths or WDL.Value.rewrite_files eventually. ๐ŸŒˆ

Parameters

  • environment (WDLBindings)
  • transform (INodeTransform)

Return type

WDLBindings


๐Ÿ’œ toil.wdl.wdltoil.map_over_inodes_in_binding(binding, transform)

Same energy as the one above, but for a single binding ๐Ÿงธ It runs all File values' types and values inside that binding's value through the transform. Again, the transform must not mutate the original File. Iykyk. ๐Ÿ™ƒ

Parameters

  • binding (WDL.Env.Binding[WDL.Value.Base])
  • transform (INodeTransform)

Return type

WDL.Env.Binding[WDL.Value.Base]


๐Ÿซง toil.wdl.wdltoil.remove_expr_from_value(value)

Takes a WDL value and gives you back a brand new one with the expr field stripped out ๐Ÿช„ Think of it as a glow-up with no expression attached. ๐Ÿ’–

Parameters

  • value (WDL.Value.Base): the original WDL value

Return type

WDL.Value.Base: a new WDL value without the expr field


๐ŸŒท toil.wdl.wdltoil.map_over_typed_value(value, transform)

This one's the main character ๐Ÿ‘‘ It applies a transform to a WDL value and every WDL value it contains. The transform takes a WDL value and hands back a new one. Recursive slay ๐Ÿ”ฅ

Parameters

  • value (WDL.Value.Base): the WDL value to transform
  • transform (Callable[[WDL.Value.Base], WDL.Value.Base]): takes a WDL value and returns a new WDL value

Return type

WDL.Value.Base: the new transformed WDL value


๐Ÿ’ toil.wdl.wdltoil.map_over_typed_inodes_in_value(value, transform)

Runs all File values embedded in the given value through the transformation function ๐ŸŽฌ Same golden rule: the transform must not mutate the original File. ๐Ÿšซ

Here's the tea โ˜• If the transform returns None, that file value gets changed to Null. The transform also gets access to type info, so it knows whether it's allowed to return None (which depends on whether the value is optional or not).

โš ๏ธ The transform may only return None if the mapping result won't actually get used. This is what lets scans work. That means any error checking has to live inside the transform itself. Be careful out there, babe ๐Ÿซถ

Parameters

  • value (WDL.Value.Base)
  • transform (INodeTransform)

Return type

WDL.Value.Base


๐ŸŒ™ toil.wdl.wdltoil.ensure_null_inodes_are_nullable(value, original_value, expected_type)

This is the bodyguard for null values ๐Ÿ›ก๏ธ It walks through every nested value inside value and checks that each null is valid. If it finds a null that doesn't have a matching expected_type that's allowed to be null, it raises an error. ๐Ÿ˜ญ

Fun side quest: this function is currently only used to check that nulls coming from File/Directory coercion sit in places with a nullable type. If someone uses it somewhere else, the error message needs updating so it describes the right types instead of just talking about files. Noted, bestie ๐Ÿ“

For example: if one of the nested values is null but the matching nested expected_type isn't optional, a FileNotFoundError gets raised. ๐Ÿšจ

Parameters

  • value (WDL.Value.Base): the WDL base value to check. This is the transformed value that has the null elements.
  • original_value (WDL.Value.Base): the original WDL base value from before the transformation. Only used for error messages.
  • expected_type (WDL.Type.Base): the WDL type of the value

Return type

None


๐Ÿงธ class toil.wdl.wdltoil.WDLBaseJob(wdl_options, **kwargs)

Bases: toil.job.Job

This is the base class for every WDL-related job, so it's giving foundation ๐Ÿ—๏ธ It handles post-processing of returned bindings, like adding in null values for things a section didn't define. You can queue up post-processing on any job before it gets saved, and it'll be applied as long as the job's run method calls postprocess(). It also remembers the Toil WDL configuration keys and values. ๐Ÿ’…

Parameters

  • wdl_options (WDLContext)
  • kwargs (Any)

๐Ÿ’• run(file_store)

Runs a WDL-related job. โœจ If you're writing a non-trivial override, remember to decorate it with report_wdl_errors(). Future-you will thank present-you ๐Ÿซถ

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type

Any


๐ŸŒˆ then_underlay(underlay)

Applies an underlay of backup bindings to the result. Think of it as a safety net ๐Ÿ•ธ๏ธ

Parameters

  • underlay (toil.job.Promised[WDLBindings])

Return type

None


๐Ÿ—‘๏ธ then_remove(remove)

Removes the given bindings from the result. Byebye ๐Ÿ‘‹

Parameters

  • remove (toil.job.Promised[WDLBindings])

Return type

None


๐Ÿท๏ธ then_namespace(namespace)

Puts the result bindings into a namespace. Organized girlies only ๐Ÿ“‚

Parameters

  • namespace (str)

Return type

None


๐ŸŽ€ then_overlay(overlay)

Overlays the given bindings on top of the result, which might already be namespaced. Layering is an art ๐ŸŽจ

Parameters

  • overlay (toil.job.Promised[WDLBindings])

Return type

None


๐Ÿซง remove_expr_from_bindings(bindings)

This one doesn't come with a description, so here are just the facts ๐Ÿค

Parameters

  • bindings (WDLBindings)

Return type

WDLBindings


๐Ÿ”ฎ postprocess(bindings)

Applies any queued changes to the bindings ๐Ÿช„ Subclasses' run() implementations should call this on their return values.

Parameters

  • bindings (WDLBindings)

Return type

WDLBindings


๐Ÿฆ„ defer_postprocessing(other)

Hands our postprocessing steps off to a different job. Use this when you're returning a promise for bindings from the job that issues the promise. Passing the baton ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

Parameters

  • other (WDLBaseJob)

Return type

None


๐ŸŒŸ class toil.wdl.wdltoil.WDLTaskWrapperJob(task, prev_node_results, enclosing_bindings, task_id, wdl_options, **kwargs)

Bases: WDLBaseJob

This job figures out the resources a WDL job needs to run. Resource planning, but make it aesthetic ๐Ÿ“‹๐Ÿ’–

Okay so this one is the bouncer of the whole operation ๐Ÿ’… It checks the input declarations for any inputs nobody specified ๐Ÿฆ‹, evaluates the runtime section ๐Ÿงš, and then either schedules the real WDL job or chains over to it โœจ Quick reminder: all bindings are in terms of task-internal names ๐ŸŽ€

Parameters:

  • task โ€” WDL.Tree.Task ๐ŸŒธ
  • prev_node_results โ€” Sequence[toil.job.Promised[WDLBindings]] ๐ŸŒˆ
  • enclosing_bindings โ€” WDLBindings ๐Ÿ’œ
  • task_id โ€” list[str] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“
  • wdl_options โ€” WDLContext โœจ
  • kwargs โ€” Any ๐Ÿซถ

๐Ÿ’– run(file_store)

Evaluate inputs and runtime and schedule the task ๐Ÿ”ฅ

Parameters:

  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore (anchor: #toil.fileStores.abstractFileStore.AbstractFileStore) ๐Ÿฆ‹

Return type: toil.job.Promised[WDLBindings] ๐Ÿ’…


๐Ÿ‘‘ class WDLTaskJob

class toil.wdl.wdltoil.WDLTaskJob(task, task_internal_bindings,
runtime_bindings, enclosing_bindings, task_id, mount_spec, wdl_options,
cache_key=None, **kwargs)

Bases: WDLBaseJob ๐ŸŒธ

Job that runs a WDL task. ๐Ÿ’–

This one is the main character ๐Ÿ‘‘ It's responsible for re-evaluating input declarations for unspecified inputs, evaluating the runtime section, re-scheduling if resources are not available, running any command, and evaluating the outputs ๐Ÿ”ฅ Same deal as before: all bindings are in terms of task-internal names ๐ŸŽ€

Parameters:

  • task โ€” WDL.Tree.Task ๐ŸŒธ
  • task_internal_bindings โ€” toil.job.Promised[WDLBindings] ๐ŸŒˆ
  • runtime_bindings โ€” toil.job.Promised[WDLBindings] โœจ
  • enclosing_bindings โ€” WDLBindings ๐Ÿ’œ
  • task_id โ€” list[str] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“
  • mount_spec โ€” dict[str | None, int] (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/functions.html#int) ๐Ÿฆ‹
  • wdl_options โ€” WDLContext โœจ
  • cache_key โ€” str | None (docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿงš
  • kwargs โ€” Any ๐Ÿซถ

Class attribute:

INJECTED_MESSAGE_DIR = '.toil_wdl_runtime'

๐ŸŒธ add_injections(command_string, task_container)

Inject extra Bash code from the Toil WDL runtime into the command for the container. Currently doesn't implement the MiniWDL plugin system, but does add resource usage monitoring to Docker containers ๐Ÿณ

Parameters:

  • command_string โ€” str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ’–
  • task_container โ€” WDL.runtime.task_container.TaskContainer ๐ŸŒˆ

Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str) โœจ

๐Ÿงš handle_injection_messages(outputs_library)

Handle any data received from injected runtime code in the container ๐Ÿ’…

Parameters:

  • outputs_library โ€” ToilWDLStdLibTaskOutputs (anchor: #toil.wdl.wdltoil.ToilWDLStdLibTaskOutputs) ๐ŸŽ€

Return type: None ๐ŸŒ™

๐Ÿฆ‹ handle_message_file(file_path)

Handle a message file received from in-container injected code. Takes the host-side path of the file ๐Ÿซถ

Parameters:

  • file_path โ€” str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ“

Return type: None โœจ

๐Ÿ”ฅ can_fake_root()

Determine if --fakeroot is likely to work for Singularity ๐Ÿ™ˆ

Return type: bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) ๐Ÿ’œ

๐Ÿ’€ can_mount_proc()

Determine if --containall will work for Singularity. On Kubernetes, this will result in operation not permitted ๐Ÿ˜ญ

See: https://github.com/apptainer/singularity/issues/5857

So if Kubernetes is detected, return False :return: bool ๐Ÿ™ˆ

Return type: bool (docs: /usr/share/doc/python3/html/library/functions.html#bool) โœจ

๐ŸŒˆ ensure_mount_point(file_store, mount_spec)

Ensure the mount point sources are available ๐Ÿฆ‹ It will check if the mount point source has the requested amount of space available ๐ŸŒธ

Note: We are depending on Toil's job scheduling backend to error when the sum of multiple mount points disk requests is greater than the total available. For example, if a task has two mount points request 100 GB each but there is only 100 GB available, the df check may pass but Toil should fail to schedule the jobs internally ๐Ÿ˜ญ

Parameters:

  • mount_spec โ€” dict[str | None, int] (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str, /usr/share/doc/python3/html/library/functions.html#int) โ€” this is the mount specification from the disks attribute in the WDL task. It's a dict where the key is the mount point target and the value is the size ๐Ÿ’–
  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore (anchor: #toil.fileStores.abstractFileStore.AbstractFileStore) โ€” the file store used to create a tmp directory for the mount point source ๐Ÿงš

Returns: a dict mapping mount point target to mount point source ๐ŸŽ€

Return type: dict[str, str] (docs: /usr/share/doc/python3/html/library/stdtypes.html#dict, /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿ‘‘

๐Ÿซถ run(file_store)

Actually run the task ๐Ÿ”ฅ

Parameters:

  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore (anchor: #toil.fileStores.abstractFileStore.AbstractFileStore) ๐Ÿ“

Return type: toil.job.Promised[WDLBindings] โœจ


๐ŸŒท class WDLWorkflowNodeJob

class toil.wdl.wdltoil.WDLWorkflowNodeJob(node, prev_node_results,
wdl_options, **kwargs)

Bases: WDLBaseJob ๐Ÿ’…

Job that evaluates a WDL workflow node. ๐ŸŒธ

Parameters:

  • node โ€” WDL.Tree.WorkflowNode ๐Ÿฆ‹
  • prev_node_results โ€” Sequence[toil.job.Promised[WDLBindings]] ๐ŸŒˆ
  • wdl_options โ€” WDLContext โœจ
  • kwargs โ€” Any ๐Ÿซถ

๐Ÿ’œ run(file_store)

Actually execute the workflow node ๐Ÿ”ฅ

Parameters:

  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore (anchor: #toil.fileStores.abstractFileStore.AbstractFileStore) ๐Ÿงš

Return type: toil.job.Promised[WDLBindings] ๐Ÿ’–


๐Ÿ“ class WDLWorkflowNodeListJob

class toil.wdl.wdltoil.WDLWorkflowNodeListJob(nodes, prev_node_results,
wdl_options, **kwargs)

Bases: WDLBaseJob ๐ŸŽ€

Job that evaluates a list of WDL workflow nodes, which are in the same scope and in a topological dependency order, and which do not call out to any other workflows or tasks or sections. โœจ

Parameters:

  • nodes โ€” list[WDL.Tree.WorkflowNode] (docs: /usr/share/doc/python3/html/library/stdtypes.html#list) ๐Ÿ’…
  • prev_node_results โ€” Sequence[toil.job.Promised[WDLBindings]] ๐ŸŒˆ
  • wdl_options โ€” WDLContext โœจ
  • kwargs โ€” Any ๐Ÿซถ

๐Ÿฆ‹ run(file_store)

Actually execute the workflow nodes ๐Ÿ”ฅ

Parameters:

  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore (anchor: #toil.fileStores.abstractFileStore.AbstractFileStore) ๐ŸŒธ

Return type: toil.job.Promised[WDLBindings] ๐Ÿ‘‘


๐ŸŒˆ class WDLCombineBindingsJob

class toil.wdl.wdltoil.WDLCombineBindingsJob(prev_node_results,
**kwargs)

Bases: WDLBaseJob ๐Ÿ’œ

Job that collects the results from WDL workflow nodes and combines their environment changes. ๐Ÿงš

Parameters:

  • prev_node_results โ€” Sequence[toil.job.Promised[WDLBindings]] ๐ŸŒˆ
  • kwargs โ€” Any ๐Ÿซถ

โœจ run(file_store)

Aggregate incoming results ๐Ÿ’…

Parameters:

  • file_store โ€” toil.fileStores.abstractFileStore.AbstractFileStore (anchor: #toil.fileStores.abstractFileStore.AbstractFileStore) ๐Ÿ“

Return type: WDLBindings ๐ŸŽ€


๐Ÿฆ‹ class WDLWorkflowGraph

class toil.wdl.wdltoil.WDLWorkflowGraph(nodes)

Represents a graph of WDL WorkflowNodes. ๐ŸŒธ

Operates at a certain level of instantiation (i.e. sub-sections are represented by single nodes) ๐Ÿ”ฅ

Assumes all relevant nodes are provided. Dependencies outside the provided nodes are assumed to be satisfied already ๐Ÿ’–

Parameters:

  • nodes โ€” Sequence[WDL.Tree.WorkflowNode] ๐ŸŒˆ

๐Ÿซถ real_id(node_id)

Map multiple IDs for what we consider the same node to one ID. This elides/resolves gathers ๐Ÿฆ‹

Parameters:

  • node_id โ€” str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str) ๐Ÿงš

Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str) โœจ

๐Ÿ’€ is_decl(node_id)

Return True if a node represents a WDL declaration, and false otherwise ๐Ÿ™ˆ

Parameters

  • node_id (str </usr/share/doc/python3/html/library/stdtypes.html#str>) ๐Ÿ’–

Return type bool </usr/share/doc/python3/html/library/functions.html#bool> โœจ

๐ŸŒธ get(node_id)

Okay so this one is the "gimme that node" move ๐Ÿ“ It grabs a node by its ID.

Parameters

  • node_id (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type WDL.Tree.WorkflowNode

๐Ÿฆ‹ get_dependencies(node_id)

Get all the nodes that a node depends on, recursively (into the node if it has a body) but not transitively. It digs into the node if there's a body ๐Ÿง  but it doesn't go down the whole rabbit hole, bestie ๐Ÿ™ˆ

It only hands back dependencies after gathers and internal-to-section dependencies are resolved, and only for nodes that are also in this graph โœจ

Parameters

  • node_id (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type set </usr/share/doc/python3/html/library/stdtypes.html#set>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]

๐Ÿ”ฎ get_transitive_dependencies(node_id)

Get all the nodes that a node depends on, transitively. This is the full chain, no cap ๐Ÿ‘‘

Parameters

  • node_id (str </usr/share/doc/python3/html/library/stdtypes.html#str>)

Return type set </usr/share/doc/python3/html/library/stdtypes.html#set>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]

๐Ÿงญ topological_order()

Get a topological order of the nodes, based on their dependencies. It's giving "who goes first" energy ๐ŸŽ€

Return type list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]

๐Ÿƒ leaves()

Get all the workflow node IDs that have no dependents in the graph. These are the end-of-the-line nodes, the ones nothing else is waiting on ๐Ÿฅน

Return type list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]


๐Ÿงš class toil.wdl.wdltoil.WDLSectionJob(wdl_options, **kwargs)

Bases: WDLBaseJob

A job that can create more graph for a section of the workflow. Main character energy for sections ๐Ÿ’…

Parameters

  • wdl_options (WDLContext)
  • kwargs (Any)

โœจ static coalesce_nodes(order, section_graph)

Given a topological order of WDL workflow node IDs, this produces a list of lists of IDs. Everything stays in topological order, and each inner list can run under a single Toil job, so it's basically bundling the tasks up for the group chat ๐Ÿซถ

Parameters

  • order (list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>])
  • section_graph (WDLWorkflowGraph <#toil.wdl.wdltoil.WDLWorkflowGraph>)

Return type list </usr/share/doc/python3/html/library/stdtypes.html#list>[list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]]

๐ŸŒˆ create_subgraph(nodes, gather_nodes, environment, local_environment=None, subscript=None)

Make a Toil job to evaluate a subgraph inside a workflow or workflow section. It's giving full glam ๐Ÿ’–

Returns

A child Job that will return the aggregated environment after running all the things in the section.

Parameters

  • gather_nodes (Sequence[WDL.Tree.Gather]) โ€” Names exposed by these will always be defined with something, even if the code that defines them does not actually run. Never left on read ๐Ÿ‘€
  • environment (WDLBindings) โ€” Bindings in this environment will be used to evaluate the subgraph and will be passed through.
  • local_environment (WDLBindings | None) โ€” Bindings in this environment will be used to evaluate the subgraph but will go out of scope at the end of the section. Temporary, but still valid ๐Ÿฆ‹
  • subscript (int </usr/share/doc/python3/html/library/functions.html#int> | None) โ€” If the subgraph is being evaluated multiple times, this should be a disambiguating integer for logging. Helps tell the copies apart in the logs ๐Ÿ”ฅ
  • nodes (Sequence[WDL.Tree.WorkflowNode])

Return type WDLBaseJob <#toil.wdl.wdltoil.WDLBaseJob>

๐ŸŽ€ make_gather_bindings(gathers, undefined)

Given a collection of Gathers, this creates bindings from every identifier gathered to the given "undefined" placeholder. That placeholder would be Null for a single execution of the body, or an empty array for a completely unexecuted scatter ๐Ÿงธ

These bindings can be overlaid with bindings from the actual execution. That way, references to names defined in unexecuted code get a proper default undefined value instead of a KeyError at runtime. Nobody gets crashed on, periodt ๐Ÿ’…

The info for all this comes from MiniWDL's "gathers" system: <<https://miniwdl.readthedocs.io/en/latest/WDL.html#WDL.Tree.WorkflowSection.gathers>>

โš ๏ธ TODO: This approach will scale O(n^2) when run on n nested conditionals, because generating these bindings for the outer conditional will visit all the bindings from the inner ones. Not the vibe, so it's on the to-do list ๐Ÿ˜ญ

Parameters

  • gathers (Sequence[WDL.Tree.Gather])
  • undefined (WDL.Value.Base)

Return type WDLBindings


๐ŸŽ€ class toil.wdl.wdltoil.WDLScatterJob(scatter, prev_node_results, wdl_options, **kwargs)

Bases: WDLSectionJob

A job that evaluates a scatter in a WDL workflow. It runs the body for each value in an array, then makes arrays of the new bindings created in each instance of the body. If an instance of the body doesn't create a binding, it gets a null value in the matching array spot ๐Ÿ“

Parameters

  • scatter (WDL.Tree.Scatter)
  • prev_node_results (Sequence[toil.job.Promised[WDLBindings]])
  • wdl_options (WDLContext)
  • kwargs (Any)

๐Ÿš€ run(file_store)

Run the scatter. Let's gooo ๐Ÿ”ฅ

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore <#toil.fileStores.abstractFileStore.AbstractFileStore>)

Return type toil.job.Promised[WDLBindings]


๐Ÿฆ‹ class toil.wdl.wdltoil.WDLArrayBindingsJob(input_bindings, base_bindings, **kwargs)

Bases: WDLBaseJob

A job that takes all the new bindings created in an array of input environments, relative to a base environment, and produces bindings where each new binding name is bound to an array of the values from all the input environments. Ngl this is the scatter-results glow-up ๐ŸŒธ

It's useful for producing the results of a scatter ๐Ÿ’œ

Parameters

  • input_bindings (Sequence[toil.job.Promised[WDLBindings]])
  • base_bindings (WDLBindings)
  • kwargs (Any)

๐Ÿง run(file_store)

Actually produce the array-ified bindings now that the promised values are available. Finally, the reveal โœจ

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore <#toil.fileStores.abstractFileStore.AbstractFileStore>)

Return type WDLBindings


๐ŸŒท class toil.wdl.wdltoil.WDLConditionalJob(conditional, prev_node_results, wdl_options, **kwargs)

Bases: WDLSectionJob

A job that evaluates a conditional in a WDL workflow. It's the "if this, then that" queen ๐Ÿ‘‘

Parameters

  • conditional (WDL.Tree.Conditional)
  • prev_node_results (Sequence[toil.job.Promised[WDLBindings]])
  • wdl_options (WDLContext)
  • kwargs (Any)

๐ŸŽˆ run(file_store)

Run the conditional. Bestie, it's giving decision time ๐Ÿซถ

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore <#toil.fileStores.abstractFileStore.AbstractFileStore>)

Return type toil.job.Promised[WDLBindings]


๐ŸŒŸ class toil.wdl.wdltoil.WDLWorkflowJob(workflow, prev_node_results, enclosing_bindings, workflow_id, wdl_options, **kwargs)

Bases: WDLSectionJob

A job that evaluates an entire WDL workflow. The whole production, start to finish ๐ŸŽฌ

Parameters

  • workflow (WDL.Tree.Workflow)
  • prev_node_results (Sequence[toil.job.Promised[WDLBindings]])
  • enclosing_bindings (WDLBindings)
  • workflow_id (list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>])
  • wdl_options (WDLContext)
  • kwargs (Any)

๐Ÿ run(file_store)

Run the workflow, then return the result of the workflow. Served, every time ๐Ÿ’…

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore <#toil.fileStores.abstractFileStore.AbstractFileStore>)

Return type toil.job.Promised[WDLBindings]


๐Ÿงธ class toil.wdl.wdltoil.WDLOutputsJob(workflow, bindings, enclosing_bindings, wdl_options, cache_key=None, **kwargs)

Bases: WDLBaseJob

A job that evaluates an outputs section for a workflow. This is where the final results get packaged up and handed back, so it's the big finish ๐ŸŽโœจ

Returns an environment with just the outputs bound, in no namespace. ๐Ÿ’…โœจ It's the outputs-only env, no namespace drama ๐ŸŽ€

Parameters

  • workflow (WDL.Tree.Workflow)
  • bindings (toil.job.Promised[WDLBindings])
  • enclosing_bindings (WDLBindings)
  • wdl_options (WDLContext)
  • cache_key (str | None)
  • kwargs (Any)

run(file_store) ๐Ÿ”ฅ Make bindings for the outputs.

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type: WDLBindings


๐Ÿ’– class toil.wdl.wdltoil.WDLStartJob(target, inputs, wdl_options, **kwargs)

Bases: WDLSectionJob

Okay bestie, this one is the main event ๐Ÿ‘‘ It's a job that evaluates an entire WDL workflow and returns the workflow outputs, namespaced with the workflow name. Inputs can be namespaced or not, and both forms are accepted ๐Ÿซถ

Parameters

  • target (WDL.Tree.Workflow | WDL.Tree.Task)
  • inputs (toil.job.Promised[WDLBindings])
  • wdl_options (WDLContext)
  • kwargs (Any)

run(file_store) โœจ Actually build the subgraph.

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type: toil.job.Promised[WDLBindings]


๐Ÿฆ‹ class toil.wdl.wdltoil.WDLInstallImportsJob(task_path, inputs, import_data, **kwargs)

Bases: toil.job.Job

A unit of work in toil, obviously ๐Ÿงš

Parameters

  • task_path (str)
  • inputs (WDLBindings)
  • import_data (toil.job.Promised[Tuple[Dict[str, toil.fileStores.FileID], Dict[str, toil.job.FileMetadata]]])
  • kwargs (Any)

run(file_store) ๐ŸŒธ Convert the filenames in the workflow inputs into URIs.

:return: Promise of transformed workflow inputs

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type: toil.job.Promised[WDLBindings]


๐ŸŽ€ class toil.wdl.wdltoil.WDLImportWrapper(target, inputs, wdl_options, inputs_search_path, import_remote_files, import_workers_batchsize, import_workers_disk, **kwargs)

Bases: WDLSectionJob

This job is the one that organises file importing onto workers instead of the leader ๐Ÿ™Œ It's in charge of pulling out filenames and metadata, calling ImportsJob, applying the imports to the input bindings, and scheduling the start workflow job. Iconic multitasking ๐Ÿ’…

This class is only used when runImportsOnWorkers is enabled.

Parameters

  • target (Union[WDL.Tree.Workflow, WDL.Tree.Task])
  • inputs (WDLBindings)
  • wdl_options (WDLContext)
  • inputs_search_path (list[str])
  • import_remote_files (bool)
  • import_workers_batchsize (toil.job.ParseableIndivisibleResource)
  • import_workers_disk (toil.job.ParseableIndivisibleResource)
  • kwargs (Any)

run(file_store) ๐Ÿ“ Run a WDL-related job.

Remember to decorate non-trivial overrides with report_wdl_errors(). Don't skip this, babe ๐Ÿ™ˆ

Parameters

  • file_store (toil.fileStores.abstractFileStore.AbstractFileStore)

Return type: toil.job.Promised[WDLBindings]


๐ŸŒˆ toil.wdl.wdltoil.make_root_job(target, inputs, inputs_search_path, toil, wdl_options, options)

Parameters

  • target (WDL.Tree.Workflow | WDL.Tree.Task)
  • inputs (WDLBindings)
  • inputs_search_path (list[str])
  • toil (toil.common.Toil)
  • wdl_options (WDLContext)
  • options (configargparse.Namespace)

Return type: WDLSectionJob


โญ toil.wdl.wdltoil.main()

A Toil workflow to interpret WDL input files. Main character energy ๐Ÿ‘‘

Return type: None


โœจ toil.worker โœจ

๐Ÿ’œ Attributes

  • logger

๐ŸŒธ Classes

  • StatsDict โ€” Subclass of MagicExpando for type-checking purposes.

๐Ÿงš Functions

  • nextChainable(predecessor, job_store, config) โ€” Returns the next chainable job's JobDescription after the given predecessor.
  • unstick_worker([interval, timeout]) โ€” Thread function that tries to prevent the process from getting stuck. ๐Ÿซถ
  • workerScript(job_store, config, job_name, job_store_id) โ€” Worker process script, runs a job.
  • parse_args(args) โ€” Parse command-line arguments to the worker.
  • in_contexts(contexts) โ€” Unpickle and enter all the pickled, base64-encoded context managers in theโ€ฆ
  • main([argv])

๐Ÿ”ฅ Module Contents

toil.worker.logger

class toil.worker.StatsDict(*args, **kwargs)

Bases: toil.lib.expando.MagicExpando

Subclass of MagicExpando for type-checking purposes. Literally just vibes ๐Ÿ’…

jobs: list[toil.lib.expando.MagicExpando]

toil.worker.nextChainable(predecessor, job_store, config)

Returns the next chainable job's JobDescription after the given predecessor JobDescription, if one exists, or None if the chain must terminate. ๐Ÿฆ‹

Parameters

  • predecessor (toil.job.JobDescription) โ€” The job to chain from
  • job_store (toil.jobStores.abstractJobStore.AbstractJobStore) โ€” The JobStore to fetch JobDescriptions from.
  • config (toil.common.Config) โ€” The configuration for the current run.

Return type: Optional[toil.job.JobDescription]

toil.worker.unstick_worker(interval=120, timeout=120)

Thread function that tries to prevent the process from getting stuck. ๐Ÿ™ˆ

Meant to be used as a daemon thread: it has no shutdown signal, but it cleans up on exit. โœจ

Parameters

  • interval (float) โ€” Try to unstick the process at intervals of this many seconds.
  • timeout (float) โ€” Stop child processes that take longer than this many seconds to finish.

Return type: None

toil.worker.workerScript(job_store, config, job_name, job_store_id, redirect_output_to_log_file=True, local_worker_temp_dir=None, debug_flags=None)

Worker process script, runs a job. ๐Ÿซถ

Parameters

  • job_store (toil.jobStores.abstractJobStore.AbstractJobStore) โ€” this is the JobStore we fetch the JobDescriptions from ๐Ÿ—„๏ธ
  • config (toil.common.Config) โ€” the configuration for the current run โš™๏ธ
  • job_name (str) โ€” the "job name" ๐Ÿท๏ธ, which is the user-friendly name of the job that's about to run ๐ŸŒธ
  • job_store_id (str) โ€” the job store ID of the job to be run ๐Ÿ†”
  • redirect_output_to_log_file (bool) โ€” if this is False, logs go straight to the console instead of capturing the job's output ๐Ÿ“บ
  • local_worker_temp_dir (Optional[str]) โ€” the directory the worker gets to work in ๐Ÿ“
heads up bestie ๐Ÿ’€ this directory may be recursively removed after the job runs, so don't store anything precious in there.
  • debug_flags (Optional[set[str]]) โ€” flags that get set on each job before it runs ๐Ÿ›

Return int โ€” 1 if a job failed, or 0 if all jobs succeeded ๐ŸŽ‰

Return type โ€” int ๐Ÿ’œ


toil.worker.parse_args(args) โœจ

Okay so this one parses the command-line arguments for the worker ๐Ÿงš

Parameters

  • args (list[str])

Return type โ€” Any ๐ŸŒˆ


toil.worker.in_contexts(contexts) ๐Ÿฆ‹

This one is giving unpack-and-enter energy. It unpickles and enters all the pickled, base64-encoded context managers in the given list, then runs the body, then leaves them all ๐Ÿ’…

Parameters

  • contexts (list[str])

Return type โ€” collections.abc.Iterator[None] ๐Ÿ‘‘


toil.worker.main(argv=None) ๐Ÿ’–

Parameters

  • argv (Optional[list[str]])

Return type โ€” None ๐Ÿซถ


โœจ Attributes โœจ

  • log ๐Ÿชต
  • KNOWN_EXTANT_IMAGES ๐ŸŒธ

โœจ Exceptions โœจ

  • ApplianceImageNotFound โ€” error raised when using TOIL_APPLIANCE_SELF results in an HTTP error ๐Ÿ˜ญ

โœจ Functions โœจ

okay bestie, this table is the whole lineup of helpers in toil ๐Ÿ’… here's the tea:

  • which(cmd[, mode, path]) โ€” returns the path that conforms to the given mode on the Path ๐Ÿงญ
  • toilPackageDirPath() โ€” gives you the absolute path of the directory for the top-level toil package ๐Ÿ“‚
  • inVirtualEnv() โ€” checks if you're inside a virtualenv or Conda virtual environment ๐Ÿ
  • resolveEntryPoint(entryPoint) โ€” finds the path to the entry point that should work on a worker ๐Ÿ‘ท
  • physicalMemory() โ€” calculates the total physical memory, in bytes ๐Ÿง 
  • physicalDisk(directory) โ€” no blurb on this one bestie ๐Ÿ™ˆ
  • applianceSelf([forceDockerAppliance]) โ€” returns the fully qualified name of the Docker image that Toil appliance containers start from ๐Ÿณ
  • customDockerInitCmd() โ€” returns the custom command set by the TOIL_CUSTOM_DOCKER_INIT_COMMAND environment variable ๐ŸŒธ
  • customInitCmd() โ€” returns the custom command set by the TOIL_CUSTOM_INIT_COMMAND environment variable ๐ŸŒธ
  • lookupEnvVar(name, envName, defaultValue) โ€” looks up the environment variables that control Toil and logs what it found ๐Ÿ”
  • checkDockerImageExists(appliance) โ€” attempts to check a url registryName for a docker image with a given tag ๐Ÿ”Ž
  • parseDockerAppliance(appliance) โ€” pulls out the parsed registry, image reference, and tag from a docker image string ๐Ÿงฉ
  • checkDockerSchema(appliance) โ€” no blurb for this one either ๐Ÿ’€
  • requestCheckRegularDocker(origAppliance, registryName, ...) โ€” checks if an image exists using the requests library ๐Ÿ“ก
  • requestCheckDockerIo(origAppliance, imageName, tag) โ€” checks docker.io to see if an image exists using the requests library ๐Ÿ“ก
  • logProcessContext(config) โ€” no blurb here either, sorry bestie ๐Ÿ’€

โœจ Package Contents โœจ

okay so this is where we get into the actual goods ๐ŸŽ€

  • toil.log โ€” listed as a module, and that's all it says ๐Ÿชต

toil.which(cmd, mode=os.F_OK | os.X_OK, path=None)

this one was copy-pasted straight from python3.6's shutil.which() ๐Ÿ“‹ it returns the path that conforms to the given mode on the Path.

mode defaults to os.F_OK | os.X_OK. path defaults to the result of os.environ.get("PATH"), but you can override it with your own custom search path ๐Ÿ›ค๏ธ

Returns: the path found, or None.

Return type: Optional[str] (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.toilPackageDirPath()

Returns the absolute path of the directory that corresponds to the top-level toil package ๐Ÿ“‚

the return value is guaranteed to end in '/toil', so you can count on that one ๐Ÿ’–

Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.inVirtualEnv()

Tests if we're inside a virtualenv or Conda virtual environment ๐Ÿ

Return type: bool (docs: /usr/share/doc/python3/html/library/functions.html#bool)

toil.resolveEntryPoint(entryPoint)

Finds the path to the given entry point that should work on a worker ๐Ÿ‘ท

Returns: the path found, which may be an absolute or a relative path.

Parameters: entryPoint (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

toil.physicalMemory()

Calculates the total amount of physical memory, in bytes ๐Ÿง  the vibes check out in this example:

>>> n = physicalMemory()
>>> n > 0
True
>>> n == physicalMemory()
True

Return type: int (docs: /usr/share/doc/python3/html/library/functions.html#int)

toil.physicalDisk(directory)

No blurb on this one, bestie ๐Ÿ™ˆ

Parameters: directory (str, docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

Return type: int (docs: /usr/share/doc/python3/html/library/functions.html#int)

toil.applianceSelf(forceDockerAppliance=False)

Returns the fully qualified name of the Docker image that Toil appliance containers start from ๐Ÿณ the answer depends on the current version of Toil and three environment variables: TOIL_DOCKER_REGISTRY, TOIL_DOCKER_NAME and TOIL_APPLIANCE_SELF. here's how they work:

  • TOIL_DOCKER_REGISTRY โ€” picks an account on a publicly hosted docker registry like Quay or Docker Hub ๐Ÿช the default is UCSC's CGL account on Quay.io, where the Toil team publishes the official appliance images
  • TOIL_DOCKER_NAME โ€” the base name of the image ๐Ÿท๏ธ the default of toil is adequate in most cases
  • TOIL_APPLIANCE_SELF โ€” fully qualifies the appliance image, complete with registry, image name and version tag ๐Ÿ‘‘ it overrides both TOIL_DOCKER_NAME and TOIL_DOCKER_REGISTRY, as well as the version tag of the image
setting TOIL_APPLIANCE_SELF won't be necessary in most cases, so don't stress about it ๐Ÿซถ

Parameters: forceDockerAppliance (bool, docs: /usr/share/doc/python3/html/library/functions.html#bool)

Return type: str (docs: /usr/share/doc/python3/html/library/stdtypes.html#str)

๐Ÿ’– toil.customDockerInitCmd()

okay so this one just hands back whatever you stashed in the TOIL_CUSTOM_DOCKER_INIT_COMMAND environment variable ๐Ÿงš it's giving custom setup energy โœจ

The custom docker command runs before the workers and/or the primary node's services start up ๐Ÿ”ฅ

It's lowkey so useful for custom initialization on instances, like logging into private docker registries ๐Ÿ” Any single quotes get escaped for you, but the command can't include blacklisted chars (newline or tab) ๐Ÿ™…

Returns The custom command, or an empty string if the environment variable isn't set ๐Ÿ“

Return type str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐ŸŒธ toil.customInitCmd()

this one gives you back the command set in TOIL_CUSTOM_INIT_COMMAND ๐Ÿ’œ

The custom init command runs before the Toil appliance itself in workers and/or the primary node. Basically it goes one stage before TOIL_CUSTOM_DOCKER_INIT_COMMAND, so the order is giving main character energy ๐Ÿ‘‘

Same vibes as the docker one: super handy for custom initialization on instances (like authenticating to private docker registries ๐Ÿซถ). Single quotes are escaped, and the command can't have blacklisted chars (newline or tab) ๐Ÿšซ

Returns The custom command, or an empty string if the environment variable isn't set ๐Ÿง

Return type str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿงš toil.lookupEnvVar(name, envName, defaultValue)

this one is the env var detective ๐Ÿ•ต๏ธโ€โ™€๏ธ it looks up the environment variables that control Toil and logs whatever it finds ๐Ÿ“

Parameters

  • name (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the human readable name of the variable ๐ŸŒท
  • envName (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the name of the environment variable to look up ๐Ÿ”Ž
  • defaultValue (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the fall-back value ๐Ÿ›Ÿ

Returns the value of the environment variable, or the default value if the variable is not set ๐Ÿ’…

Return type str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿณ toil.checkDockerImageExists(appliance)

bestie, this one checks a registry URL for a docker image with a given tag ๐Ÿ‘€

Parameters

  • appliance (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the url of a docker image's registry (with a tag), in one of these shapes: 'quay.io/<repo_path>:<tag>' or '<repo_path>:<tag>' ๐Ÿ’
    • Examples: 'quay.io/ucsc_cgl/toil:latest', 'ubuntu:latest', or 'broadinstitute/genomes-in-the-cloud:2.0.0' โœจ

Returns This one raises an exception if the docker image can't be found or is invalid ๐Ÿ’€ otherwise it returns the appliance string ๐Ÿ’–

Return type str (/usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿ“ toil.parseDockerAppliance(appliance)

this one is the image splitter ๐Ÿ”ช it takes a docker image string and derives the parsed registry, image reference, and tag ๐Ÿงฉ

Example: "quay.io/ucsc_cgl/toil:latest" should return "quay.io", "ucsc_cgl/toil", "latest" ๐ŸŒˆ

Defaults, because we love a backup plan ๐Ÿซถ:

  • If a registry isn't defined, the default is "docker.io" ๐Ÿ‹
  • If a tag isn't defined, the default is "latest" ๐Ÿท๏ธ

Parameters

  • appliance (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the full url of the docker image originally specified by the user (or the default), e.g. "quay.io/ucsc_cgl/toil:latest" ๐ŸŽ€

Returns registryName, imageName, tag ๐Ÿง

Return type tuple[str, str, str] (/usr/share/doc/python3/html/library/stdtypes.html#tuple, /usr/share/doc/python3/html/library/stdtypes.html#str)


๐Ÿฆ„ toil.checkDockerSchema(appliance)

this one is just a bare signature with no description, so there's nothing extra to say here ๐Ÿ™ˆ


๐Ÿšจ exception toil.ApplianceImageNotFound(origAppliance, url, statusCode)

Bases: docker.errors.ImageNotFound

this is the error you get when using TOIL_APPLIANCE_SELF results in an HTTP error ๐Ÿ˜ญ

Parameters

  • origAppliance (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the full url of the docker image originally specified by the user (or the default), e.g. "quay.io/ucsc_cgl/toil:latest" ๐Ÿ“
  • url (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the URL where the image's manifest is supposed to appear ๐Ÿ”—
  • statusCode (int, /usr/share/doc/python3/html/library/functions.html#int) โ€” the failing HTTP status code returned by the URL ๐Ÿ™…โ€โ™€๏ธ

๐ŸŒˆ toil.KNOWN_EXTANT_IMAGES

another bare one with no description, so we're just gonna vibe past it ๐Ÿ’…


๐Ÿ” toil.requestCheckRegularDocker(origAppliance, registryName, imageName, tag)

this one checks if an image exists using the requests library ๐Ÿง 

The URL is based on the docker v2 schema (https://docs.docker.com/registry/spec/manifest-v2-2/) and has this format: https://{websitehostname}.io/v2/{repo}/manifests/{tag} ๐Ÿฆ‹

Heads up, bestie: this does not work with the official docker.io site, because they require an OAuth token. That's why docker.io images get their own separate check ๐Ÿšจ

Parameters

  • origAppliance (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the full url of the docker image originally specified by the user (or the default), e.g. quay.io/ucsc_cgl/toil:latest ๐Ÿ’–
  • registryName (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the url of a docker image's registry, e.g. quay.io ๐ŸŒท
  • imageName (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the image, including path and excluding the tag, e.g. ucsc_cgl/toil ๐Ÿง
  • tag (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the tag used at that docker image's registry, e.g. latest ๐Ÿท๏ธ

Raises ApplianceImageNotFound if no match is found ๐Ÿ˜ญ

Returns Returns True if a match is found โœจ

Return type bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐Ÿ‹ toil.requestCheckDockerIo(origAppliance, imageName, tag)

this one checks docker.io to see if an image exists, also with the requests library ๐Ÿซง

The URL is based on the docker v2 schema, but there's a catch: you have to fetch an access token first ๐Ÿ”‘

Parameters

  • origAppliance (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the full url of the docker image originally specified by the user (or the default), e.g. ubuntu:latest ๐Ÿ’
  • imageName (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the image, including path and excluding the tag, e.g. ubuntu ๐ŸŒธ
  • tag (str, /usr/share/doc/python3/html/library/stdtypes.html#str) โ€” the tag used at that docker image's registry, e.g. latest ๐Ÿ’œ

Raises ApplianceImageNotFound if no match is found ๐Ÿ˜ญ

Returns Returns True if a match is found ๐Ÿฆ„

Return type bool (/usr/share/doc/python3/html/library/functions.html#bool)


๐Ÿ“ toil.logProcessContext(config)

this one logs the process context for a given config ๐Ÿงพ

Parameters

  • config (common.Config, #toil.common.Config) โš™๏ธ

Return type None


[1] Created with sphinx-autoapi https://github.com/readthedocs/sphinx-autoapi ๐Ÿ› ๏ธ

  • Index
  • Search Page

โœจ AUTHOR โœจ

UCSC Computational Genomics Lab ๐ŸŽ“


2015 โ€“ 2026 UCSC Computational Genomics Lab ๐ŸŒˆ


Bestie, that's the whole page ๐Ÿซถ Toil 9.1.2, dropped Jan 08, 2026, and we're officially done. Stay iconic ๐Ÿฆ‹๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from