Skip to content

tsk.monster

A cute little tsk runner.

Quick Start

Install:

poetry add tsk-monster

Write a tskfile.py:

tskfile.py
from tsk_monster import tsk


def download_image():
    yield tsk(
        'wget -O large.jpg https://picsum.photos/200/300',
        prods=['large.jpg'])

    yield tsk(
        'convert -resize 100x large.jpg small.jpg',
        needs=['large.jpg'],
        prods=['small.jpg'])

Run:

tsk download_image

Parallel Execution

tsk.monster executes independent tasks in parallel and utilizes all available CPU cores on the machine. Here is an example:

tskfile.py
from tsk_monster import tsk


def download_images():
    for i in range(10):
        large = f'large_{i:02}.jpg'
        small = f'small_{i:02}.jpg'

        yield tsk(
            f'wget -O {large} https://picsum.photos/200/300',
            prods=[large])

        yield tsk(
            f'convert -resize 100x {large} {small}',
            needs=[large],
            prods=[small])

Prevent Unnecessary Work

There are three situations in which a task is executed:

  1. If any of the prods files are missing.
  2. If any of the needs files were updated since the last run.
  3. If the updts list is not empty.

In all other situations, the task is considered up to date and is skipped.

In the following example, the first task will be executed only if the file lazy.txt is missing. The second task will always be executed (if yielded), and the third task will be executed only if lazy.txt was updated (touched) since the last run.

tskfile.py
from random import random

from tsk_monster import tsk


def lazy():
    yield tsk(
        'touch lazy.txt',
        prods=['lazy.txt'])

    if random() < 0.5:
        yield tsk(
            'touch lazy.txt',
            updts=['lazy.txt'])

    yield tsk(
        'echo lazy.txt was updated',
        needs=['lazy.txt'])

Dynamic Execution

tskfile.py
from functools import partial
from pathlib import Path

from PIL import Image

from tsk_monster import exist, tsk


def thumbnails():
    def thumbnail(in_path: Path, out_path: Path):
        img = Image.open(in_path)
        img.thumbnail((100, 100))
        img.save(out_path)

    for in_path in Path('imgs').glob('*.jpg'):
        out_path = Path('thumbs') / in_path.name

        # Tells tsk.monster that this file exists
        yield exist(in_path)

        yield tsk(
            partial(thumbnail, in_path, out_path),
            needs=[in_path],
            prods=[out_path])