Hello,
I’d like to (re-)open a discussion about adding support for environment variables to the argparse module in Python’s stdlib.
Background:
Nowadays it’s common for software to take arguments and configuration options via command line. I had a long list of examples here, but apparently “new users can only put 2 links in a post.”
The Issue
Although accepting environment variables (as an alternative way for passing command line arguments) is a fairly common thing, Python does not provide an “integrated” way of doing so for apps/scripts written in Python. While every developer can build something for his/her app based on os.getenv() and similar, every app where this is needed also has to implement the logic for doing so. This involves precedence (command line arguments take precedence over arguments passed via environment variables), naming the environment variables (e.g. the environment variable MYAPP_FOO can be used as a replacement for the –-foo command line option), and documentation (the developer will have to document the names of all the environment variables).
The current situation goes against the
There should be one-- and preferably only one --obvious way to do it.
from the “zen of python” and leads to inconsistencies in how various projects developed in Python handle environment variables.
My Proposal:
In my opinion, it would be great if this could be handled by the argparse module. I would propose to add a new (optional) argument for ArgumentParsers, I’ll call it envvar_prefix.
It could be used like this:
parser = argparse.ArgumentParser(envvar_prefix="MYAPP_")
I imagine the semantics as follows:
- if
envvar_prefixis not set, the argument parser will not consider any environment variables. (This should make the change perfectly backwards compatible.) - If
envvar_prefixis set (it would have to be set to a string), it should be possible to pass every argument added to the parser via environment variables (see below for exceptions). For example, an argument calledfoowould be taken from the environment variable calledenvvar_prefix + "FOO", optional arguments such as--barwould be taken fromenvvar_prefix + "BAR".
Some more details:
- The name of the environment variable for an argument would be constructed as
parser.envvar_prefix + argument.name.upper(). - arguments that can get multiple values (where
nargsis+,*or > 1) should not be taken from environment variables. (One could discuss about using comma-separated values, e.g.MYAPP_FOO=bar,baz, but I’d like to keep things simple for now.) - Precedence: When calling
parser.parse_args(), command line arguments should take precedence over environment variables and environment variables should take precedence over the default value (if any) of the argument. envvar_prefixcould be set to the empty string. If so, the environment variable corresponding to an argument namedfoowould simply be calledFOO.- The
envvar_prefixshould apply to all subparsers, too. (Maybe it should be possible to specify additional prefixes for subparsers, so that args would be taken from an environment variable calledroot_parser.envvar_prefix + subparser.envvar_prefix + argument_name?) - I don’t know (yet) if there would be problems handling non-ascii argument names. For now I assume the argument name would simply be converted to upper-case, e.g. an argument called
cañawould be taken fromMYAPP_CAÑA. I’d have to look into what this would mean for languages like chinese and arabic where there are no upper-case characters, my assumption is that Python’supper()method doesn’t change the characters.
I’d love to get some feedback on the idea above and getting such a feature into Python’s stdlib.
References:
Ways of using environment variables for argparse have been discussed before, I could find the following discussions:
- Have argparse provide ability to require a fallback value be present · Issue #70582 · python/cpython · GitHub
- Apparently this was discussed in the PEP about adding argparse to Python’s stdlib (but considered as out-of-scope)
- There are various questions about this on StackOverflow (but I’ve already exhausted the two links I can add to my post).