Evaluating Boolean Environment Variables in Python
When working with environment variables in Python, properly handling boolean values can be tricky. Environment variables are always strings, so you need to convert them to boolean values correctly. This article covers the best practices for handling boolean environment variables.
The Core Problem
Environment variables are always stored as strings, so you cannot directly compare them to Python's True
or False
:
# ❌ INCORRECT - This will not work as expected
if os.environ['ENV_VAR'] is True:
# This will never execute because os.environ['ENV_VAR'] returns a string
Recommended Approaches
Simple Conversion with Flexible Values
For most use cases, this approach offers a good balance of flexibility and simplicity:
def get_env_bool(key: str, default: bool = False) -> bool:
"""Convert environment variable to boolean with flexible truthy values."""
value = os.getenv(key, str(default)).lower()
return value in ('true', '1', 't', 'yes', 'y', 'on')
Usage:
DEBUG = get_env_bool('DEBUG', False)
FEATURE_ENABLED = get_env_bool('FEATURE_FLAG', True)
This function handles common truthy values regardless of case:
- True values:
true
,1
,t
,yes
,y
,on
- Anything else returns
False
INFO
This approach is ideal when you want to be permissive about input formats, such as when working with environment files that might have inconsistent casing.
Strict Validation Approach
If you need strict validation and want to ensure environment variables contain only specific values:
def get_strict_env_bool(key: str, default: bool = None) -> bool:
"""Strict boolean environment variable parsing with validation."""
if key not in os.environ:
if default is None:
raise ValueError(f'Environment variable "{key}" is not set!')
return default
value = os.environ[key].lower()
valid_true = ('true', '1', 't')
valid_false = ('false', '0', 'f')
valid_values = valid_true + valid_false
if value not in valid_values:
raise ValueError(f'Invalid value "{value}" for environment variable "{key}"!')
return value in valid_true
Usage:
# Raises error if MY_FEATURE is not set
MY_FEATURE = get_strict_env_bool('MY_FEATURE')
# Returns False if OPTIONAL_FEATURE is not set
OPTIONAL_FEATURE = get_strict_env_bool('OPTIONAL_FEATURE', False)
WARNING
Use this approach when you need to ensure environment variables are explicitly set to valid boolean values and want to catch configuration errors early.
Alternative Solutions
Using strtobool (Deprecated in Python 3.12)
The distutils.util.strtobool
function was commonly used but is deprecated:
from distutils.util import strtobool # Deprecated in Python 3.12+
# Implementation of the deprecated function for reference
def strtobool(val):
"""Convert string representation of truth to boolean."""
val = val.lower()
if val in ('y', 'yes', 't', 'true', 'on', '1'):
return True
elif val in ('n', 'no', 'f', 'false', 'off', '0'):
return False
else:
raise ValueError(f"Invalid truth value: {val}")
DANGER
The distutils
module is deprecated as of Python 3.10 and will be removed in Python 3.12. Avoid using strtobool
in new code.
Using Third-Party Libraries
For complex applications, consider using dedicated environment variable libraries:
# Using environs library
from environs import Env
env = Env()
DEBUG = env.bool("DEBUG", False)
FEATURE_FLAG = env.bool("FEATURE_FLAG", True)
Popular options include:
environs
- Comprehensive environment variable parsingpython-decouple
- Strict separation of settings from codedjango-environ
- Django-specific environment variable management
Complete Implementation Example
Here's a robust implementation that combines flexibility with proper error handling:
import os
from typing import Optional
def parse_bool_env(
key: str,
default: Optional[bool] = None,
strict: bool = False
) -> bool:
"""
Parse boolean environment variable with flexible options.
Args:
key: Environment variable name
default: Default value if environment variable is not set
strict: If True, raises error on invalid values
Returns:
Boolean value of the environment variable
Raises:
ValueError: If environment variable is not set and no default provided,
or if value is invalid and strict=True
"""
# Handle missing environment variable
if key not in os.environ:
if default is None:
raise ValueError(f'Environment variable "{key}" is not set!')
return default
value = os.environ[key].strip().lower()
# Define accepted values
truthy = ('true', '1', 't', 'yes', 'y', 'on')
falsy = ('false', '0', 'f', 'no', 'n', 'off')
# Check if value is valid
if strict and value not in truthy + falsy:
raise ValueError(f'Invalid boolean value "{value}" for environment variable "{key}"')
return value in truthy
# Usage examples
DEBUG = parse_bool_env('DEBUG', False)
STRICT_MODE = parse_bool_env('STRICT_MODE', False, strict=True)
Common Pitfalls to Avoid
- Case sensitivity: Always convert to lowercase for consistent comparison
- Whitespace: Use
.strip()
to handle values with accidental spaces - Missing variables: Always provide sensible defaults or handle missing variables explicitly
- Unexpected values: Consider whether to be permissive or strict with input validation
Best Practices
- Be explicit: Use clear environment variable names that indicate they represent boolean values
- Document defaults: Clearly document the default behavior in your code
- Validate early: Check environment variables at application startup
- Use consistent naming: Establish conventions for boolean environment variables (e.g., prefix with
IS_
,ENABLE_
, orUSE_
)
Testing Your Implementation
Always test your boolean parsing logic:
import pytest
from unittest.mock import patch
def test_bool_parsing():
with patch.dict(os.environ, {'FEATURE_FLAG': 'true'}):
assert parse_bool_env('FEATURE_FLAG') is True
with patch.dict(os.environ, {'FEATURE_FLAG': 'False'}):
assert parse_bool_env('FEATURE_FLAG') is False
with patch.dict(os.environ, {}):
assert parse_bool_env('MISSING_VAR', True) is True
By following these patterns, you can reliably handle boolean environment variables in your Python applications while avoiding common pitfalls and ensuring consistent behavior across different environments.