docs: enhance README.md with detailed examples and features for environment loader
fix: update version to 0.2.2 in setup.py feat: import json in env.py for future enhancements
This commit is contained in:
parent
be769153b3
commit
1e700a485d
98
README.md
98
README.md
@ -1,24 +1,104 @@
|
|||||||
# multinut
|
# `multinut`
|
||||||
|
|
||||||
The multitool nobody asked for. Includes stuff and so
|
The multitool nobody asked for. Includes stuff and so.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `multinut.env`
|
## `multinut.env`
|
||||||
|
|
||||||
A simple but flexible environment loader.
|
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.
|
Supports `.env` file parsing with optional mode suffixes (e.g. `.env.production`, `.env.testing`, etc.), lazy loading, and dynamic access.
|
||||||
|
|
||||||
Useful when:
|
### Features
|
||||||
|
|
||||||
* You want a single class that can load environment configs based on mode (`development`, `production`, etc.)
|
* Mode-based config support (`.env.production`, `.env.testing`, etc.)
|
||||||
* You need access via `env["KEY"]`, `env.get("KEY")`, or even `env.KEY`
|
* Access via:
|
||||||
* You want optional type casting and sane default handling
|
|
||||||
* You *don’t* want `os.environ` to be touched
|
* `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
|
### Use cases
|
||||||
|
|
||||||
* Loading `.env` files in mode-aware Python projects
|
* Loading `.env` files in mode-aware Python projects
|
||||||
* Separating secrets and configs by deployment context
|
* Separating secrets and configs by deployment context
|
||||||
* Dynamically reading values like `env.DB_URL`, `env.get("DEBUG", default=False, cast=bool)`
|
* Dynamically reading values like `env.DB_URL`, `env.get("DEBUG", default=False, cast=cast_bool)`
|
||||||
* Avoiding external dependencies beyond `python-dotenv`
|
* Avoiding `os.environ` pollution
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Basic Example
|
||||||
|
|
||||||
|
```python
|
||||||
|
from multinut.env 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 multinut.env import (
|
||||||
|
Environment, cast_bool, cast_int, cast_float,
|
||||||
|
cast_list, cast_tuple, cast_dict, cast_none_or_str
|
||||||
|
)
|
||||||
|
|
||||||
|
env = Environment()
|
||||||
|
|
||||||
|
print("INT:", env.get("PORT", cast=cast_int)) # -> int
|
||||||
|
print("FLOAT:", env.get("PI", cast=cast_float)) # -> float
|
||||||
|
print("BOOL:", env.get("ENABLED", cast=cast_bool)) # -> bool
|
||||||
|
print("LIST:", env.get("NUMBERS", cast=cast_list)) # -> list[str]
|
||||||
|
print("TUPLE:", env.get("WORDS", cast=cast_tuple)) # -> tuple[str]
|
||||||
|
print("DICT:", env.get("CONFIG", cast=cast_dict)) # -> dict
|
||||||
|
print("NONE_OR_STR:", env.get("OPTIONAL", cast=cast_none_or_str)) # -> None or str
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
### Included Cast Helpers
|
||||||
|
|
||||||
|
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` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import os.path as op
|
|||||||
from typing import Optional, Callable, Any
|
from typing import Optional, Callable, Any
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from dotenv import dotenv_values
|
from dotenv import dotenv_values
|
||||||
|
import json
|
||||||
|
|
||||||
NO_DEFAULT = object() # Used to indicate no default value was provided
|
NO_DEFAULT = object() # Used to indicate no default value was provided
|
||||||
|
|
||||||
|
|||||||
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='multinut',
|
name='multinut',
|
||||||
version='0.2.1.post1',
|
version='0.2.2',
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
install_requires=["dotenv"],
|
install_requires=["dotenv"],
|
||||||
author='Chipperfluff',
|
author='Chipperfluff',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user