Skip to main content

A Python app configuration toolkit that tries to do things right.

Project description

Convoke

A decentralized async-first app configuration toolkit that tries to do things right.

from convoke.configs import BaseConfig, env_field
from convoke.bases import Base

class ComponentConfig(BaseConfig):
# Get your stuff done
project.do_stuff()

Features

  • Type-safe, environment-based configuration
  • Decentralized app configurations

Installation

With Pip:

pip install convoke

Configuration

Configurations are modular, inspired by Python's dataclasses module:

>>> from convoke.configs import BaseConfig, env_field

>>> class CacheConfig(BaseConfig):
...     """Configuration for the caching framework."""
...
...     CACHE_STORAGE_URI: str = env_field(
...         default="memory://",
...         doc="""A configuration URI pointing to the desired cache backend.
...
...         For instance, for a simple Redis-based cache, use:
...
...             redis://localhost:6379/mycachepath
...         """,
...     )
...

In this example, instantiating CacheConfig() will read CACHE_STORAGE_URI from the process environment (os.environ), defaulting to 'memory://' if nothing is defined.

Rather than defining one singular configuration (e.g. Django's settings.py), convoke encourages defining modular, limited-scope configurations close to where the settings will be used.

Configuration discovery & .env files

In order to discover what configuration values an application needs, convoke provides a .env file generator:

>>> from convoke.configs import generate_dot_env

>>> print(generate_dot_env(BaseConfig.gather_settings()))
################################
## convoke.configs.BaseConfig ##
################################
##
## Base settings common to all configurations

# ------------------
# -- DEBUG (bool) --
# ------------------
#
# Development mode?

DEBUG=""

# --------------------
# -- TESTING (bool) --
# --------------------
#
# Testing mode?

TESTING=""


##########################
## __main__.CacheConfig ##
##########################
##
## Configuration for the caching framework.

# -----------------------------
# -- CACHE_STORAGE_URI (str) --
# -----------------------------
#
# A configuration URI pointing to the desired cache backend.
#
# For instance, for a simple Redis-based cache, use:
#
#     redis://localhost:6379/mycachepath

CACHE_STORAGE_URI="memory://"

Modular apps & signals

Inspired by Django's AppConfig, convoke provides an abstraction called "bases":

In foo.py:

from convoke.bases import Base
from convoke.configs import BaseConfig, env_field
from convoke.signals import Signal


class FOO(Signal):
    pass


class FooConfig(BaseConfig):
    BAR: str = env_field(default="baz")


class Main(Base):
    config_class = FooConfig

    foos: list[FOO.Message] = Base.field(init=False)

    # Circular dependency!
    dependencies = ["baz"]

    def on_init(self):
        self.foos = []

    @Base.responds(FOO)
    def on_foo(self, obj: FOO.Message):  # pragma: nocover
        self.foos.append(obj)

In bar.py:

from convoke.bases import Base
from convoke.signals import Signal


class BAR(Signal):
    pass


class Main(Base):
    dependencies = ["baz"]

    bars: list[BAR.Message] = Base.field(default_factory=list)

    @Base.responds(BAR)
    async def on_bar(self, obj):  # pragma: nocover
        self.bars.append(obj)

In baz.py:

from typing import Callable

from convoke.bases import Base
from convoke.mountpoints import Mountpoint
from convoke.signals import Signal


class BAZ(Signal):
    pass


class ThingyMadoodle(Mountpoint):
    pass


class Main(Base):
    # Circular dependency!
    dependencies = ["foo"]

    things: list[str] = Base.field(default_factory=list)
    other_things: list[str] = Base.field(default_factory=list)

    @Base.responds(BAZ)
    def on_baz(self, obj: BAZ.Message):
        for thinger in self.thingers:
            thinger(obj.value)

    @property
    def thingers(self) -> list[Callable[[str], None]]:
        return list(self.hq.mountpoints[ThingyMadoodle].mounted)

    @ThingyMadoodle.register
    def do_a_thing(self, value):
        self.things.append(value)

    @ThingyMadoodle.register
    def do_another_thing(self, value):
        self.other_things.append(value)

Each Base provides a platform for building a modular app upon, with interdependencies between Bases. Dependencies are allowed to be circular, because bases are instantiated separately from import time by the "main base" known as the HQ:

>>> hq = HQ(config=config)

>>> hq.load_dependencies(dependencies=["foo", "bar"])

The HQ manages loading and instantiating bases, connecting signal handlers, etc. The main application can maintain a reference to the HQ. The HQ class also maintains an HQ.current_hq context variable which contains a reference to the HQ instance for the current thread, if one exists.

Signals

Convoke signals are presently async-only.

Unlike most signals frameworks (e.g. blinker or Django), signals are not global. Instead, signals are passed within the network of bases established by the HQ:

>>> from foo import FOO

>>> await FOO.send(value='blah', using=hq)

>>> await FOO.send(value='blah')  # <-- uses HQ.current_hq

Contribute

License

The project is licensed under the BSD 3-clause license.

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

convoke-2.2.9.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

convoke-2.2.9-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

Details for the file convoke-2.2.9.tar.gz.

File metadata

  • Download URL: convoke-2.2.9.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.7 Linux/6.2.0-1019-azure

File hashes

Hashes for convoke-2.2.9.tar.gz
Algorithm Hash digest
SHA256 c7b25a8bbaab5d1b4a365517ec71056ed771ea1c234de5e4b9162eb1211780eb
MD5 eb5c55175d68efe60c52b96f003cd866
BLAKE2b-256 8ac7610f995fce0c24f1916083b24fc3cc20f4978066b856101accdaa56f174c

See more details on using hashes here.

File details

Details for the file convoke-2.2.9-py3-none-any.whl.

File metadata

  • Download URL: convoke-2.2.9-py3-none-any.whl
  • Upload date:
  • Size: 17.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.7 Linux/6.2.0-1019-azure

File hashes

Hashes for convoke-2.2.9-py3-none-any.whl
Algorithm Hash digest
SHA256 ec9b0ea52c5cbde133537338436355f16cd237de0a5e1ab1f38e65d0a4034260
MD5 c6dc359adb1115a67a4b6bf8cf1fd8f7
BLAKE2b-256 5c754c0df1dac5a8fb2e10cafd1d804017ce7f73a716153d892986d5e8aac49c

See more details on using hashes here.

Supported by

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