cliss — A lightweight framework for building CLI applications on top of argparse
Project description
cliss — A lightweight framework for building CLI applications on top of argparse
Write type-annotated Python functions, get a full CLI — automatic --help, validation, and async support with zero dependencies.
✨ Features
- 🪶 Zero Dependencies — Pure stdlib:
argparse,asyncio,inspect - 🏷️ Type-Driven — Automatic arguments from function signatures and type hints
- 🧩 Flexible — Declarative
Argumentobjects, type inference, or both - ⚡ Async-Native —
async defhandlers with automatic event loop management - 🌍 Global Args — Define flags shared across all commands
- 🔧 argparse Access — Full access to underlying parsers for advanced use
🚀 Quick Start
Prerequisites
- Python 3.9+
Installation
pip install cliss
Via uv
uv pip install cliss
Via pipx (isolated environment)
pipx install cliss
From source (development)
git clone https://github.com/yourusername/cliss.git && cd cliss
pip
pip install .
uv
uv pip install .
pipx
pipx install .
Usage
from cliss import CLI
cli = CLI(name="todo", description="Task manager", version="1.0.0")
@cli.command()
def add(task: str, priority: int = 1, done: bool = False):
"""Add a new task."""
status = "✓" if done else "○"
return f"[{status}] {task} (priority: {priority})"
if __name__ == "__main__":
cli.handle()
$ python todo.py add "Buy milk" --priority 2
[○] Buy milk (priority: 2)
$ python todo.py add "Call mom" --done --priority 3
[✓] Call mom (priority: 3)
📋 Commands
CLI class
CLI(name="myapp", description="...", version="1.0.0", auto_help=True)
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
— | Program name in help output |
description |
str |
— | Description in help output |
version |
str |
— | Adds --version flag |
auto_help |
bool |
True |
Adds --help flag |
Argument class
Argument("--output", "-o", type=str, default=None, help="...", required=False, choices=["a","b"], action="store_true")
| Parameter | Type | Default | Description |
|---|---|---|---|
*flags |
str |
— | Argument flags (e.g., --output, -o) |
type |
type |
str |
Value type for coercion |
default |
Any |
None |
Default value |
help |
str |
"" |
Help text |
required |
bool |
False |
Make argument required |
choices |
list |
— | Restrict allowed values |
action |
str |
— | argparse action (store_true, etc.) |
Type → CLI Mapping
| Function Signature | CLI Argument |
|---|---|
name: str |
Positional name |
count: int = 1 |
--count with type int, default 1 |
verbose: bool = False |
--verbose flag (store_true) |
quiet: bool = True |
--quiet flag (store_false) |
📖 Examples
CRUD Application
from cliss import CLI
cli = CLI(name="db", description="Key-value store")
db = {}
@cli.command()
def set(key: str, value: str):
"""Store a value."""
db[key] = value
return f"OK: {key} = {value}"
@cli.command()
def get(key: str):
"""Retrieve a value."""
return db.get(key, "Not found")
@cli.command()
def delete(key: str, force: bool = False):
"""Delete a key."""
if force or key in db:
db.pop(key, None)
return f"Deleted: {key}"
return f"Not found: {key} (use --force)"
cli.handle()
Explicit Arguments
from cliss import CLI, Argument
cli = CLI(name="convert")
@cli.command(arguments=[
Argument("input", help="Input file"),
Argument("--output", "-o", default="out.txt"),
Argument("--format", "-f", choices=["json", "csv"], default="json")
])
def convert(input: str, output: str = "out.txt", format: str = "json"):
"""Convert file format."""
return f"{input} -> {output} [{format}]"
Async Handler
@cli.command()
async def fetch(url: str, retries: int = 3):
"""Fetch data asynchronously."""
return f"Fetched {url} (retries: {retries})"
Global Arguments
cli = CLI(name="myapp")
cli.add_global_argument("--verbose", "-v", action="store_true")
@cli.command()
def status(verbose: bool = False):
return "Detailed status..." if verbose else "OK"
$ myapp --verbose status
Detailed status...
📁 Project Structure
cliss/
├── cliss/
│ └── __init__.py # CLI, Argument classes
├── pyproject.toml # Project metadata
├── README.md # Documentation
└── LICENSE # MIT License
🔧 Requirements
| Dependency | Purpose |
|---|---|
| Python 3.9+ | Type hints, inspect.signature |
No external dependencies — stdlib only.
❓ FAQ
Why cliss when argparse already works?
argparse is powerful but verbose. A simple app with 3 commands can easily require 100+ lines of parser setup. cliss reduces this to type-annotated functions — the boilerplate is inferred, not written.
What about Click/Typer/Fire?
| Tool | Dependencies | Style |
|---|---|---|
| cliss | 0 (stdlib) | Decorators + type hints |
| Click | Click | Decorators |
| Typer | Click, typing-extensions | Type hints |
| Fire | 0 (stdlib) | Introspection |
cliss sits between Fire (zero-config, no validation) and Typer (rich features, heavy deps). It gives you type-driven CLI generation with argparse-compatible control, all in ~200 lines.
Can I use argparse features directly?
Yes. cli.parser and cli.subparsers are standard argparse objects. Add custom actions, mutually exclusive groups, or parent parsers as needed.
Does it support nested commands?
For subcommand groups, access cli.subparsers directly or use dotted command names:
@cli.command(name="compute:start")
def start(instance: str):
return f"Starting {instance}"
How does async work?
If the command handler is async def or returns a coroutine, cliss automatically runs it with asyncio.run(). No manual event loop setup needed.
🐛 Troubleshooting
| Issue | Solution |
|---|---|
| Arguments not appearing | Check that explicit Argument objects' dest matches parameter names |
| Bool flag inverted | bool = False → store_true, bool = True → store_false |
| Type coercion fails | argparse error message shown automatically |
| Subcommand not found | Verify command name: func.__name__ with _ → - unless overridden |
📄 License
MIT License — see LICENSE file.
🙏 Acknowledgments
- argparse — The foundation this is built on
Repository: github.com/Fkernel653/cliss PyPI: pypi.org/project/cliss
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cliss-0.1.0.tar.gz.
File metadata
- Download URL: cliss-0.1.0.tar.gz
- Upload date:
- Size: 7.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9691a8471acdd075b2fbcbe36ab398215c2096537149498976f35e829a870d64
|
|
| MD5 |
c5dd718145a2f4751d56b75890cdf41b
|
|
| BLAKE2b-256 |
d7041bcc335d1f298159692c74a35a096793f950d63ffb9749a9197cac5a5043
|
File details
Details for the file cliss-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cliss-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0172f5aafa7f41532bd2b0d89cbe0693a110f40d51fdda752b90c669207c807c
|
|
| MD5 |
2bfd0df0255b02987091520bdff6c2f4
|
|
| BLAKE2b-256 |
14fbca7151b4b351ed6536ed21b9a1fb64ec9bcd019c09a457f702163f1ed522
|