Development Status
- 4 - Beta
Intended Audience
- Developers
Programming Language
- Python :: 3.10
- Python :: 3.11
- Python :: 3.12
- Python :: 3.13
- Python :: 3.14
Topic
- Software Development :: Libraries :: Python Modules
- Utilities
Typing
- Typed
Kitware’s keyword configuration module: kwconf defines small configuration objects that work from Python kwargs, command line arguments, environment variables, and JSON/YAML files. It is the successor to scriptconfig, with the same small-script ergonomics and a clearer parser model.
Read the Docs |
|
Github |
|
Pypi |
Features
Define config once, then read it from kwargs, argv, env, or files.
Use the object like a dataclass, dict, or argparse namespace.
Start with plain defaults. Add Value for help text, aliases, choices, flags, positions, nargs, default factories, or a custom parser.
Coerce only string-only sources: sys.argv tokens and os.environ values. Python values are used as Python values.
Use the default parsers: auto for scalars, csv for comma lists, and yaml for YAML-shaped values.
Build argparse-backed CLIs, modal subcommands, nested config trees, dotted overrides, and YAML/JSON load/dump.
Ship with py.typed and zero required runtime dependencies.
Installation
pip install kwconf
# optional extras
pip install kwconf[yaml] # YAML config load/dump and parser='yaml'
pip install kwconf[ubelt] # rich repr, Config.__json__, port_to_argparse
Quickstart
Start with plain class attributes. Type annotations are optional.
import kwconf
class DemoConfig(kwconf.Config):
count = 1
mode = kwconf.Value('fast', choices=['fast', 'safe'])
tags = kwconf.Value(default_factory=list, nargs='+')
cfg = DemoConfig.cli(argv=['--count=3', '--mode=safe', '--tags', 'a', 'b'])
assert cfg.count == 3
assert cfg['mode'] == 'safe'
assert cfg.tags == ['a', 'b']
The same class works from Python, files, env, or argv:
cfg = DemoConfig(count=2)
cfg = DemoConfig().load({'count': 2})
cfg = DemoConfig.cli(data={'count': 2}, argv=False)
cfg = DemoConfig.cli(argv='--count=2 --mode=safe')
cfg = DemoConfig.from_env(prefix='DEMO_')
cfg = DemoConfig.from_yaml('demo.yaml')
Parser basics
A parser tells a field how to read a CLI/env string.
import kwconf
class ParserConfig(kwconf.Config):
scalar = kwconf.Value(None) # parser='auto'
nums = kwconf.Value(default_factory=list, parser='csv')
payload = kwconf.Value(None, parser='yaml')
cfg = ParserConfig.cli(argv=[
'--scalar=3',
'--nums=1,2,3',
'--payload={enabled: true, size: 4}',
])
assert cfg.scalar == 3
assert cfg.nums == [1, 2, 3]
assert cfg.payload == {'enabled': True, 'size': 4}
auto reads scalar strings such as 3, true, and null. csv splits commas and applies auto to each part. yaml uses yaml.safe_load for lists, dicts, and scalars; install kwconf[yaml] for that parser. See the coercion manual for the detailed parser contract.
Flags and bare options
Kwconf deliberately lets flags be written both conveniently and explicitly. For example, --flag means the flag’s bare value while --flag=false or --flag false records an explicit false value on the command line. This is a core kwconf feature: explicit configurations do not need to delete false-valued keys.
bare= generalizes the same idea to non-boolean values:
class ArchiveConfig(kwconf.Config):
patch = kwconf.Value(None, bare='auto', short_alias=['p'])
verbose = kwconf.Value(0, isflag='counter', short_alias=['v'])
assert ArchiveConfig.cli(argv=['--patch']).patch == 'auto'
assert ArchiveConfig.cli(argv=['--patch=base.tar']).patch == 'base.tar'
assert ArchiveConfig.cli(argv=['-pv']).patch == 'auto'
assert ArchiveConfig.cli(argv=['-pv']).verbose == 1
Bare-capable short aliases are clusterable. They intentionally do not accept undelimited attached values: use -p=file or -p file, not -pfile. Ordinary required-value aliases continue to accept argparse’s -kVALUE syntax. Use -- when a token following a bare option must be positional, for example prog --flag -- input.txt.
The lexical conveniences can be disabled independently with __fuzzy_hyphens__ = False and __short_alias_clusters__ = False. See the coercion and CLI contract for the full grammar.
Growing a script
kwconf is designed for scripts that start as a dictionary and grow into a CLI with minimal churn.
import kwconf
class MyConfig(kwconf.Config):
simple_option1 = 1
simple_option2 = 2
def main(argv=None, **kwargs):
config = MyConfig.cli(argv=argv, data=kwargs)
return run_algorithm(config)
def run_algorithm(config):
# Existing dict-style code can keep using config['simple_option1'].
...
Add metadata where the CLI needs it:
class MyConfig(kwconf.Config):
simple_option1 = kwconf.Value(1, help='first simple option')
simple_option2 = kwconf.Value(2, help='second simple option')
Typed path
Annotations improve static checks, editor help, parser selection, and runtime validation.
class TrainConfig(kwconf.Config):
lr: float = 1e-3
mode: str = kwconf.Value('fast', choices=['fast', 'safe'])
tags: list[str] = kwconf.Value(default_factory=list, nargs='+')
cfg = TrainConfig.cli(argv=['--lr=0.01', '--tags', 'cat', 'dog'])
assert cfg.lr == 0.01
assert cfg.tags == ['cat', 'dog']
Runnable examples
The checked-in examples live in examples/. Run commands from the repo root:
python examples/01_minimal_config.py --help
python examples/01_minimal_config.py --width=128 --height=96 --method=lanczos --dst=thumb.png --tags demo small --dry-run
python examples/03_config_files.py --config examples/data/report.yaml --limit=3 --format=json
python examples/run_all.py
Use examples/README.md as the map. Each example focuses on one surface: basic configs, CLI flags, files, nested configs, modals, large app structure, and migration helpers.
Scriptconfig migration
Use the migration guide when porting existing code or prompting an LLM that already knows scriptconfig.
import scriptconfig as scfg -> import kwconf.
scfg.Config / scfg.DataConfig -> kwconf.Config.
type= -> parser= for new code.
cmdline= -> argv=. Recent scriptconfig already supports argv; older examples often emphasize cmdline.
--config / --dump / --dumps are opt-in via special_options=True or __special_options__ = True.
Comma-separated CLI strings stay strings. Use nargs='+', parser='csv', or parser='yaml' for structured text input.
See the migration guide for the checklist, footguns, and exact replacements.
Next steps
Read the documentation for the core contract, parser model, nested configs, modal CLIs, and migration notes. The examples/ directory contains runnable scripts for the main patterns.