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.

License

This project is licensed under the MIT License.


Happy configuring with cabina!

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.0.tar.gz (18.5 kB view details)

Uploaded Source

Built Distribution

cabina-1.1.0-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file cabina-1.1.0.tar.gz.

File metadata

  • Download URL: cabina-1.1.0.tar.gz
  • Upload date:
  • Size: 18.5 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.0.tar.gz
Algorithm Hash digest
SHA256 ec5daa2a82336843c499d8fbc9e7facad1ec37dab533abb3d4b9f344a495a08f
MD5 dab2b478feb325c02a9b5795b784f1a2
BLAKE2b-256 592b25b6df14b287868b0da2ca489fa332a996c84e9d948f5c9c000548497444

See more details on using hashes here.

File details

Details for the file cabina-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: cabina-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.3 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4375dab29deec0b688bd5d4b1eb11364a5da38a8dd78967076ea0b648c6e4cd3
MD5 149758105ed9b1e83646ebc2aa627c70
BLAKE2b-256 3f9be6eab2d6b1b47011adfe02fdc501dbcc7ad379a79c7532036cf8058308d9

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