CLI integration¶
Generate command-line interfaces for your config classes
automatically, saving you from writing custom argument parsing code.
cfx generates argparse and Click CLI options directly from your config
classes. Every non-static field becomes a flag; nested sub-configs use
dot-notation (--worker.threads). A config file can be supplied as a
positional argument (argparse) or --config-file option (Click); CLI
flags override file values.
The examples below use the three-level hierarchy from the front page:
from cfx import Config, Float, Int, String, Bool
class FormatConfig(Config):
"""Output formatting."""
confid = "format"
precision = Int(6, "Decimal places")
encoding = String("utf-8", "Output encoding")
class WorkerConfig(Config, components=[FormatConfig]):
"""Worker settings."""
confid = "worker"
threads = Int(4, "Worker threads", minval=1)
timeout = Float(30.0, "Request timeout in seconds", minval=0.0)
class AppConfig(Config, components=[WorkerConfig]):
"""Application configuration."""
confid = "app"
name = String("myapp", "Application name")
debug = Bool(False, "Enable debug output")
argparse¶
Call add_arguments() on a parser, then
from_argparse() on the parsed result:
import argparse
parser = argparse.ArgumentParser()
AppConfig.add_arguments(parser)
args = parser.parse_args()
cfg = AppConfig.from_argparse(args)
The flags registered for AppConfig are:
positional:
config_file Optional YAML config file.
CLI flags override file values.
options:
--name NAME Application name
--debug, --no-debug Enable debug output
--worker.threads WORKER.THREADS Worker threads
--worker.timeout WORKER.TIMEOUT Request timeout in seconds
--worker.format.precision WORKER.FORMAT.PRECISION Decimal places
--worker.format.encoding WORKER.FORMAT.ENCODING Output encoding
Rules:
Underscore -> hyphen in the flag name (
run_id->--run-id).Bool fields use
argparse.BooleanOptionalAction:--debugsetsTrue,--no-debugsetsFalse.Nested sub-configs are prefixed by their
confidwith dot notation. Deeper nesting extends the prefix (--worker.format.precision).config_file is a positional argument registered once at the top level; it is not repeated for nested sub-configs.
The complete Python attribute path maps to the flag name like this:
Python path |
Flag |
|---|---|
|
|
|
|
|
|
Pass a config file to load base values, then override with flags:
cfg = AppConfig.from_argparse(
parser.parse_args(["app.yaml", "--worker.threads", "8"])
)
# cfg.worker.threads == 8; everything else loaded from app.yaml
Flags that are omitted resolve to None and leave the loaded or default
value unchanged — they do not reset fields to their class defaults.
Note
Only .yaml and .yml extensions are supported. Passing a file
with any other extension will fail at parse time.
When you need to merge several configs into a single shared parser, pass
prefix= explicitly:
parser = argparse.ArgumentParser()
ProcessingConfig.add_arguments(parser, prefix="proc")
FormatConfig.add_arguments(parser, prefix="fmt")
# registers: --proc.iterations, --fmt.precision, ...
Click¶
Stack click_options() on a @click.command() and call
from_click() with the command’s **kwargs:
import click
@click.command()
@AppConfig.click_options()
def run(**kwargs):
cfg = AppConfig.from_click(kwargs)
...
if __name__ == "__main__":
run()
The generated options mirror the argparse flags with two differences:
A
--config-fileoption is added at the top level instead of a positional argument.Bool fields use click’s
--flag/--no-flagsyntax rather thanBooleanOptionalAction.
$ python run.py --help
Usage: run.py [OPTIONS]
Options:
--config-file TEXT Optional YAML config file.
--name TEXT Application name
--debug / --no-debug Enable debug output
--worker.threads INTEGER Worker threads
--worker.timeout FLOAT Request timeout in seconds
--worker.format.precision INTEGER Decimal places
--worker.format.encoding TEXT Output encoding
--help Show this message and exit.
Click is an optional dependency:
pip install "cfx[click]"