- Introduced `Environment`, `EnvShared`, and `TestEnv` classes for managing environment variables. - Added casting functions for various data types in a new `cast.py` module. - Updated README with usage examples and class descriptions.
4.0 KiB
4.0 KiB
chipenv
A simple but flexible environment loader.
Supports .env file parsing with optional mode suffixes (e.g. .env.production, .env.testing, etc.), lazy loading, and dynamic access.
Features
-
Mode-based config support (
.env.production,.env.testing, etc.) -
Access via:
env["KEY"]env.get("KEY", ...)env.KEY
-
Optional type casting (
str,bool,list,dict, etc.) -
Sane default handling
-
Does not mutate
os.environ
Use cases
- Loading
.envfiles in mode-aware Python projects - Separating secrets and configs by deployment context
- Dynamically reading values like
env.DB_URL,env.get("DEBUG", default=False, cast=cast_bool) - Avoiding
os.environpollution
When to use which class
Environment: default choice for most apps; new instance per config.EnvShared: use when you want a single shared instance across the process (legacy singleton behavior).TestEnv: use for tests/fixtures when you want to inject a dict and skip file I/O.
Basic Example
from chipenv import Environment, Modes
env = Environment(env_file_name=".env", mode=Modes.DEVELOPMENT)
print(env.get("DEBUG", default=False))
print(env["API_KEY"])
print(env.DB_URL)
Given a .env.development file:
DEBUG=true
API_KEY=secret
DB_URL=https://example.com
Smart Casts Example
from chipenv import Environment, cast
env = Environment()
print("INT:", env.get("PORT", cast=cast.cast_int)) # -> int
print("FLOAT:", env.get("PI", cast=cast.cast_float)) # -> float
print("BOOL:", env.get("ENABLED", cast=cast.cast_bool)) # -> bool
print("LIST:", env.get("NUMBERS", cast=cast.cast_list)) # -> list[str]
print("TUPLE:", env.get("WORDS", cast=cast.cast_tuple)) # -> tuple[str]
print("DICT:", env.get("CONFIG", cast=cast.cast_dict)) # -> dict
print("NONE_OR_STR:", env.get("OPTIONAL", cast=cast.cast_none_or_str)) # -> None or str
Singleton Example
from chipenv import EnvShared, Modes
env_a = EnvShared(env_file_name=".env", mode=Modes.LOCAL)
env_b = EnvShared(env_file_name=".env", mode=Modes.LOCAL)
print(env_a is env_b) # -> True
Test/Fixture Example
from chipenv import TestEnv
env = TestEnv({"DEBUG": "true", "PORT": "8080"})
print(env.get("DEBUG")) # -> "true"
print(env["PORT"]) # -> "8080"
Example .env:
PORT=8080
PI=3.1415
ENABLED=yes
NUMBERS=1,2,3
WORDS=hello,world,test
CONFIG={"timeout": 30, "debug": true}
OPTIONAL=null
Common errors and handling
Missing key with no default:
from chipenv import Environment, EnviromentKeyMissing
env = Environment(suppress_file_not_found=True)
try:
env.get("MISSING_KEY")
except EnviromentKeyMissing as exc:
print(exc)
Missing .env file:
from chipenv import Environment
try:
env = Environment(env_file_name=".env", mode="missing")
except FileNotFoundError as exc:
print(exc)
Included Cast Helpers
Import them via from chipenv import cast and use cast.cast_int(...), etc.
All built-in cast functions handle common edge cases:
| Cast Function | Description |
|---|---|
cast_str |
Ensures string |
cast_int |
Converts to integer |
cast_float |
Converts to float |
cast_bool |
Accepts 1, true, yes, on, etc. |
cast_list |
Comma-split list |
cast_tuple |
Comma-split, converted to tuple |
cast_dict |
Parses JSON string into dictionary |
cast_none_or_str |
Returns None if value is null or None |
EnviromentKeyMissing
if a key is get from env.get and it has no default given it will raise
EnviromentKeyMissing(f"Environment variable '{key}' not found.")