- 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.
163 lines
4.0 KiB
Markdown
163 lines
4.0 KiB
Markdown
## `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 `.env` files 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.environ` pollution
|
|
|
|
---
|
|
|
|
### 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
|
|
|
|
```python
|
|
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:
|
|
|
|
```env
|
|
DEBUG=true
|
|
API_KEY=secret
|
|
DB_URL=https://example.com
|
|
```
|
|
|
|
---
|
|
|
|
### Smart Casts Example
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
from chipenv import TestEnv
|
|
|
|
env = TestEnv({"DEBUG": "true", "PORT": "8080"})
|
|
|
|
print(env.get("DEBUG")) # -> "true"
|
|
print(env["PORT"]) # -> "8080"
|
|
```
|
|
|
|
Example `.env`:
|
|
|
|
```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:
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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.")
|
|
|
|
---
|