Skip to main content

Configuration with typed env vars

Project description

cabina

Codecov PyPI PyPI - Downloads Python Version

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

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cabina-1.1.2.tar.gz (22.2 kB view details)

Uploaded Source

Built Distribution

cabina-1.1.2-py3-none-any.whl (18.9 kB view details)

Uploaded Python 3

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

Hashes for cabina-1.1.2.tar.gz
Algorithm Hash digest
SHA256 91502936f2e75143403999be96bb199d4819825a462aabb8ffd2d8848b702bd5
MD5 37bc27316a6881930bf1b7a5804d888d
BLAKE2b-256 f542cb2fd18fb213823470ae5e6e40c3b68180e0e630f08fd836074e7fcbc7b9

See more details on using hashes here.

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

Hashes for cabina-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1be6c0b7e411d91af7bbe3c0315ea6e31251cbd24e9d7fa8e3c1b3c78b90eb63
MD5 7514e84626287831ff033e6895956794
BLAKE2b-256 54cc7db5582ec76688c65132265829ab56c1cea2d9f79755c91bd23a3762e61f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page