Skip to main content

envgate

CI codecov PyPI version Python License: MIT

A minimal Python library to validate environment variables at startup. Zero dependencies.

Why?

Instead of your app crashing at runtime because DATABASE_URL is missing, envgate validates everything at startup and tells you exactly what's wrong.

Installation

pip install envgate

Quick Start

from envgate import get_env, validate

# Get a single variable with type coercion
port = get_env("PORT", type="int", default=8000)
debug = get_env("DEBUG", type="bool", default=False)

# Explicitly mark a variable as required
api_key = get_env("API_KEY", required=True)

# Parse comma-separated lists (or use a custom separator)
hosts = get_env("ALLOWED_HOSTS", type="list")            # ["a", "b", "c"]
ports = get_env("PORTS", type="list[int]", sep=":")      # [8000, 8001]

# Or validate multiple variables at once
config = validate({
    "DATABASE_URL": {"type": "str"},
    "REDIS_URL": {"type": "str"},
    "PORT": {"type": "int", "default": 8000},
    "DEBUG": {"type": "bool", "default": False},
})

If DATABASE_URL and REDIS_URL are missing and PORT is invalid, you get all errors at once:

envgate.exceptions.ValidationError: Environment validation failed:
    - Environment variable 'DATABASE_URL' is not set.
    - Environment variable 'REDIS_URL' is not set.
    - Environment variable 'PORT' has invalid value 'abc' (expected int).

Custom validators

Type coercion checks that PORT is an integer. A validator checks that the value also makes sense — e.g. that the port is in a usable range, or that a log level is one of a fixed set:

def in_port_range(p):
    if not (1024 <= p <= 65535):
        raise ValueError("must be in [1024, 65535]")

def is_known_level(level):
    if level not in {"debug", "info", "warning", "error"}:
        raise ValueError("must be one of debug|info|warning|error")

config = validate({
    "PORT": {"type": "int", "validator": in_port_range},
    "LOG_LEVEL": {"type": "str", "default": "info", "validator": is_known_level},
})

A validator signals failure by raising any exception — its message is captured and joined into the same collective ValidationError as missing and invalid-type errors:

envgate.exceptions.ValidationError: Environment validation failed:
    - Environment variable 'PORT' has invalid value '80': must be in [1024, 65535]
    - Environment variable 'LOG_LEVEL' has invalid value 'verbose': must be one of debug|info|warning|error

Loading a .env file

For local development, load variables from a .env file before validating. load_env() copies the file's entries into os.environ, so validate() picks them up with no extra wiring:

from envgate import load_env, validate

load_env()  # reads ./.env into os.environ (defaults to ".env")

config = validate({
    "DATABASE_URL": {"type": "str"},
    "PORT": {"type": "int", "default": 8000},
})

Given a .env like:

# database
DATABASE_URL=postgres://localhost/app
PORT=5432
export DEBUG="true"
  • Real environment variables always win. A key already set in the environment (CI, containers, systemd) is never overwritten by the file.
  • A missing file is a silent no-op — handy in production, where you rely on real environment variables and ship no .env. A file that exists but has a broken line raises EnvFileError.
  • load_env() returns a dict of everything it parsed from the file, so you can log or inspect it without touching global state.

Parsing is stdlib-only and deliberately simple: blank lines and full-line # comments are skipped, a leading export is tolerated, surrounding quotes are stripped, and there's no shell-style interpolation.

Supported Types

Type Example values
str Any string (default)
int "42", "-7", "0"
float "3.14", "42", "-2.5"
bool "true", "1", "yes", "on" / "false", "0", "no", "off"
list, list[str], list[int], list[float], list[bool] Comma-separated values — e.g. "a,b,c"["a", "b", "c"]. Pass sep=":" (or any character) to override the separator.

Contributing

Contributions are welcome! Check out the CONTRIBUTING.md for guidelines.

License

MIT

Download files

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

Source Distribution

envgate-0.7.0.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

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

envgate-0.7.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file envgate-0.7.0.tar.gz.

File metadata

  • Download URL: envgate-0.7.0.tar.gz
  • Upload date:
  • Size: 11.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for envgate-0.7.0.tar.gz
Algorithm Hash digest
SHA256 b80c7534528c6e2581ff7f2fc0cb67a7df5b4a2b85fea97164e6a73a70fb656b
MD5 b942e5c201767b73794f8a54ab745ec0
BLAKE2b-256 c5c8f98ee41ff4b7643bb4ad8d0ac9ee23064b42a134efcc43559d40c8c348dc

See more details on using hashes here.

File details

Details for the file envgate-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: envgate-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for envgate-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 451d77e8dbf2dd71bfb68144264c59716ec4333555117b467f0d98cf223c4022
MD5 db447143c7ca37180286255c457c6f7e
BLAKE2b-256 c2785a6caca7b8d12b53f35221271e2ea27b5a88c8210d6a65b0bdf119f9c1f9

See more details on using hashes here.

Supported by

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