Created
November 11, 2022 07:00
-
-
Save bebosudo/8352d6ba4c8911528f085890becc01c4 to your computer and use it in GitHub Desktop.
A trick to support environment variables as a backup in Python's argparse when command line argument is not provided
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import argparse | |
import getpass | |
import logging | |
import os | |
# Check for values inside the environment variables and, if any, set them in the 'default' | |
# parameter of argparse, so that we don't duplicate code. Just make sure not to use '%(default)s' | |
# inside the help method, or it would print the env var and not the actual default, if an env var | |
# was defined. | |
# Use a **kwargs dict expansion so that we can expand both {"default": os.getenv("num")} into | |
# default=123 or {} into no default value at all, since passing default=None is not the same as | |
# not passing any default. | |
pos_var1_env = "EXPECTED_NAME_OF_POSITIONAL_VAR" | |
opt_var1_env = "EXPECTED_NAME_OF_FIRST_OPTIONAL_VAR" | |
opt_var2_env = "EXPECTED_NAME_OF_SECOND_OPTIONAL_VAR" | |
opt_var1_default = "ajeje" | |
def get_dict_with_default(env_var): | |
return {"default": os.getenv(env_var)} if os.getenv(env_var) else {} | |
parser = argparse.ArgumentParser(description="Here goes a description") | |
# nargs=? is mandatory for positional arguments; make sure to check after parsing if a | |
# positional argument was set by an environment variable. Without nargs=? argparse will | |
# complain because it doesn't find a required positional argument | |
parser.add_argument("host", nargs="?", **get_dict_with_default(pos_var1_env), | |
help=(f"Help text for a required argument (if no value provided at cmd | |
f"line it can also be provided through environment " | |
f"variable: {pos_var1_env})") | |
# No need to call the special function above and expand a dictionary, since here we have a | |
# default value, so default can always be used. | |
# Make sure not to use %(default)s inside the help text, or that would print the | |
parser.add_argument("-u", "--username", default=os.getenv(opt_var1_env, opt_var1_default), | |
help=(f"Help text for optional argument with a default (if no value " | |
f"from cmd line check in env var: {opt_var1_env}, otherwise " | |
f"set default value to: {opt_var1_default})")) | |
parser.add_argument("-p", "--password", **get_dict_with_default(opt_var2_env), | |
help=(f"Help text for another optional argument with no default (if no " | |
f"value from cmd line check in env var: {opt_var2_env})")) | |
args = parser.parse_args() | |
# Final checks, since nargs=? means that argparse won't require a value at command line, but | |
# it may get set anyway if it was available as environment variable. | |
if not args.host: | |
parser.error(f"Host value not provided at command line nor through environment " | |
f"variable '{pos_var1_env}'") | |
# Optional arguments are by default nargs=?, so content must be checked if no default was | |
# provided. | |
if not args.password: | |
# You may want to end up asking the user to type in the password. | |
prompt = f"Password for user '{args.username}'" | |
logging.warning(f"{prompt} not provided at command line nor through environment " | |
f"variable '{opt_var2_env}'") | |
args.password = getpass.getpass(f"{prompt}: ") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment