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.
  • Process-level defaults. Call set_defaults() once at startup instead of threading options through every call site.
  • A CLI for shell scripts. Exit codes map to truthiness, so it drops straight into && / || chains.
  • Zero ceremony. Zero dependencies, 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

Process-level defaults

Set policy once at startup instead of threading strict=/extend_truthy= through every call site:

import envbool

envbool.set_defaults(strict=True, extend_truthy=["enabled"])

envbool.envbool("DEBUG")  # now raises on unrecognized values by default

set_defaults() replaces the process-level defaults from the built-ins, not from whatever a previous set_defaults() call left in place — call it once. Call-site arguments (envbool("X", strict=False)) still override whatever set_defaults() configured:

built-in defaults  →  set_defaults()  →  function arguments / CLI flags

get_defaults() returns the active Defaults (a frozen dataclass: strict, warn, effective_truthy, effective_falsy) for inspection. reset_defaults() restores the built-ins — call it in a test fixture (see Testing code that uses envbool).

Through 0.3.x, envbool read TOML config files (envbool.toml, [tool.envbool]). 0.4.0 removed them in favor of set_defaults() — see CHANGELOG.md for the rationale and migration note.

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]
               [--required] [--print] [--truthy VALUE] [--falsy VALUE]
               [--extend-truthy VALUE] [--extend-falsy VALUE]
               [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).
  --required, -r        Exit 2 if VAR_NAME is not set in the environment.
  --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).

A few rules worth knowing:

  • Omitting --strict / --warn uses the built-in defaults (lenient, no warnings). set_defaults() is a library-level concern — the one-shot CLI process doesn't read it.
  • VAR_NAME and --value are mutually exclusive.
  • --required only applies to VAR_NAME; combining it with --value or giving it no VAR_NAME at all is a usage error.
  • With no VAR_NAME, --value, or non-empty piped stdin, the CLI prints usage and exits 2.

API reference

Symbol Description
envbool(var, **opts) Read an environment variable and return bool.
to_bool(value, **opts) Coerce a string to bool.
set_defaults(**opts) Set process-level strict/warn/truthy/falsy defaults, replacing the built-ins.
get_defaults() Return the active Defaults.
reset_defaults() Restore built-in defaults.
Defaults Frozen dataclass: strict, warn, effective_truthy, effective_falsy.
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.

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 set_defaults()).
warn bool | None None Log a warning on unrecognized values (None defers to set_defaults()).
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

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

If your tests call set_defaults(), reset it between tests with an autouse fixture so overrides don't leak across the suite:

# conftest.py
import pytest
from envbool import reset_defaults


@pytest.fixture(autouse=True)
def _reset_envbool_defaults():
    yield
    reset_defaults()

Contributing

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

License

Released under the MIT License.

Metadata

Release files for envbool 0.4.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for envbool 0.4.2
File Size Uploaded
envbool-0.4.2.tar.gz 15.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for envbool 0.4.2
File Interpreter ABI Platform
envbool-0.4.2-py3-none-any.whl Python 3 none any Details

Total release size: 33.7 kB

Release files / envbool-0.4.2.tar.gz

Download URL envbool-0.4.2.tar.gz
Size 15.5 kB
Tags Source
SHA-256 checksum
How to use checksums
d9c7657d2565b350da9f3cec26656696de7661555855be3f1b3d3166877aa86e
BLAKE2b-256 checksum
How to use checksums
3b69ec361235b823b8c24ae5fe068f0a8a14164ddb1972f70530b11a183e60e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release files / envbool-0.4.2-py3-none-any.whl

Download URL envbool-0.4.2-py3-none-any.whl
Size 18.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
10f9b82b4418162acf3c56cce8997cf9b2e19f1816a2d8478de26707224c744c
BLAKE2b-256 checksum
How to use checksums
68bfeaf1094ecfd177fe8b7012a331c81fe56da9891fa04c590ab8f3fde02fd8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.0

2 release files

0.5.0

2 release files

This release

0.4.2 This release

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page