Skip to main content

A simple task runner that generates command line interfaces

from cleek import task


@task
def binary_op(x: int, y: int, op: Literal['add', 'sub'] = 'add') -> None: ...

⬇️ Becomes ⬇️

$ clk binary-op -h
usage: clk binary-op [-h] [-o {add,sub}] x y

positional arguments:
  x
  y

options:
  -h, --help          show this help message and exit
  -o, --op {add,sub}  default: add

See how I cleek in another project

Install

PyPI

pip install cleek

GitHub

git clone https://github.com/petersuttondev/cleek.git
pip install ./cleek

Get Started

  1. Create a cleeks.py file in the root of your project and add tasks.
from cleek import task


@task
def greet(name: str) -> None:
    print(f'Hello, {name}!')
  1. Run clk from anywhere inside your project to see your tasks.
$ clk
┏━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
┃ Task  ┃ Usage               ┃
┡━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
│ greet │ clk greet [-h] name │
└───────┴─────────────────────┘
  1. Run clk <task> -h to print a task's help.
$ clk greet
usage: clk greet [-h] name

positional arguments:
  name

options:
  -h, --help  show this help message and exit
  1. Run a task.
$ clk greet Peter
Hello, Peter!

Customizing Tasks

Set a task's name:

from cleek import task


@task('bar')
def foo() -> None:
    print('foo function, bar task')
$ clk bar
foo function, bar task

Set a task's group:

from cleek import task


@task(group='foo')
def bar() -> None:
    print('bar task in the foo group')
$ clk foo.bar
bar task in the foo group

Set a task's style. Used when listing tasks. See Rich's Style documentation for supported styles.

from cleek import task


@task(style='red')
def foo() -> None:
    print("I'll be red if you run clk")

To apply the same customization to many tasks, use customize() to create a pre-configured version of the task decorator.

from cleek import customize

foo_task = customize('foo', style='red')


@foo_task
def a() -> None: ...


@foo_task
def b() -> None: ...


bar_task = customize('bar', style='blue')


@bar_task
def c() -> None: ...


@bar_task
def d() -> None: ...
$ clk
┏━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Task  ┃ Usage          ┃
┡━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ foo.a │ clk foo.a [-h] │
│ foo.b │ clk foo.b [-h] │
│ bar.c │ clk bar.c [-h] │
│ bar.d │ clk bar.d [-h] │
└───────┴────────────────┘

Configuration

Sometimes it's useful to the directory your cleeks live in to be on the Python path. For example, if your tasks use multiprocessing. cleek can do that for you:

from cleek import config, task

config(prepend_to_path=True)


@task
def foo() -> None: ...

Shell Completion

Shell completion is provided by argcomplete:

  1. Setup argcomplete following their installation instructions

  2. Add eval "$(register-python-argcomplete clk)" to your shell configuration.

Async Support

Your tasks can be async functions:

from cleek import task
import trio


@task
async def sleep(duration: float = 1.0) -> None:
    print(f'Sleeping for {duration} seconds')
    await trio.sleep(duration)

Cleek runs async tasks with anyio. Select the backend with @task(backend='asyncio') or @task(backend='trio'), or for a set of tasks with customize(backend=...). trio is the default backend.

Finding Tasks

  1. If the environmental variable CLEEKS_PATH is set, clk treats the value as a path and attempts to load it. If the load fails, clk fails.

  2. clk searches upwards from the current working directory towards the root directory /, looking for a cleeks.py script or a cleeks package. A script takes precedence over a package if both are found in the same directory.

Supported Parameters

If you get an error saying your task's parameters are not supported, open an issue containing the function signature and I'll add support.

bool

Keyword bool with False or True default

def foo(a: bool = False): ...
def foo(a: bool = True): ...

Keyword optional bool with False, True, or None default

def foo(a: bool | None = False): ...
def foo(a: bool | None = True): ...
def foo(a: bool | None = None): ...

str

Positional str

def foo(a: str): ...

Positional optional str

def foo(a: str | None): ...

Keyword str with str default

def foo(a: str = 'a'): ...

Keyword optional str with str or None default

def foo(a: str | None = 'a'): ...
def foo(a: str | None = None): ...

Variadic positional str

def foo(*a: str): ...

int

Positional int

def foo(a: int): ...

Keyword int with int default

def foo(a: int = 1): ...

Poitisonal optinal int

def foo(a: int | None): ...

Keyword optional int with int or None default

def foo(a: int | None = 1): ...
def foo(a: int | None = None): ...

float

Positional float

def foo(a: float): ...

Keyword float with float default

def foo(a: float = 1.0): ...

Keyword optional float with float or None default

def foo(a: float | None = 1.0): ...
def foo(a: float | None = None): ...

Literal[T]

Positional int literal

@task
def foo(a: Literal[1, 2, 3]): ...

Positional str literal

@task
def foo(a: Literal['a', 'b', 'c']): ...

Positional only str literal

@task
def foo(a: Literal['a', 'b', 'c'], /): ...

Positional only str literal with str default

@task
def foo(a: Literal['a', 'b', 'c'] = 'a', /): ...

Keyword int literal with int default

@task
def foo(a: Literal[1, 2, 3] = 1): ...

Keyword str literal with str default

@task
def foo(a: Literal['a', 'b', 'c'] = 'a'): ...

Misc

Positional pathlib.Path or pathlib.PurePosixPath

from pathlib import Path, PurePosixPath


@task
def foo(a: Path): ...


@task
def bar(b: PurePosixPath): ...

Keyword optional pathlib.Path or pathlib.PurePosixPath with None default

from pathlib import Path


@task
def foo(a: Path | None = None): ...


@task
def bar(a: PurePosixPath | None = None): ...

Variadic positional pathlib.Path

from pathlib import Path


@task
def foo(*a: Path): ...

Variadic positional trio.Path

from trio import Path


@task
def foo(*a: Path): ...

Metadata

Release files for cleek 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cleek 1.1.0
File Size Uploaded Provenance Actions
cleek-1.1.0.tar.gz 101.7 kB Without provenance Details for cleek-1.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cleek 1.1.0
File Interpreter ABI Platform Actions
cleek-1.1.0-py3-none-any.whl Python 3 none any Details for cleek-1.1.0-py3-none-any.whl

Total release size: 113.0 kB

Release files / cleek-1.1.0.tar.gz

Download URL cleek-1.1.0.tar.gz
Size 101.7 kB
Tags Source
SHA-256 checksum
How to use checksums
35e96d86a7f43eaf651c5017187c622ca370c4cdf18fcbc937c1db5d26efd5bd
BLAKE2b-256 checksum
How to use checksums
a9ea57bfedb040a9da560d4e62466912291be2e8f19947e729ab59cfcd9d4d6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Release files / cleek-1.1.0-py3-none-any.whl

Download URL cleek-1.1.0-py3-none-any.whl
Size 11.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c1cf80cdb47938ae6e9c5e9d2e93b5be49f3b14c05e84cdf30989e836a570bf4
BLAKE2b-256 checksum
How to use checksums
53bb0b17aaccfadd15912d40aa94c29941c44423dcdebb428f0667564c93745f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Security for cleek 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page