Argh: Effortless CLI
Argh is a lightweight Python library that simplifies the creation of command-line interfaces (CLIs) by building on top of the `argparse` module. It allows developers to define CLI commands using plain Python functions, reducing boilerplate code and inferring arguments from function signatures and type annotations. The library is actively maintained, with regular releases, and is currently at version 0.31.3.
Warnings
- breaking Argh v0.31.0 automatically enables typing hints introspection for functions without `@arg` decorators. This may change behavior if you previously relied on no introspection for such functions, potentially leading to unexpected argument parsing.
- breaking Argh v0.30.0 introduced a new default policy for mapping function arguments to CLI arguments. Positional arguments with default values now map to positional CLI arguments instead of optional flags (e.g., `def func(foo, bar=None)` maps `bar` as a positional `[bar]` instead of `--bar`).
- gotcha Since v0.30.2, Argh raises `ArgumentNameMappingError` if a non-keyword-only argument has a default value and no explicit name mapping policy is defined. This prevents silent misinterpretation of CLI arguments based on the new policy.
- deprecated The `@expects_obj` decorator and the `add_help_command` argument in `dispatch()` (which enabled the `help` positional command alias) were deprecated in v0.30.0 and subsequently removed in v0.31.0.
- gotcha Earlier versions (prior to v0.31.2) had broken support for type aliases like `typing.List` and `typing.Optional[List]`, leading to incorrect argument parsing for these types.
Install
-
pip install argh
Imports
- dispatch_command
from argh import dispatch_command
- dispatch_commands
from argh import dispatch_commands
- arg
from argh import arg
Quickstart
import argh
import os
def verify_paths(paths: list[str], *, verbose: bool = False):
"""Verify that all given paths exist."""
for path in paths:
if verbose:
print(f"Checking {path}...")
if not os.path.exists(path):
raise FileNotFoundError(f"Path does not exist: {path}")
print("All paths verified successfully.")
if __name__ == "__main__":
# For a single command application, use dispatch_command.
# For multiple commands, use argh.dispatch_commands([cmd1, cmd2]).
# Note: old_name_mapping_policy=False is often recommended during the transition
# for explicit argument mapping, especially with positional arguments having defaults.
argh.dispatch_command(verify_paths, old_name_mapping_policy=False)