Evaluate boolean environment variable in Python

Viewed 49813

How can I evaluate if a env variable is a boolean True, in Python? Is it correct to use:

if os.environ['ENV_VAR'] is True:
      .......
9 Answers

Option 1

I think this works well:

my_env = os.getenv("ENV_VAR", 'False').lower() in ('true', '1', 't')

It allows: things like true, True, TRUE, 1, "1", TrUe, t, T, ...

Update: After I read the commentary of Klaas, I updated the original code my_env = bool(os.getenv(... to my_env = os.getenv(... because in will result in a bool type


Option 2

UPDATE: After the @MattG commentary, I added a new solution that raises an error for entries like ttrue instead of returning False:

# ...
import os
# ...

def get_variable(name: str, default_value: bool | None = None) -> bool:
    true_ = ('true', '1', 't')  # Add more entries if you want, like: `y`, `yes`, ...
    false_ = ('false', '0', 'f')
    value: str | None = os.getenv(name, None)
    if value is None:
        if default_value is None:
            raise ValueError(f'Variable `{name}` not set!')
        else:
            value = str(default_value)
    if value.lower() not in true_ + false_:
        raise ValueError(f'Invalid value `{value}` for variable `{name}`')
    return value in true_

# ...

my_env1 = get_variable("ENV_VAR1")
my_env2 = get_variable(name="ENV_VAR2") # Raise error if variable was not set
my_env3 = get_variable(name="ENV_VAR3", default_value=False) # return False if variable was not set

All the same, but thats the most readable version for me:

DEBUG = (os.getenv('DEBUG', 'False') == 'True')

Here anything but True will evaluate to False. DEBUG is False unless explicitly set to True in ENV

I recommend using strtobool function

example:

DEBUG = strtobool(os.getenv("DEBUG", "false"))

You can check them in python documentation https://docs.python.org/3/distutils/apiref.html#distutils.util.strtobool

Only one problem, they raise an error if you pass the wrong value

Code

from distutils.util import strtobool

print("Value: ", strtobool("false"))

print("Value: ", strtobool("Wrong value"))

Output

Value:  0
Traceback (most recent call last):
  File "<string>", line 9, in <module>
  File "/usr/lib/python3.8/distutils/util.py", line 319, in strtobool
    raise ValueError("invalid truth value %r" % (val,))
ValueError: invalid truth value 'wrong value'

Neither of the ways you have will work. os.environ['ENV_VAR'] alone will cause a KeyError if the key doesn't exist, and will return the value associated with the 'ENV_VAR' if it does. In either case, you'll error out, or compare to True or "true" which will always result in False (unless the value associated with the environment variable happens to be "true"; but that isn't what you're after).

To check if a mapping contains a particular key, you would use in:

if 'ENV_VAR' in os.environ:
    # It contains the key
else:
    # It doesn't contain the key

Highly recommend environs:

from environs import Env

env = Env()

MY_BOOL_VALUE = env.bool("MY_BOOL_VALUE", False)

if MY_BOOL_VALUE:
    print("MY_BOOL_VALUE was set to True.")
else:
    print("MY_BOOL_VALUE was either set to False or was not defined.")

Another alternative that accepts either "false", "False", "true" or "True":

import os
import ast

def getenv_bool(name: str, default: str = "False"):
    raw = os.getenv(name, default).title()
    return ast.literal_eval(raw)

I use the following to have more strict typing and support wider boolean variations in inputs

import os

def getenv_bool(name: str, default: bool = False) -> bool:
    return os.getenv(name, str(default)).lower() in ("yes", "y", "true", "1", "t")

Usage :

feature_1=getenv_bool('FEATURE_1', False)

Another possible solution is parse values as JSON values:

import json
import os

def getenv(name, default="null"):
    try:
        return json.loads(os.getenv(name, default))
    except json.JSONDecodeError:
        return name

The try is for cases when is not possible a direct conversion.

assert getenv("0") == 0
assert getenv("1.1") = 1.1
assert getenv("true") == True
assert getenv("Hello") = "Hello"
assert getenv('["list", "of", "strings"]') == ["list", "of", "strings"]

If you don't want to use the environs library mentioned above then strtobool is perfect for this. The only problem is it is deprecated, there does not seem to be a replacement library anywhere, but luckily it is only a few lines of simple code with no dependencies. Just implement the code:

# Copied from distutils.util.strtobool, which is deprecated
def strtobool (val):
    """Convert a string representation of truth to true (1) or false (0).

    True values are case insensitive 'y', 'yes', 't', 'true', 'on', and '1'.
    false values are case insensitive 'n', 'no', 'f', 'false', 'off', and '0'.
    Raises ValueError if 'val' is anything else.
    """
    val = val.lower()
    if val in ('y', 'yes', 't', 'true', 'on', '1'):
        return 1
    elif val in ('n', 'no', 'f', 'false', 'off', '0'):
        return 0
    else:
        raise ValueError("invalid truth value %r" % (val,))

Use it like this:

my_env_var_value = strtobool(os.getenv("ENV_VAR", "False"))

And YES, this will throw an error if the environment variable has some value that is neither true nor false. In the great majority of cases that is probably the best course of action.

Related