I copy and paste some some small functions to get an environment variable and cast it to an int or cast it to a bool. There are some more full featured libraries like environs, django-environ but I actually haven’t used them.
One problem is this:
FOO_ENABLED = os.getenv("FOO_ENABLED")
if FOO_ENABLED:
foo()
An experienced person will know that when export FOO_ENABLED=false
, it’s still going to run because strings are truthy.
Another problem is:
RETRY_COUNT = os.getenv("RETRY_COUNT", 10)
if num_retries <= RETRY_COUNT:
retry()
An experienced person will know that when export RETRY_COUNT=10
, this is going to result in a TypeError, because strings and ints can not be compared.
I thought that maybe these cases are common and preventable enough with a reasonable implementation; therefore perhaps worthy of adding something to os module in the stdlib.
Two functions called os.getint
or os.getbool
seem like they would be great and straight forward. Alternatively I thought maybe adding a cast function parameter to the existing os.getenv
might be nice. That way, if people have their own env var deserialization function, they can still use the getenv method. The pattern of “try and find something, try and serialize it, otherwise fall back on this default” is always nice to have. I think that the stdlib should also make a decision on how to parse a bool. If that does not always suffice, people can use their own bool casting function.
assert getenv2("TEST_INT", default=500, cast_to=int) == 500
assert getenv2("TEST_INT", cast_to=int) is None
os.environ["TEST_INT"] = "100"
assert getenv2("TEST_INT", default=500, cast_to=int) == 100
assert getenv2("TEST_BOOL", default=True, cast_to=bool) is True
assert getenv2("TEST_BOOL", cast_to=bool) is None
os.environ["TEST_BOOL"] = "True"
assert getenv2("TEST_BOOL", default=False, cast_to=bool) is True
os.environ["TEST_BOOL"] = "False"
assert getenv2("TEST_BOOL", default=True, cast_to=bool) is False
def boolenv(value):
TRUE_VALUES = ("y", "yes", "t", "true", "on", "1")
value = value.lower()
return value in TRUE_VALUES
def getenv2(key, default=None, cast_to=None):
try:
result = os.environ[key]
except KeyError:
return default
if cast_to is None:
return result
if cast_to is bool:
fn = boolenv
else:
fn = cast_to
try:
return fn(result)
except ValueError:
return default
What do you think?