Skip to main content

envbool

Coerce environment variables and strings into booleans — sensibly.

PyPI version Python versions License: MIT CI


Reading a boolean out of the environment is the kind of thing every project reinvents, slightly differently, in slightly buggy ways:

DEBUG   = os.environ.get("DEBUG",   "").lower() in ("1", "true", "yes")
VERBOSE = os.environ.get("VERBOSE", "").lower() in ("1", "true", "yes")
CACHE   = os.environ.get("CACHE",   "").lower() in ("1", "true", "yes")

envbool is that snippet, done once and done properly:

from envbool import envbool

DEBUG   = envbool("DEBUG")
VERBOSE = envbool("VERBOSE")
CACHE   = envbool("CACHE")

Features

  • Lenient by default, strict when you want it. Unrecognized values quietly become False, or raise on demand to catch typos in production config.
  • Always returns bool. No None, no surprises in your type signatures.
  • Customizable value sets. Replace or extend the truthy/falsy words your environment uses.
  • Config files. Share defaults across a project via envbool.toml or [tool.envbool] in pyproject.toml.
  • A CLI for shell scripts. Exit codes map to truthiness, so it drops straight into && / || chains.
  • Zero ceremony. One dependency, fully typed, Python 3.11+.

Contents

Installation

pip install envbool
# or
uv add envbool

Usage

The basics

envbool is lenient by default: anything not recognized as truthy returns False, and unset or empty variables return the default.

from envbool import envbool

DEBUG = envbool("DEBUG")                 # False if unset or empty
CACHE = envbool("CACHE", default=True)   # True if unset or empty

The built-in truthy values are true, 1, yes, on; the falsy values are false, 0, no, off. Comparison is case-insensitive and ignores surrounding whitespace.

Strict mode

Pass strict=True to raise InvalidBoolValueError on anything outside the truthy/falsy sets — ideal for failing fast on a misconfigured deployment.

import sys
from envbool import envbool, InvalidBoolValueError

try:
    USE_SSL = envbool("USE_SSL", strict=True)
except InvalidBoolValueError as e:
    sys.exit(f"Bad value for USE_SSL: {e.value!r}")

Custom value sets

When your environment speaks a different dialect, extend the defaults or replace them outright:

# Add to the built-in sets
FEATURE = envbool("FEATURE_FLAG", extend_truthy={"enabled", "y"})

# Replace them entirely
LOCALE = envbool("USE_METRIC", truthy={"metric"}, falsy={"imperial"})

Coercing arbitrary strings

Use to_bool for values that don't come from the environment. It accepts the same keyword arguments as envbool.

from envbool import to_bool

to_bool("yes")                 # True
to_bool("0")                   # False
to_bool("maybe", strict=True)  # raises InvalidBoolValueError

Command-line interface

The envbool command exits 0 for truthy, 1 for falsy, and 2 on error, so it composes naturally with shell control flow.

$ export DEBUG=true
$ envbool DEBUG && echo "debug is on"
debug is on

$ echo "Verbose: $(envbool --print VERBOSE)"
Verbose: false

$ echo "yes" | envbool && echo "truthy"
truthy

$ envbool --strict ENABLE_CACHE || echo "cache is off or misconfigured"
cache is off or misconfigured

Input is taken from a VAR_NAME argument, the --value flag, or a stdin pipe — in that order of priority.

$ envbool --help
usage: envbool [-h] [--value TEXT] [--strict] [--warn] [--default] [--print]
               [--truthy VALUE] [--falsy VALUE] [--extend-truthy VALUE]
               [--extend-falsy VALUE] [--show-config]
               [VAR_NAME]

Coerce an environment variable or string to a boolean.

positional arguments:
  VAR_NAME              Environment variable name to check.

options:
  -h, --help            show this help message and exit
  --value, -v TEXT      Check a literal string instead of an env var.
  --strict, -s          Raise error on unrecognized values.
  --warn                Log a warning on unrecognized values.
  --default, -d         Default value if unset/empty (default: false).
  --print, -p           Print "true" or "false" instead of using exit codes.
  --truthy VALUE        Replace the truthy set with VALUE (repeatable).
  --falsy VALUE         Replace the falsy set with VALUE (repeatable).
  --extend-truthy VALUE
                        Add VALUE to the truthy set (repeatable).
  --extend-falsy VALUE  Add VALUE to the falsy set (repeatable).
  --show-config         Print the effective configuration and exit.

A few rules worth knowing:

  • Omitting --strict / --warn defers to the config file setting.
  • VAR_NAME and --value are mutually exclusive.
  • --show-config prints the effective configuration and exits. It cannot be combined with VAR_NAME, --value, --print, or --default, but it can take the value-set flags to preview overrides.
  • With no VAR_NAME, --value, or piped stdin, the CLI prints usage and exits 2.

Configuration

Share defaults across a project by dropping an envbool.toml at its root (or a [tool.envbool] table in pyproject.toml):

# envbool.toml
strict = true
extend_truthy = ["enabled"]
extend_falsy  = ["disabled"]

envbool walks up from the current directory to find the nearest project config, then falls back to a user-level config.toml in the platform's standard config directory (~/.config/envbool/ on Linux, ~/Library/Application Support/envbool/ on macOS), resolved via platformdirs.

Values resolve in three layers, each overriding the last:

built-in defaults  →  config file  →  function arguments / CLI flags

Set ENVBOOL_NO_CONFIG=1 to skip config discovery entirely.

API reference

Symbol Description
envbool(var, **opts) Read an environment variable and return bool.
to_bool(value, **opts) Coerce a string to bool.
load_config() Load and return the active EnvBoolConfig (cached).
reload_config() Discard the cache, re-read the config file, and return the fresh EnvBoolConfig.
EnvBoolConfig Frozen dataclass: strict, warn, effective_truthy, effective_falsy, source_path.
DEFAULT_TRUTHY frozenset of the built-in truthy strings.
DEFAULT_FALSY frozenset of the built-in falsy strings.
EnvBoolError Base class for every exception the library raises.
InvalidBoolValueError Raised in strict mode for unrecognized values. Also a ValueError.
MissingEnvVarError Raised by envbool(required=True) when the variable is unset. Also a KeyError.
ConfigError Raised when a config file is malformed.

envbool() and to_bool() share the same keyword-only options:

Option Type Default Meaning
default bool False Returned for unset/empty input.
strict bool | None None Raise on unrecognized values (None defers to config).
warn bool | None None Log a warning on unrecognized values (None defers to config).
truthy / falsy Iterable[str] | None None Replace the effective set.
extend_truthy / extend_falsy Iterable[str] | None None Extend the effective set.

envbool() also accepts required (bool, default False): when True, a variable that is unset raises MissingEnvVarError before default is applied. A variable set to an empty string counts as present and still uses default.

Advanced topics

Exception handling

Every exception inherits from EnvBoolError, so a single except EnvBoolError catches the whole library. Catch a specific subclass when you need its detail:

from envbool import envbool, InvalidBoolValueError

try:
    result = envbool("MY_VAR", strict=True)
except InvalidBoolValueError as e:
    print(e.var)    # "MY_VAR" — env var name, or None when raised from to_bool()
    print(e.value)  # "maybe" — the normalized (stripped, lowercased) value
    print(e.truthy) # frozenset({"true", "1", "yes", "on"}) — effective truthy set
    print(e.falsy)  # frozenset({"false", "0", "no", "off"}) — effective falsy set

InvalidBoolValueError also subclasses the built-in ValueError, so existing except ValueError handlers keep working. Its message spells out exactly what was expected:

InvalidBoolValueError: Invalid boolean value for MY_VAR: 'maybe'
  Expected truthy: 1, on, true, yes
  Expected falsy:  0, false, no, off

ConfigError is raised when a config file is found but malformed (for example, strict = "yes" instead of strict = true). It carries the offending path on e.path.

Logging

envbool logs through the standard logging module under the "envbool" namespace and attaches no handlers of its own — configure it like any other library logger:

import logging

logging.getLogger("envbool").setLevel(logging.DEBUG)
logging.getLogger("envbool").addHandler(logging.StreamHandler())
Level When
DEBUG A config file was discovered and loaded, or none was found.
WARNING An unrecognized value fell through in lenient mode (only when warn=True).
WARNING The truthy and falsy sets overlap (truthy wins).

The unset-vs-empty distinction

envbool() always returns bool and deliberately cannot tell an unset variable apart from one set to the empty string — both yield default. Most deployment tooling can't distinguish the two either, and a plain bool keeps call sites clean. When you genuinely need the distinction, check os.environ yourself:

import os
from envbool import envbool

if "MY_VAR" not in os.environ:
    ...  # truly unset — handle the "not configured" case
else:
    result = envbool("MY_VAR")

Testing code that uses envbool

envbool loads its config file once and caches it for the process lifetime. If your tests create temporary config files, clear that cache between them with an autouse fixture:

# conftest.py
import pytest
from envbool._config import _reset_config

@pytest.fixture(autouse=True)
def _reset_envbool_config():
    yield
    _reset_config()

_reset_config() is private but stable and exists for exactly this purpose; it clears the cache under a lock, so it is safe to call from any thread.

Contributing

Contributions are welcome. See CONTRIBUTING.md for development setup, project layout, and the conventions this repo follows.

License

Released under the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

envbool-0.3.0.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

envbool-0.3.0-py3-none-any.whl (20.9 kB view details)

Uploaded Python 3

File details

Details for the file envbool-0.3.0.tar.gz.

File metadata

  • Download URL: envbool-0.3.0.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for envbool-0.3.0.tar.gz
Algorithm Hash digest
SHA256 9c7ca32e040f2054305e951a362349882e05697f08f2dff814fd96c28579564b
MD5 c6844602b7b12bbfe34b697dbcdf17f1
BLAKE2b-256 e17ed8f2ebc3d12ed0046ed9b69f182ac7cc54ef59bce4cf070444d3550dee5c

See more details on using hashes here.

Provenance

The following attestation bundles were made for envbool-0.3.0.tar.gz:

Publisher: cd.yml on jkomalley/envbool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file envbool-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: envbool-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 20.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for envbool-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 18c727e040361645351d9958f82ae65de2be58fb1a35c5d1fe0e975a3412762c
MD5 ea946f6fdb58548be6f69629206dd375
BLAKE2b-256 d51c479f6761b623eff69bc567fec03fa8b8d5587c91a506ad24f6f129fc2fab

See more details on using hashes here.

Provenance

The following attestation bundles were made for envbool-0.3.0-py3-none-any.whl:

Publisher: cd.yml on jkomalley/envbool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page