Configuration with typed env vars
Project description
cabina
cabina is a Python library that simplifies building hierarchical, environment-driven configurations. It provides:
- Simple class-based configurations
- Automatic environment variable parsing
- Type-safe defaults
- Computed values
- Flexible customization
Installation
pip3 install cabina
Quick Start
Here’s a minimal example showing how cabina handles environment variables, defaults, and computed properties:
import cabina
from cabina import computed, env
class Config(cabina.Config):
class Main(cabina.Section):
API_HOST: str = env.str("API_HOST", default="localhost")
API_PORT: int = env.int("API_PORT", default=8080)
@computed
def API_URL(cls) -> str:
return f"http://{cls.API_HOST}:{cls.API_PORT}"
# Usage
assert Config.Main.API_URL == "http://localhost:8080"
assert Config["Main"]["API_URL"] == "http://localhost:8080"
# Print
print(Config)
# class <Config>:
# class <Main>:
# API_HOST = 'localhost'
# API_PORT = 8080
# API_URL = 'http://localhost:8080'
Recipes
Below are some common patterns and features you can use with cabina:
- Root Section
- Computed Values
- Default Values
- Raw Values
- Custom Parsers
- JSON Parser
- Lazy Env
- Env Vars Prefix
- Inheritance
Root Section
You can use cabina for simple, flat configurations by inheriting cabina.Section
in your main config:
export API_HOST=localhost
export API_PORT=8080
import cabina
from cabina import env
class Config(cabina.Config, cabina.Section): # Note the inheritance
API_HOST = env.str("API_HOST")
API_PORT = env.int("API_PORT")
assert Config.API_HOST == "localhost"
assert Config.API_PORT == 8080
Computed Values
You can define dynamic or derived config values via the @computed
decorator:
export API_HOST=localhost
export API_PORT=8080
import cabina
from cabina import computed, env
class Config(cabina.Config, cabina.Section):
API_HOST: str = env.str("API_HOST")
API_PORT: int = env.int("API_PORT")
@computed
def API_URL(cls) -> str:
return f"http://{cls.API_HOST}:{cls.API_PORT}"
assert Config.API_URL == "http://localhost:8080"
Default Values
Provide a default if an environment variable isn’t set:
export API_HOST=127.0.0.1
import cabina
from cabina import env
class Config(cabina.Config, cabina.Section):
API_HOST = env.str("API_HOST", default="localhost")
API_PORT = env.int("API_PORT", default=8080)
assert Config.API_HOST == "127.0.0.1"
assert Config.API_PORT == 8080
Raw Values
Get the raw, unprocessed string from an environment variable — even if it includes leading/trailing spaces:
export DEBUG=" yes"
import cabina
from cabina import env
class Config(cabina.Config, cabina.Section):
DEBUG_RAW = env.raw("DEBUG") # Same as env("DEBUG") without processing
DEBUG_STR = env.str("DEBUG") # Strips whitespace
assert Config.DEBUG_RAW == " yes" # The raw value includes whitespace
assert Config.DEBUG_STR == "yes" # Whitespace is stripped
Custom Parsers
Use custom parsing functions to handle special formats. For instance, parse a duration string with pytimeparse
:
export HTTP_TIMEOUT=10s
import cabina
from cabina import env
from pytimeparse import parse as parse_duration
class Config(cabina.Config, cabina.Section):
HTTP_TIMEOUT: int = env("HTTP_TIMEOUT", parser=parse_duration)
assert Config.HTTP_TIMEOUT == 10
JSON Parser
Easily load JSON data from an environment variable:
export IMAGE_SETTINGS='{"AllowedContentTypes": ["image/png", "image/jpeg"]}'
import json
import cabina
from cabina import env
class Config(cabina.Config, cabina.Section):
IMAGE_SETTINGS = env("IMAGE_SETTINGS", parser=json.loads)
assert Config.IMAGE_SETTINGS == {
"AllowedContentTypes": ["image/png", "image/jpeg"]
}
Lazy Env
Defer parsing environment variables until their first access. This can be useful if some variables may not exist at import time:
export DEBUG=yes
export API_PORT=80a # Contains an invalid int "80a"
import cabina
from cabina import lazy_env
class Config(cabina.Config, cabina.Section):
DEBUG = lazy_env.bool("DEBUG")
API_HOST = lazy_env.str("API_HOST") # Only fetched upon attribute access
API_PORT = lazy_env.int("API_PORT")
# Attempt to fetch all at once
Config.prefetch()
# Raises ConfigEnvError with:
# - Config.API_HOST: 'API_HOST' does not exist
# - Config.API_PORT: Failed to parse '80a' as int
Env Vars Prefix
Use a prefix for all your environment variables to avoid collisions:
export APP_HOST=localhost
export APP_PORT=8080
import cabina
env = cabina.Environment(prefix="APP_")
class Config(cabina.Config, cabina.Section):
API_HOST = env.str("HOST") # 'APP_HOST' will be used
API_PORT = env.int("PORT") # 'APP_PORT' will be used
assert Config.API_HOST == "localhost"
assert Config.API_PORT == 8080
Inheritance
Create a base configuration and extend it for local or specialized use cases:
import cabina
class Config(cabina.Config, cabina.Section):
DEBUG = False
class Api(cabina.Section):
API_HOST = "app.dev"
API_PORT = 5000
class ConfigLocal(Config):
DEBUG = True
class Api(Config.Api):
API_HOST = "localhost"
assert ConfigLocal.DEBUG is True
assert ConfigLocal.Api.API_HOST == "localhost"
assert ConfigLocal.Api.API_PORT == 5000
Contributing
Contributions, bug reports, and feature requests are welcome! Feel free to open an issue or submit a pull request.
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
File details
Details for the file cabina-1.1.2.tar.gz
.
File metadata
- Download URL: cabina-1.1.2.tar.gz
- Upload date:
- Size: 22.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.12.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 91502936f2e75143403999be96bb199d4819825a462aabb8ffd2d8848b702bd5 |
|
MD5 | 37bc27316a6881930bf1b7a5804d888d |
|
BLAKE2b-256 | f542cb2fd18fb213823470ae5e6e40c3b68180e0e630f08fd836074e7fcbc7b9 |
File details
Details for the file cabina-1.1.2-py3-none-any.whl
.
File metadata
- Download URL: cabina-1.1.2-py3-none-any.whl
- Upload date:
- Size: 18.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.12.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1be6c0b7e411d91af7bbe3c0315ea6e31251cbd24e9d7fa8e3c1b3c78b90eb63 |
|
MD5 | 7514e84626287831ff033e6895956794 |
|
BLAKE2b-256 | 54cc7db5582ec76688c65132265829ab56c1cea2d9f79755c91bd23a3762e61f |