Skip to main content

Configuration driven CLI builder with subcommands and script loading

Project description

Sigil

Declarative argparse, without the CLI boilerplate.

Sigil is a lightweight, declarative CLI framework for Python. Define your command tree in YAML (or any other format), and sigil builds the argparse parser on the fly. Complete with subcommands and dynamic script loading.
It plays nicely with argcomplete out of the box.

pypi PyPI Wheel Python 3.10+ License: MIT Downloads Tests Coverage Status


Features

  • Declarative command hierarchies (parents, subparsers, defaults)
  • Each command can point to a dynamically imported Python script
  • argcomplete integration for tab‑completion
  • Pluggable data sources – YAML is the default, but JSON, TOML, or a dict are trivial to swap in
  • No boilerplate argparse code in your main logic

The alternatives

There are plenty of established options out there. Click and Typer are great libraries with their own approaches.

Sigil takes a different path, focusing on reducing boilerplate while keeping your command structure modular and flexible.

Quick Start

Install

pip install sigil-cli

or include argcomplete

pip install sigil-cli[completion]

0. Recommended file structure

project_root/
├── mycli.py              # drop‑in entry script (alias this)
├── manifest.yml          # lists all YAML config files to load
├── yml/                  
│   ├── root.yml          # root command definition
│   ├── root_run.yml      # subcommand definition(s)
│   └── ...               
└── scripts/              
    ├── run.py            # implements the 'run' command
    └── ...               # other scripts

1. Entry script

Create mycli.py:

#!/usr/bin/env python3
from pathlib import Path
from sigil import run_from_config

if __name__ == "__main__":
    run_from_config(Path(__file__).parent)

2. Configuration files

List all your YAML definitions in manifest.yml:

- root.yml
- root_run.yml

Define the root command in root.yml:

root:
  name: mycli
  script_dir: scripts

Define a subcommand in root_run.yml:

root_run:
  name: run
  parent: root
  help: command utility to run containers
  script: run
  args:
    - help: port to run, autoincrements from 8080
      name:
        - -p
        - --port

3. Write the script

Create scripts/run.py:

import argparse
from typing import Any

def run(args: argparse.Namespace, ctx: dict[str, Any]) -> None:
    port = getattr(args, "port", 8080)
    port = find_next_free_port_logic(port)
    print(f"Running container on port {port}")

4. Run it

chmod +x mycli.py
./mycli.py run --port 9000
# Running container on port 9000

./mycli.py run
# Running container on port 8080

./mycli.py run
# Running container on port 8081

Configuration Reference

Root

Field Description
name Program name (used as prog in argparse)
script_dir Directory (relative to the config root) where command scripts are located

Command

Field Description
name Subcommand name
parent Parent command (must exist elsewhere in a config)
help Help text for this subcommand
script Python module name (without .py) inside script_dir or as absolute path
args List of argument definitions (see below)
default If true, this subcommand is used when no subcommand is given
any other parser kwarg except for dest and formatter_class they are all supported

Note that parent does not refer to argparse's parent parameter but is only used to resolve the parser tree. Parser (multi-)inheritance isn't supported but can be emulated by adding arguments to this command's parents in the tree.

Argument

Each argument entry can be a plain dict which maps 1-to-1 with argparse add_argument, except name which maps it's *args

- name: ["-p", "--port"]   # or a single string, e.g. "positional"
  required: false
  default: 8069
  help: "port number"

Groups and mutex groups are also suppored via the "kind" parameter (defaults to argument)

# mutex group
- kind: mutex
  args:
    - <any recursive args/group/mutex construct here>
    ...
  ... # any valid mutex group arguments go here

- kind: group
  ...  # same

The name field can be --flag for flags or a string for positional arguments. Both literal string and list of strings are supported.

Tab‑Completion (argcomplete)

Sigil registers itself with argcomplete automatically if available on your system.
To enable completion, install argcomplete and activate it for your entry script:

pip install argcomplete
activate-global-python-argcomplete

Then run your script and hit Tab – subcommands and flags will complete.

Pluggable Backends

Sigil uses yaml by default, but you can supply any loader that returns a dict[str, ParserConfig]:

from sigil import run_from_config

# Use JSON instead:
class JsonReader:
    @classmethod
    def load(cls, config_root):
        # read *.json, parse, convert to dict of ParserConfig
        ...

run_from_config("/path/to/config", loader_class=JsonReader)

You can also pass a pre‑loaded dictionary directly by wrapping it:

run_from_config(my_dict, loader_class=DictLoader)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sigil_cli-1.1.0.tar.gz (18.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sigil_cli-1.1.0-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file sigil_cli-1.1.0.tar.gz.

File metadata

  • Download URL: sigil_cli-1.1.0.tar.gz
  • Upload date:
  • Size: 18.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for sigil_cli-1.1.0.tar.gz
Algorithm Hash digest
SHA256 04b2e746616f6168a73f4af7e5a47659328f413af37db38360257321033970a3
MD5 a058f4b615b2b76278ace883047c152b
BLAKE2b-256 6b358e58e798a72d9df0472691b106eb2b4e2a977f1213f30877e0bb31bc496e

See more details on using hashes here.

Provenance

The following attestation bundles were made for sigil_cli-1.1.0.tar.gz:

Publisher: publish.yml on kenzo-staelens/sigil

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sigil_cli-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: sigil_cli-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for sigil_cli-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 28aa539f74ec62330fe00bb06e07928ba8320e823d40783a21e3e8e0cc173f9c
MD5 b77dba272588bf776c0fb8b860993d59
BLAKE2b-256 2986c5ddf0763a57af485a1427de9dd5f12adddfe31304c89ec9b21abab60cc8

See more details on using hashes here.

Provenance

The following attestation bundles were made for sigil_cli-1.1.0-py3-none-any.whl:

Publisher: publish.yml on kenzo-staelens/sigil

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page