Skip to main content

Typed, dependency-free environment variable loading: read env vars as int/bool/list/json/Path with defaults, required-checks, and clear errors.

Project description

envcaster ⚙️

Read environment variables as the type you actually wantint, bool, list, json, Path — with defaults, required-checks, and errors that name the offending variable. Zero dependencies, pure standard library.

CI PyPI Python License: MIT

os.environ only ever gives you strings. So every project grows the same little pile of int(os.environ.get("PORT", "8000")) and hand-rolled truthy checks that quietly treat "False" as True. envcaster is that pile, done once and done right.

  • 🪶 Zero required dependencies — pure standard library.
  • 🎯 Typed gettersstr · int · float · bool · list · json · path (+ custom cast).
  • 🧯 Loud, precise errors — missing or malformed values tell you which variable and why.
  • 🧪 Fully tested across Python 3.9–3.12.
  • 🧩 Drop-in .env loader that never clobbers real environment config.

Install

pip install envcaster

Quick start

from envcaster import env

PORT    = env.int("PORT", default=8000)
DEBUG   = env.bool("DEBUG", default=False)
HOSTS   = env.list("ALLOWED_HOSTS", sep=",")          # ["a", "b"] from "a,b"
TIMEOUT = env.float("TIMEOUT", default=1.5)
SECRET  = env.str("SECRET_KEY", required=True)         # raises if not set
DATA    = env.path("DATA_DIR", default="/var/data")   # -> pathlib.Path
FLAGS   = env.json("FEATURE_FLAGS", default={})        # parsed JSON

A variable is required unless you give it a default. Missing required variables raise MissingEnvError; bad values raise CastError. Both subclass EnvError — catch broadly or narrowly.


Usage

Booleans that actually behave

env.bool("DEBUG")     # 1 true t yes y on  -> True   (case-insensitive)
                      # 0 false f no n off -> False
                      # anything else      -> CastError

No more bool("False") == True bugs.

Lists (and lists of other types)

env.list("ALLOWED_HOSTS")                 # "a, b ,, c" -> ["a", "b", "c"]  (trims, drops empties)
env.list("PORTS", sep=":", cast=int)      # "80:443"    -> [80, 443]
env.list("TAGS", default=[])              # missing     -> []

JSON and paths

env.json("LIMITS")          # '{"rpm": 60}' -> {"rpm": 60}
env.path("LOG_DIR")         # "/var/log"    -> PosixPath("/var/log")

Anything else — bring your own cast

from decimal import Decimal

env.cast("PRICE", Decimal)                 # "9.99" -> Decimal("9.99")
env.cast("COLOR", lambda v: int(v, 16))    # "ff0000" -> 16711680
# exceptions from your function are wrapped in CastError, naming the variable

Scoped readers with a prefix

from envcaster import Env

app = Env(prefix="APP_")
app.int("PORT")        # reads APP_PORT
app.bool("DEBUG")      # reads APP_DEBUG

Read from somewhere other than os.environ

cfg = Env(source={"PORT": "9000"})   # great for tests — no global state
cfg.int("PORT")                       # 9000

Load a .env file (no dependency)

from envcaster import load_dotenv, env

load_dotenv()                  # reads ./.env into os.environ (won't override real env vars)
load_dotenv(".env.local", override=True)

PORT = env.int("PORT")

# Or parse without touching the environment:
from envcaster import read_dotenv
values = read_dotenv(".env")   # -> {"PORT": "8000", ...}

Handles KEY=value, export KEY=value, # comments, and quoted values. For interpolation or multiline values, use python-dotenv.


API reference

Call Returns Notes
env.str(name, default=…, required=False) str The raw value, unchanged
env.int(name, …) int Base-10, whitespace stripped
env.float(name, …) float
env.bool(name, …) bool 1/true/t/yes/y/on0/false/f/no/n/off
env.list(name, …, sep=",", cast=str) list Trims items, drops empties, per-item cast
env.json(name, …) Any json.loads of the value
env.path(name, …) pathlib.Path Not resolved/validated
env.cast(name, func, …) Any Apply any callable; errors wrapped in CastError
Env(source=None, prefix="") Env Custom mapping and/or name prefix
read_dotenv(path=".env") dict Parse a .env file; {} if absent
load_dotenv(path=".env", override=False) dict Inject into os.environ

Errors: EnvError (base) · MissingEnvError (also KeyError) · CastError (also ValueError).


Why not just os.environ?

# Before
import os
PORT  = int(os.environ.get("PORT", "8000"))
DEBUG = os.environ.get("DEBUG", "false").lower() in ("1", "true", "yes")
HOSTS = [h.strip() for h in os.environ.get("ALLOWED_HOSTS", "").split(",") if h.strip()]

# After
from envcaster import env
PORT  = env.int("PORT", default=8000)
DEBUG = env.bool("DEBUG", default=False)
HOSTS = env.list("ALLOWED_HOSTS", default=[])

Development

git clone https://github.com/YoungAlpaccino/envcast
cd envcast
pip install -e ".[dev]"
pytest          # run tests
ruff check .    # lint

License

MIT — see LICENSE. Use it anywhere, including commercially.

Project details


Download files

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

Source Distribution

envcaster-0.1.0.tar.gz (12.2 kB view details)

Uploaded Source

Built Distribution

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

envcaster-0.1.0-py3-none-any.whl (9.0 kB view details)

Uploaded Python 3

File details

Details for the file envcaster-0.1.0.tar.gz.

File metadata

  • Download URL: envcaster-0.1.0.tar.gz
  • Upload date:
  • Size: 12.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for envcaster-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a7553b39c5b345974195557a3088762b7d019c83004924396140b04622358bd2
MD5 658232643d6964bbcdd264f88af1f534
BLAKE2b-256 2cb04861a8ccae2332841c5a9066f2168f73551328198269ffabe110d9bbd4bc

See more details on using hashes here.

File details

Details for the file envcaster-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: envcaster-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for envcaster-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f35a235a14fc1dcb2f355aafb3187d15997493c09597789e5e8520a273a213ce
MD5 5c40c42a5d8d394fb001dbf8a91ada59
BLAKE2b-256 f89679fbf0dab27b6214aaf4bcd72555985d573f8d0fff89a455d027cc8db6df

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 Pingdom Monitoring Sentry Error logging StatusPage Status page