A decorator-based, declarative interface to Python's argparse for building hierarchical CLI applications.
Project description
argdec
A decorator-based, declarative interface to Python's argparse for building hierarchical CLI applications.
Overview
argdec (formerly argdeclare) provides two complementary approaches to configuring argparse:
-
Decorator-based configuration - Use
@optionand@option_groupdecorators to attach argparse arguments directly to command methods, keeping argument definitions co-located with the code that uses them. -
Declarative class structure - Define CLI applications as classes where methods become commands, docstrings become help text, and class attributes configure parser behavior.
This combination eliminates boilerplate while preserving full access to argparse's capabilities.
Features
-
Decorator-driven options - Configure argparse arguments with
@optionand@option_groupdecorators directly on methods -
Declarative command structure - Methods prefixed with
do_automatically become subcommands -
Hierarchical commands - Build nested command structures (e.g.,
git remote add) using underscore-separated method names -
Reusable option groups - Define common options once, apply to multiple commands with
@option_group -
Full argparse compatibility - All argparse features available through decorator parameters
-
Customizable - Configure command prefix, hierarchy levels, and more
-
Production ready - Comprehensive test suite, type hints, error handling
Installation
pip install argdec
Or install from source:
git clone https://github.com/shakfu/argdec.git
cd argdec
pip install .
Quick Start
from argdec import Commander, option
class MyApp(Commander):
"""My awesome CLI application."""
name = 'myapp'
version = '1.0'
@option("-v", "--verbose", action="store_true", help="verbose output")
def do_build(self, args):
"""Build the project."""
print(f"Building... (verbose={args.verbose})")
if __name__ == '__main__':
app = MyApp()
app.cmdline()
$ python myapp.py build --verbose
Building... (verbose=True)
Declarative Format Example
#!/usr/bin/env python3
from argdec import Commander, option, option_group
# ----------------------------------------------------------------------------
# Commandline interface
common_options = option_group(
option("--dump", action="store_true", help="dump project and product vars"),
option("-d","--download",
action="store_true",
help="download python build/downloads"),
option("-r", "--reset", action="store_true", help="reset python build"),
option("-i","--install",
action="store_true",
help="install python to build/lib"),
option("-b","--build",
action="store_true",
help="build python in build/src"),
option("-c","--clean",
action="store_true",
help="clean python in build/src"),
option("-z", "--ziplib", action="store_true", help="zip python library"),
option("-p", "--py-version", type=str,
help="set required python version to download and build"),
)
class Application(Commander):
"""builder: builds the py-js max external and python from source."""
name = 'builder'
epilog = ''
version = '0.1'
default_args = ['--help']
_argparse_levels = 1
# ----------------------------------------------------------------------------
# python builder methods
# def do_python(self, args):
# "download and build python from src"
@common_options
def do_python_static(self, args):
"""build static python"""
print(args)
@common_options
def do_python_shared(self, args):
"""build shared python"""
print(args)
@common_options
def do_python_shared_pkg(self, args):
"""build shared python to embed in package"""
print(args)
@common_options
def do_python_framework(self, args):
"""build framework python"""
print(args)
@common_options
def do_python_framework_pkg(self, args):
"""build framework python to embed in a package"""
print(args)
# ----------------------------------------------------------------------------
# utility methods
# def do_check(self, args):
# """check reference utilities"""
# print(args)
@common_options
def do_check_log_day(self, args):
"""analyze log day"""
print(args)
@common_options
def do_check_log_week(self, args):
"""analyze log week"""
print(args)
@common_options
def do_check_sys_month(self, args):
"""analyze sys month"""
print(args)
@common_options
def do_check_sys_def(self, args):
"""analyze sys def"""
print(args)
@common_options
def do_check_sys_xyz(self, args):
"""analyze sys xyz"""
print(args)
@common_options
def do_test(self, args):
"""test suite"""
print(args)
@common_options
def do_test_app(self, args):
"""test app"""
print(args)
@common_options
def do_test_functions(self, args):
"""test functions"""
print(args)
if __name__ == '__main__':
app = Application()
app.cmdline()
with levels=0 gives:
$ python3 demo.py
usage: demo.py [-h] [-v] ...
builder: builds the py-js max external and python from source.
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
subcommands:
valid subcommands
additional help
check_log_day analyze log day
check_log_week analyze log week
check_sys_def analyze sys def
check_sys_month analyze sys month
check_sys_xyz analyze sys xyz
python_framework build framework python
python_framework_pkg
build framework python to embed in a package
python_shared build shared python
python_shared_pkg build shared python to embed in package
python_static build static python
test test suite
test_app test app
test_functions test functions
with levels=1 gives:
$ python3 demo.py
usage: demo.py [-h] [-v] ...
builder: builds the py-js max external and python from source.
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
subcommands:
valid subcommands
additional help
check check commands
python python commands
test test suite
Advanced Features
Custom Command Prefix
By default, methods starting with do_ become commands. You can customize this:
class MyApp(Commander):
_command_prefix = "cmd_" # Use 'cmd_' instead of 'do_'
def cmd_build(self, args):
"""Build the project."""
pass
def cmd_deploy(self, args):
"""Deploy the project."""
pass
See examples/custom_prefix.py for more examples.
Error Handling
Version 0.2.0+ includes comprehensive error handling:
from argdec import ArgDecError, CommandExecutionError
try:
app.cmdline()
except CommandExecutionError as e:
print(f"Command failed: {e}")
except ArgDecError as e:
print(f"Configuration error: {e}")
Examples
Can be found in the examples directory:
basic.py- Basic example applicationhierarchical.py- Full-featured example applicationcustom_prefix.py- Custom prefix demonstrations
Development
Running Tests
make test # Run test suite (38 tests)
make coverage # Run with coverage report
make lint # Run ruff linter
make typecheck # Run mypy type checker
make all # Run all checks
Requirements
- Python 3.7+
- No external dependencies (uses stdlib only)
- Development: pytest, ruff, mypy (optional)
Version History
See CHANGELOG.md for detailed version history.
License
MIT License - See LICENSE file for details.
Credits
Based on the original argdeclare recipe from ActiveState.
Contributing
Contributions welcome! Please:
- Run tests:
make test - Check types:
make typecheck - Lint code:
make lint - Add tests for new features
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 argdec-0.2.2.tar.gz.
File metadata
- Download URL: argdec-0.2.2.tar.gz
- Upload date:
- Size: 20.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa9cbf5e9f392fceeb850fd4b1555da1c3e7fe899fa5be4c8d57e358a851655d
|
|
| MD5 |
e5e7de140c3a7745b10402fa7993948f
|
|
| BLAKE2b-256 |
ad560cf36fee0a9b0897f6fd17a67831f29f107b8fd709e96ac02fd6244dd7e4
|
File details
Details for the file argdec-0.2.2-py3-none-any.whl.
File metadata
- Download URL: argdec-0.2.2-py3-none-any.whl
- Upload date:
- Size: 20.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f50c5ef52fbe439b7af221b5cf9bc50b419d9e847dbb8442b4ca1e3944eef3e7
|
|
| MD5 |
b72ef240cdebbcffe9a0cfbacf0d7bc8
|
|
| BLAKE2b-256 |
9a607b357bae60740ea4eac32f3e05deb12313861f075aeee7ba8c455980909d
|