ConfigArgParse and one precedence order for flags, files and environment
Drop-in replacement for argparse with added support for config files and environment variables.
At a glance
- What is it?
- ConfigArgParse extends argparse so that a value can come from the command line, a config file, an environment variable or a default, with a fixed precedence between them. It is a small, single module library with no required dependencies, and the interesting part is the config file syntax it invented and the places where it deliberately differs from argparse.
- Who is it for?
- ConfigArgParse fits a Python application with more than a handful of user-settable options, where the same setting needs to be adjustable from a config file on one machine and an environment variable in a container. It is the wrong tool for a small script with three flags, where argparse is already enough, and the wrong tool if you need per-environment layered config files with merge semantics, because the precedence order is a single fixed chain.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One API for four places a setting can come from
ConfigArgParse is described as a drop-in replacement for argparse with added support for config files and environment variables, and the reasoning starts from a simple observation about applications.
Applications with more than a handful of user-settable options are best configured through a combination of command line args, config files, hard-coded defaults, and in some cases, environment variables. Python's command line parsing modules such as argparse have very limited support for config files and environment variables, so this module extends argparse to add these features.
The install is a single command:
pip install ConfigArgParseThe core promise is that command-line, config file, env var and default settings can be defined, documented and parsed in one go using a single API. The key word there is one, because the alternative is what most projects end up with: argparse for the flags, a separate configparser call, a separate os.environ lookup, and a hand-rolled merge of the three, with the precedence order written by hand in a place nobody looks at twice.
The precedence is fixed and documented: if a value is specified in more than one way then command line overrides environment variables, which override config file values, which override defaults. That ordering is the sensible one, since a person typing a command line is present and intends to win, and a deployment's environment is more specific than a checked-in config file.
Two other details make the library pleasant to live with. Env vars and config file keys and syntax are automatically documented in the `-h` help message, so a user who runs with `--help` learns that a setting can come from a file without reading separate documentation. And a new method `print_values()` can report keys and values and where they were set, for example command line, env var, config file or default, which is exactly what you want in a log line when a production run used a different value than the one you expected.
The whole library is one module file
The repository layout is unusual for a package of this age and worth noting before you adopt it.
The top level contains `configargparse.py`, a single module, alongside `setup.py`, `LICENSE`, `MANIFEST.in`, `README.md`, `CONTRIBUTING.rst`, `SECURITY.md`, `apidocs.sh`, a `tests/` directory and the usual repository files. The code is not a package directory with a `src/` layout, it is one file at the root of the tree.
That tells you a lot about the project's character. There is no build step to speak of, no extension point directory, and no plugin architecture. The library is the file, and you either take it or you do not.
The feature list backs this up. It is described as lite-weight with no 3rd-party library dependencies except optionally PyYAML, and as extensible because `ConfigFileParser` can be subclassed to define a new config file format. The only extension point is the config file format, and it is a single abstract class.
The claim that all argparse functionality is fully supported is tested in a specific way: the module is unittested by running the unittests that came with argparse but on configargparse. That is a strong compatibility argument expressed as a test suite, and it is the sort of thing that is easy to claim and hard to do, since argparse has a large surface of behaviours around prefix matching, abbreviation and error messages.
The API documentation is published at bw2.github.io/ConfigArgParse, and the package is on PyPI as ConfigArgParse. The project also keeps a `SECURITY.md` and a `CONTRIBUTING.rst`, so the more recent additions are about process rather than code.
A config file arrives through an ordinary flag, not an @ prefix
One design choice distinguishes this library from the more common approach, and it is the one you will notice first when reading a script that uses it.
The user can provide a config file via a normal-looking command line arg, for example `-c path/to/config.txt`, rather than the argparse-style `@config.txt`. Most argparse-based config file extensions use the `@` prefix, which means the file path is consumed by the parser before argparse sees the arguments. ConfigArgParse instead registers the config file as a normal argument, with `is_config_file=True` on the `add_argument` call, and the file is read as part of normal parsing.
The practical effect is that the config file argument appears in the help output as an ordinary option and behaves like one, and the same `-c` convention works in a shell script without any special quoting.
The other half of the configuration story is the default config file paths. One or more default config file paths can be specified, for example `['/etc/bla.conf', '~/.my_config']`, and the example in the documentation uses a glob pattern: `default_config_files=['/etc/app/conf.d/*.conf', '~/.my_settings']`. So a system-wide directory of fragments and a per-user file are both searched, and the user can still point somewhere else with `-c`.
The example in the documentation registers the config file as a normal argument and marks it as one:
p.add('-c', '--my-config', required=True, is_config_file=True, help='config file path')Only command line args that have a long version, one that starts with `--`, can be set in a config file. So `--color` can be set by putting `color=green` in a config file, but a short-only option cannot. That rule is a direct consequence of the implementation, since a config file key has no way to express a short flag, and it means the long names in your parser definition are effectively the public config file interface.
Config file values are rewritten as command line arguments
The mechanism under the hood is worth understanding, because it explains both the special value handling and several of the library's edges.
Under the hood, configargparse handles environment variables and config file values by converting them to their corresponding command line arg. For example, `key = value` will be processed as if `--key value` was specified on the command line.
So there is no separate merge phase over heterogeneous data structures. Environment variables and config file entries are turned into synthetic command line arguments and then go through the same argparse machinery as everything else. That is why the library can be a drop-in replacement rather than a wrapper, and why the argparse unittest suite passing is meaningful evidence.
The special values follow from the same trick. Two forms are handled specially to support booleans and lists. `key = true` is handled as if `--key` was specified on the command line, and in your Python code this key must be defined as a boolean flag, for example `action="store_true"` or similar. And `key = [value1, value2, ...]` is handled as if `--key value1 --key value2` and so on was specified, which requires the key to be defined as a list, for example `action="append"`.
That requirement is a real constraint rather than a footnote. If a config file contains `verbose = true` but the argument was defined with `action="store_true"`, it works. If the same key was defined as `type=int` or with a different action, the value is reinterpreted as a command line argument and the behaviour is not what the config file author expected. The two forms also explain why the config file syntax section shows `stuff=[a,b,c]` as valid in the default parser.
Six config file parsers, and a default that accepts more than you might want
The config file syntax depends on the constructor argument `config_file_parser_class`, which can be set to one of the provided classes: `DefaultConfigFileParser`, `YAMLConfigFileParser`, `ConfigparserConfigFileParser`, `IniConfigParser`, `TomlConfigParser` or `CompositeConfigParser`, or to your own subclass of the `ConfigFileParser` abstract class.
The default parser is the interesting one, because it is the loosest. The documentation shows the full range of valid syntax, and the file begins with a comment style, then a second comment style, then a rule that lines starting with `---` are ignored in the yaml style, then a rule that ini-style section names are treated as comments.
In other words, the default parser accepts comments in two syntaxes, ignores yaml document separators, and treats ini sections as comments so that a file can be read by several parsers at once. The key value pairs follow, and the documentation is careful about case sensitivity: the key is case sensitive, so `Name` is not `name`.
The separate parsers are there for when you want strictness. The YAML, ini and TOML parsers each implement one format properly, and `CompositeConfigParser` is the one to look at if you need to read several files of different types, for example a `.yaml` file and a `.toml` file together.
That choice has a consequence for anyone deploying this. The default parser is forgiving, which means a typo in a key is not an error, it is a key that gets ignored. The strict parsers will fail loudly on a malformed file, which is usually what you want in production and occasionally annoying when you are writing the file by hand.
Where a fixed precedence chain is the wrong shape
There are three cases where reaching for this library costs more than it saves.
The first is a small script. If your program has three options and no deployment story, argparse already does the job, and the extra dependency plus the config file plumbing is more to explain than the flags themselves.
The second is a configuration system that needs layering. The precedence here is a single chain: command line beats environment variables, which beat config files, which beat defaults. That is right for most applications, and it is wrong for a system with several config files that should merge. The `CompositeConfigParser` helps with reading several formats, but the merge semantics between them are still the single chain, not a layered override where a later file overrides only the keys it mentions.
The third is a case where the environment is not the right source of truth. If a value has to be validated against a schema, or typed in a way that argparse's `type=` callables do not cover, converting it to a synthetic command line argument is not necessarily the cleanest path. The library is a parser, and it is very good at being a parser, but the "convert everything to a command line arg" trick means your value type system is argparse's type system.
There is also a small operational point about the config file key names. Since only long options can come from a config file, and the key is case sensitive, the config file interface is bound to the exact spelling of your long options. Renaming `--genome` to `--reference` silently stops the file from setting that value, with no error, which is the same failure mode as the default parser's tolerance of typos. A strict parser, or a test that asserts the config file keys match the parser's long options, is the mitigation.
What the library does give you for free is the reporting. `print_values()` tells you not just the effective value but where it came from, and in a system where the value can arrive four different ways, that provenance is often the thing you actually needed.
Editorial conclusion
ConfigArgParse fits a Python application with more than a handful of user-settable options, where the same setting needs to be adjustable from a config file on one machine and an environment variable in a container. It is the wrong tool for a small script with three flags, where argparse is already enough, and the wrong tool if you need per-environment layered config files with merge semantics, because the precedence order is a single fixed chain. Before adopting, verify two things: that the config file syntax you want is one of the parser classes it provides, since the default parser accepts a deliberately loose syntax and the YAML, ini and TOML parsers behave differently, and that your long option names match your config file keys, because only arguments with a long form can be set from a file. The code is MIT licensed, the current release is v1.8.0 from 2026-09-28, and the last push was on 2026-10-18.
Frequently asked questions
What is ConfigArgParse and how does it differ from argparse?
It is a drop-in replacement for argparse that adds support for config files and environment variables, so that command line args, config file values, env vars and defaults can all be defined, documented and parsed through one API. The full argparse feature set is supported, and it is verified by running argparse's own unittests against configargparse.
How do I install ConfigArgParse?
Run `pip install ConfigArgParse`. The package is on PyPI as ConfigArgParse, and it has no third-party dependencies other than optionally PyYAML.
What is the precedence order when a value is set in more than one place?
Command line values override environment variables, which override config file values, which override defaults. The new method `print_values()` reports the keys, the values and where each one was set, which is useful for logging.
Which config file formats does ConfigArgParse support?
The parser class is set through the constructor argument `config_file_parser_class`, and the provided options are `DefaultConfigFileParser`, `YAMLConfigFileParser`, `ConfigparserConfigFileParser`, `IniConfigParser`, `TomlConfigParser` and `CompositeConfigParser`, or your own subclass of the `ConfigFileParser` abstract class.
Can a short option be set from a config file in ConfigArgParse?
No. Only command line args that have a long version, one that starts with `--`, can be set in a config file, so `--color` can be set with `color=green` in the file. The config file key is also case sensitive, so `Name` is not `name`.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bw2-configargparse)Was this useful?