Zero-dependency typed environment variable loader for Python
Project description
specenv
Zero-dependency typed environment variable loader for Python
The Problem
Reading environment variables in plain Python is verbose, fragile, and produces cryptic errors at runtime:
import os
PORT = int(os.environ.get("PORT", "8080"))
DEBUG = os.environ.get("DEBUG", "false").lower() in ("1", "true", "yes")
TIMEOUT = float(os.environ.get("TIMEOUT", "30.0"))
HOSTS = [h.strip() for h in os.environ.get("ALLOWED_HOSTS", "").split(",") if h.strip()]
# If PORT is "abc" you get:
# ValueError: invalid literal for int() with base 10: 'abc'
# — no variable name, no hint on how to fix it.
The Solution
import specenv
PORT = specenv.get("PORT", default=8080, cast=int)
DEBUG = specenv.get("DEBUG", default=False, cast=bool)
TIMEOUT = specenv.get("TIMEOUT", default=30.0, cast=float)
HOSTS = specenv.get("ALLOWED_HOSTS", default=[], cast=list)
# If PORT is "abc" you get:
# EnvCastError: Cannot cast PORT="abc" to int.
# → Set PORT to a valid integer (e.g. PORT=8080)
Install
pip install specenv
Python 3.10+ required. No runtime dependencies.
Usage
Simple get
import specenv
PORT = specenv.get("PORT", default=8080, cast=int)
DEBUG = specenv.get("DEBUG", default=False, cast=bool)
TIMEOUT = specenv.get("TIMEOUT", default=30.0, cast=float)
HOSTS = specenv.get("ALLOWED_HOSTS", default=[], cast=list) # list[str]
PORTS = specenv.get("PORTS", default=[8080], cast=list[int]) # list[int]
When default is omitted and the variable is not set, EnvCastError is
raised immediately.
Bool casting
| Environment value | Result |
|---|---|
1, true, yes, on |
True |
0, false, no, off |
False |
| anything else | EnvCastError |
Matching is case-insensitive (TRUE, Yes, ON all work).
Schema-based loading
Group all variables into a single class for easier testing and injection:
from specenv import Schema, Var
class AppConfig(Schema):
PORT = Var(int, default=8080)
DEBUG = Var(bool, default=False)
DB_URL = Var(str, required=True)
TIMEOUT = Var(float, default=30.0)
ALLOWED_IPS = Var(list[str], default=[])
config = AppConfig.load()
print(config.PORT) # 8080 (or whatever PORT is set to)
Pass a plain dict to load() in tests to avoid touching the real environment:
cfg = AppConfig.load(env={"DB_URL": "sqlite:///test.db"})
Validation
PORT = specenv.get(
"PORT",
cast=int,
validate=lambda v: 1 <= v <= 65535,
)
Or inside a Schema:
class Config(Schema):
PORT = Var(int, default=8080, validate=lambda v: 1 <= v <= 65535)
Namespace / prefix
db = specenv.namespace("DB_")
HOST = db.get("HOST", default="localhost") # reads DB_HOST
PORT = db.get("PORT", default=5432, cast=int) # reads DB_PORT
cache = specenv.namespace("CACHE_")
URL = cache.get("URL", default="redis://localhost:6379") # reads CACHE_URL
Error Messages
Every error is designed to tell you what went wrong and how to fix it.
EnvCastError: Cannot cast PORT="abc" to int.
→ Set PORT to a valid integer (e.g. PORT=8080)
EnvCastError: Required variable DB_URL is not set.
→ Add DB_URL to your environment or .env file.
EnvValidationError: PORT=99999 failed validation (must satisfy the provided lambda).
API Reference
| Symbol | Description |
|---|---|
specenv.get(name, *, default, cast, validate) |
Read and optionally cast one variable |
specenv.namespace(prefix) |
Return a Namespace that prepends prefix to every key |
specenv.reset() |
Reset internal state (no-op in 0.1.0; safe to call in teardowns) |
Schema |
Base class for declarative config |
Var(cast_type, *, default, required, validate) |
Field descriptor used inside a Schema |
Namespace |
Prefix-scoped view returned by namespace() |
EnvCastError |
Raised on missing required variable or bad cast |
EnvValidationError |
Raised when a validate callable returns False |
Supported cast types: int, float, bool, str, list,
list[int], list[float], list[str], pathlib.Path, and any
list[T] where T is one of the above.
Contributing
Bug reports and pull requests are welcome on the GitHub issues page. Please open an issue before starting large changes so we can discuss the approach first.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file specenv-0.1.0.tar.gz.
File metadata
- Download URL: specenv-0.1.0.tar.gz
- Upload date:
- Size: 10.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7a4b747e10d10dfbc958fe3d6bd92055fddf232b7fcfe36464083feca37079dc
|
|
| MD5 |
08a1934b947f58bdfc01e8a021f75d7f
|
|
| BLAKE2b-256 |
33f9c4706e2fcc999e6c2b4fdaf291861d1d9b0c4da96ef83c8b75af22682815
|
Provenance
The following attestation bundles were made for specenv-0.1.0.tar.gz:
Publisher:
publish.yml on abhijatchaturvedi/envspec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
specenv-0.1.0.tar.gz -
Subject digest:
7a4b747e10d10dfbc958fe3d6bd92055fddf232b7fcfe36464083feca37079dc - Sigstore transparency entry: 1708070212
- Sigstore integration time:
-
Permalink:
abhijatchaturvedi/envspec@c887dae728b6432de3550ec09e7f23bdf2f3db16 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/abhijatchaturvedi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c887dae728b6432de3550ec09e7f23bdf2f3db16 -
Trigger Event:
release
-
Statement type:
File details
Details for the file specenv-0.1.0-py3-none-any.whl.
File metadata
- Download URL: specenv-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
becebea0d967d37db23f0ba6944a0b000b8f587537e856a7a6e660547980ea5b
|
|
| MD5 |
d6ba769b18f7876c05c9e3f39114f594
|
|
| BLAKE2b-256 |
0b22caaf87474fb813cc410083a57b49d9ae66c30449e5931323c75b698c018f
|
Provenance
The following attestation bundles were made for specenv-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on abhijatchaturvedi/envspec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
specenv-0.1.0-py3-none-any.whl -
Subject digest:
becebea0d967d37db23f0ba6944a0b000b8f587537e856a7a6e660547980ea5b - Sigstore transparency entry: 1708070229
- Sigstore integration time:
-
Permalink:
abhijatchaturvedi/envspec@c887dae728b6432de3550ec09e7f23bdf2f3db16 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/abhijatchaturvedi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c887dae728b6432de3550ec09e7f23bdf2f3db16 -
Trigger Event:
release
-
Statement type: