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
- Source Code: https://github.com/eykd/convoke
- Issue Tracker: https://github.com/eykd/convoke/issues
License
The project is licensed under the BSD 3-clause license.
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 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
Algorithm | Hash digest | |
---|---|---|
SHA256 | c7b25a8bbaab5d1b4a365517ec71056ed771ea1c234de5e4b9162eb1211780eb |
|
MD5 | eb5c55175d68efe60c52b96f003cd866 |
|
BLAKE2b-256 | 8ac7610f995fce0c24f1916083b24fc3cc20f4978066b856101accdaa56f174c |
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
Algorithm | Hash digest | |
---|---|---|
SHA256 | ec9b0ea52c5cbde133537338436355f16cd237de0a5e1ab1f38e65d0a4034260 |
|
MD5 | c6dc359adb1115a67a4b6bf8cf1fd8f7 |
|
BLAKE2b-256 | 5c754c0df1dac5a8fb2e10cafd1d804017ce7f73a716153d892986d5e8aac49c |