In a bunch of our projects, there's a DEBUG setting that's a boolean. Here's a gotcha, and corresponding good-practice for settings like this...
I'll set an environmental variable to false:
birkin@birkinbox-2021 ~ %
birkin@birkinbox-2021 ~ % export FOO="false"
birkin@birkinbox-2021 ~ %
birkin@birkinbox-2021 ~ % env | sort
FOO=false
[snip]
...and then I'll load that in python:
>>>
>>> import os
>>>
>>> DEBUG = os.environ['FOO']
>>>
>>> DEBUG
'false'
>>>
Ok, at a quick glance, everything seems good. But... there's a common, reasonable, pythonic way of coding that anyone expecting a boolean might use:
>>>
>>> if DEBUG:
... print( "I'm reasonably assuming the value is True" )
... else:
... print( "I'm reasonably assuming the value is False" )
...
I'm reasonably assuming the value is True
>>>
Whoa! NOT what we want! This happens because that if statement is a general check for the existence of the "foo_setting" value. So if the value were the integer 0, or the empty string '', or the boolean False
, it would have printed out "I'm reasonably assuming the value is False".
But the load of the envar is perceived as the string "false", not as the boolean False
. Thus bad things could happen.
(If the envar would have been set to "False" it would have loaded as a boolean. But solutions that depend upon humans always doing the right thing aren't great solutions.)
Consequences of this mistaken settings-load could be avoided with code like:
>>>
>>> if DEBUG == True:
... print( "I'm reasonably assuming the value is True" )
... else:
... print( "I'm reasonably assuming the value is False" )
...
I'm reasonably assuming the value is False
>>>
...But that explicit check would have to be done in all places. A better way is to ensure you're dealing with expected values right up-front, when the envar is loaded.
I've long loaded the DEBUG setting like this:
>>> DEBUG = json.loads( os.environ['FOO'] )
...which will throw an error on any non-numeric or non-json-boolean string. (json can load string values, but the syntax for setting a string value in an envar isn't likely to be done accidentally.) Another possibility that'd work even for numerals:
>>> DEBUG = os.environ['FOO']
>>> assert type(DEBUG) == bool