Skip to content

Instantly share code, notes, and snippets.

@orls
Last active February 7, 2024 21:56
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save orls/51525c86ee77a56ad396 to your computer and use it in GitHub Desktop.
Save orls/51525c86ee77a56ad396 to your computer and use it in GitHub Desktop.
Using env vars in argparse
import argparse
from EnvDefault import env_default
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="use env vars as defaults for argparse"
)
parser.add_argument(
"--alpha", "-a",
action=env_default('ALPHA'),
required=False,
help="""Optional. Value from CLI will be used if present, or from env var ALPHA.
If neither of these is present, value is None becasue no fallback default
was given"""
)
parser.add_argument(
"--beta", "-b",
action=env_default('BETA'),
required=True,
help="""Required. Value from CLI will be used if present, or from env var BETA.
If neither of these is present, it's an error"""
)
parser.add_argument(
"--gamma", "-g",
action=env_default('GAMMA'),
required=True,
default=9001,
help="""Value from CLI will be used if present, or from env var GAMMA.
If neither of these is present, default of 9001 is used"""
)
print parser.parse_args()
"""Provides a utility to inject environment variables into argparse definitions.
Currently requires explicit naming of env vars to check for"""
import argparse
import os
# Courtesy of http://stackoverflow.com/a/10551190 with env-var retrieval fixed
class EnvDefault(argparse.Action):
"""An argparse action class that auto-sets missing default values from env
vars. Defaults to requiring the argument."""
def __init__(self, envvar, required=True, default=None, **kwargs):
if not default and envvar:
if envvar in os.environ:
default = os.environ[envvar]
if required and default:
required = False
super(EnvDefault, self).__init__(default=default, required=required,
**kwargs)
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
# functional sugar for the above
def env_default(envvar):
def wrapper(**kwargs):
return EnvDefault(envvar, **kwargs)
return wrapper
@flying-sheep
Copy link

For this to behave as described, the if not default and envvar: check needs to be removed.

The env variable is supposed to override the default.

@spinus
Copy link

spinus commented Oct 23, 2021

@flying-sheep that only helps partially. IMHO the correct behavior would be to set the value from environment variable but not to override the default (that can break "help" message when using env vars, which is not broken behavior).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment