Skip to content

Instantly share code, notes, and snippets.

@birkin
Last active September 8, 2023 14:49
Show Gist options
  • Save birkin/a6538ff457068ff2b7e2e22499f60584 to your computer and use it in GitHub Desktop.
Save birkin/a6538ff457068ff2b7e2e22499f60584 to your computer and use it in GitHub Desktop.
gotcha & solution for loading boolean envars

When false is true!

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...

problem example

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.

solutions

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment