Class-based command-line argument parsing for Python that combines the power of argparse with class definitions and
type annotations.
- Type-safe arguments - Automatically infer type conversion from Python type annotations
- Clean syntax - Define arguments as class attributes with straightforward decorators
- Composable - Easily reuse and extend argument definitions through inheritance
- Validation - Built-in validation system with chainable API
- Subcommands - Support for command hierarchies with minimal boilerplate
- Organized help - Group arguments into logical sections for better documentation
pip install argclzfrom argclz import *
class MyArgs(AbstractParser):
verbose: bool = argument('--verbose', help='Enable verbose output')
name: str = argument('-n', '--name', required=True, help='Name of the user')
count: int = argument('--count', default=1, help='Number of times to greet')
def run(self):
for _ in range(self.count):
if self.verbose:
print(f"Greeting with enthusiasm: Hello, {self.name}!")
else:
print(f"Hello, {self.name}!")
if __name__ == '__main__':
MyArgs().main()Show help:
python my_script.py -hExpected output:
usage: my_script.py [-h] [--verbose] -n NAME [--count COUNT]
options:
-h, --help show this help message and exit
--verbose Enable verbose output
-n NAME, --name NAME Name of the user
--count COUNT Number of times to greet
Run with:
python my_script.py --name Alice --count 3 --verbose# Regular argument
name: str = argument('-n', '--name', help='Name of the user')
# Boolean flag
verbose: bool = argument('--verbose', help='Enable verbose output')
# Positional argument
filename: str = pos_argument('FILENAME', help='Input file to process')
# Variable-length argument
items: list[str] = var_argument('ITEMS', help='Items to process')# Comma-separated values to a tuple of floats
coords: tuple[float, ...] = argument('--coords', type=float_tuple_type)
# Value range (min:max)
ranging: tuple[int, int] = argument('--range', type=int_tuple_type)# Grouped arguments
verbose: bool = argument('--verbose', group='general')
output_dir: str = argument('--output', group='output')
# Mutually exclusive arguments
output_json: bool = argument('--json', ex_group='output')
output_yaml: bool = argument('--yaml', ex_group='output')# Range validator
age: int = argument('--age', validator.int.in_range(18, 99))
# Path validator
path: Path = argument('--path', validator.path.is_dir().is_exists())class InitCmd(AbstractParser):
name: str = argument('--name', required=True)
def run(self):
print(f"Initializing project: {self.name}")
class BuildCmd(AbstractParser):
release: bool = argument('--release')
def run(self):
print("Building in release mode" if self.release else "Building in debug mode")
# Entry point
from argclz.commands import parse_command_args
if __name__ == '__main__':
parse_command_args({
'init': InitCmd,
'build': BuildCmd
})class IOOptions:
input_path: str = argument('--input', help='Input file')
output_path: str = argument('--output', help='Output file')
class LoggingOptions:
verbose: bool = argument('--verbose', help='Enable verbose logging')
class MyOptions(IOOptions, LoggingOptions):
# Override an inherited argument
input_path = as_argument(IOOptions.input_path).with_options(required=True)