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
- Create a
cleeks.pyfile in the root of your project and add tasks.
from cleek import task
@task
def greet(name: str) -> None:
print(f'Hello, {name}!')
- Run
clkfrom anywhere inside your project to see your tasks.
$ clk
┏━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
┃ Task ┃ Usage ┃
┡━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
│ greet │ clk greet [-h] name │
└───────┴─────────────────────┘
- Run
clk <task> -hto print a task's help.
$ clk greet
usage: clk greet [-h] name
positional arguments:
name
options:
-h, --help show this help message and exit
- 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:
-
Setup
argcompletefollowing their installation instructions -
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 unless the
environment variable CLEEK_BACKEND is set to asyncio or trio
(case-sensitive). @task(backend=...) takes precedence over
customize(backend=...), which takes precedence over CLEEK_BACKEND.
Finding Tasks
-
If the environmental variable
CLEEKS_PATHis set,clktreats the value as a path and attempts to load it. If the load fails,clkfails. -
clksearches upwards from the current working directory towards the root directory/, looking for acleeks.pyscript or acleekspackage. 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.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cleek-1.2.0.tar.gz | 102.2 kB | Without provenance | Details for cleek-1.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cleek-1.2.0-py3-none-any.whl | Python 3 | none | any | Details for cleek-1.2.0-py3-none-any.whl |
Total release size: 113.7 kB
Release files / cleek-1.2.0.tar.gz
| Download URL | cleek-1.2.0.tar.gz |
|---|---|
| Size | 102.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c14f97c7a49600772960b4cb87eb2192955e0d219a41504107e3515f9d8815d2
|
|
BLAKE2b-256 checksum How to use checksums |
9d691e791e3d8016e611cd029942a113c9b0e5d916be98cc80f35a1b69b115a4
|
| 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.2.0-py3-none-any.whl
| Download URL | cleek-1.2.0-py3-none-any.whl |
|---|---|
| Size | 11.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0b6de476c9427a6330bb7c09285a4f65b3c0f619c74b9e1791b3414e7eb538ae
|
|
BLAKE2b-256 checksum How to use checksums |
d815fabc7e36f675f4221935fbbf0e67e47a2adaf9baef1352f62adeed87a044
|
| 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.2.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.