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.1.tar.gz (18.6 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.1-py3-none-any.whl (15.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: sigil_cli-1.1.1.tar.gz
  • Upload date:
  • Size: 18.6 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.1.tar.gz
Algorithm Hash digest
SHA256 0dbd0a8fc692171b061b8cabaf3c4dde6511cce9bbed7bb274f8100745be3d1e
MD5 ea993157e2a4e8196edc0b8608e1ccd3
BLAKE2b-256 d9f0a975b96a8d7bb665af6cdb042ee2fab8b445a89ffc8c66f196f85fe447eb

See more details on using hashes here.

Provenance

The following attestation bundles were made for sigil_cli-1.1.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: sigil_cli-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 15.2 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5a5e8ba4c27a71a12b84c75b5f57ea9d1cc6a444aceb17e5ad686cfc43c4ebbb
MD5 e63474d803d907efc0d69e564473fad0
BLAKE2b-256 97c9333ec795d1d0a0ba6c102299c3a936d4d1605a9f79afc89d02047d88c1f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for sigil_cli-1.1.1-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