I wish to use the argparse
module to set the value of a server URL. As well as being set via an argument, the vale can also be in an environment variable, though the argument should always take precedence.
To achieve this, I've added an argument to the parser with the environment variable value as the default, and a custom type. However, if the argument is omitted, the custom type=EnvironDefault
is not initialised. This means that if default value is None
, that value is used regardless, rather than an exception being raised as expected.
I have found a 10 year old question that suggests it is necessary to check the value of the argument after parsing the arguments, but I'm hoping that in the interim a solution has been added to argparse
.
Example 1 - Success - Environment variable but no argument
foo@bar:~$ export SERVER_URL="https://some.server.co.uk"
foo@bar:~$ python mycli
Namespace(url='https://some.server.co.uk')
Example 2 - Success - Environment variable and argument
foo@bar:~$ export SERVER_URL="https://some.server.co.uk"
foo@bar:~$ python mycli --url "https://different.server.co.uk"
Namespace(url='https://different.server.co.uk')
Example 3 - Failure - No environment variable or argument
foo@bar:~$ unset SERVER_URL
foo@bar:~$ python mycli
Namespace(url=None)
Expected response
usage: mycli [-h] [--url URL]
mycli: error: argument --url: Server URL must be provided via either the CLI or the environment variable SERVER_URL.
Example Argument Parser
import argparse
import os
class EnvironDefault(str):
def __init__(self, url: str) -> None:
err_msg = (
'Server URL must be provided via either the CLI or the '
'environment variable SERVER_URL.')
if not url:
raise argparse.ArgumentTypeError(err_msg)
parser = argparse.ArgumentParser()
parser.add_argument(
'--url', type=EnvironDefault, default=os.environ.get('SERVER_URL'),
help='Server URL. Overrides environment variable SERVER_URL.')
print(parser.parse_args())