ConfigArgParse
ConfigArgParse is a drop-in replacement for Python's standard `argparse` module, enhancing it with the ability to load configuration options from command-line arguments, environment variables, and configuration files (INI, YAML, TOML formats). It offers a unified API to define, document, and parse settings from multiple sources with a clear precedence order (command line > environment variables > config file values > defaults). The library is actively maintained, with its current version being 1.7.5.
Warnings
- breaking Prior to v1.7.4, environment variables were ignored when used in conjunction with subparsers. This could lead to unexpected behavior where subcommands would not receive their intended environment-sourced configuration.
- breaking In versions prior to v1.7.3/v1.7.4, using `nargs=argparse.REMAINDER` or the `--` separator could lead to config file options being 'swallowed' or incorrectly parsed. This resulted in config file settings not being applied or arguments being misinterpreted as positional arguments.
- gotcha ConfigArgParse introduced stricter input validation for `ArgumentParser.__init__()` in v1.7.4. Passing incorrect types for parameters like `config_file_parser_class`, `formatter_class`, `default_config_files`, `args_for_setting_config_path`, or `args_for_writing_out_config_file` will now raise a `TypeError` with a clear message.
- gotcha When defining boolean flags with `action='store_true'` or `action='store_false'`, set them as `key = true` or `key = false` in config files or environment variables. For arguments with `action='append'` (lists), use `key = [value1, value2]` or multiple `key = value` lines (depending on parser). A simple `key = value` will be treated as `--key value`.
- gotcha Only command-line arguments that have a long version (i.e., start with `--`, e.g., `--my-option`) can be set via config files. Short arguments (e.g., `-m`) cannot directly be specified in config files.
- gotcha Prior to v1.7.3, the TOML parser might only read the first matching section, or INI-style config parsers could encounter `SyntaxError`s due to `ast.literal_eval` leaks.
Install
-
pip install configargparse -
pip install configargparse[yaml] -
pip install configargparse toml
Imports
- ArgumentParser
from configargparse import ArgumentParser
Quickstart
import configargparse
import os
# Simulate an environment variable
os.environ['MYAPP_HOST'] = 'localhost'
# Create a dummy config file
config_content = """
host = 127.0.0.1
port = 8080
debug = false
"""
with open('my_config.ini', 'w') as f:
f.write(config_content)
# Initialize the parser
p = configargparse.ArgumentParser(
default_config_files=['./my_config.ini'],
auto_env_var_prefix='MYAPP_'
)
# Add arguments
p.add('--host', help='Host address')
p.add('--port', type=int, help='Port number')
p.add('--debug', action='store_true', help='Enable debug mode')
p.add('-c', '--config', is_config_file_arg=True, help='Path to config file')
# Parse arguments (simulate command line: --port 9000)
# `parse_args` can take a list of args, e.g., ['--port', '9000']
# For this example, we'll let it parse from system args (or defaults/env/config)
# If running as a script, try: python your_script.py --port 9000
# You can also set MYAPP_PORT=9001 in your shell before running.
# For the demo, let's explicitly provide some command-line args.
args = p.parse_args(['--port', '9002'])
print(f"Host: {args.host} (from config file, overridden by env var if present) ")
print(f"Port: {args.port} (command line > env var > config > default)")
print(f"Debug: {args.debug} (from config file)")
# Cleanup (optional)
os.remove('my_config.ini')
del os.environ['MYAPP_HOST'] # Clean up the simulated env var
# Expected precedence: command line > environment variables > config file values > defaults
# In this example:
# - Host: 'localhost' (from MYAPP_HOST env var, overrides 127.0.0.1 in config)
# - Port: 9002 (from explicit command line, overrides 8080 and any MYAPP_PORT)
# - Debug: False (from config file 'debug=false' which becomes --debug false; action='store_true' needs --debug to be present for True)
# Actually, `debug = false` in INI for `action='store_true'` will effectively NOT set the flag, resulting in False. If you want true, it should be `debug=true` or just `debug`.
# Let's verify debug: `debug = false` in INI would mean the flag `--debug` is NOT present, so `args.debug` defaults to `False` for `action='store_true'`. If `debug=true` it would be `True`.