Asyncio plugins, components, dependency injection and configs
Project description
This is heavily inspired by Pyramid and my daily needs to fastly create and maintain microservice like applications.
a plugin mechanic
plugin may depend on other plugins
plugins yield tasks to run
a registry serves as a store for application components created by plugins
a dependency injection creates intermediate components
a config source is mapped to plugin specific needs
structlog boilerplate for json/tty logging
You bootstrap like following:
from buvar import plugin
plugin.stage("some.module.with.plugin.function")
# some.module.with.plugin.function
from buvar import context, plugin
class Foo:
...
async def task():
asyncio.sleep(1)
async def server():
my_component = context.get(Foo)
await asyncio.Future()
# you may omit include in arguments
async def prepare(load: plugin.Loader):
await load('.another.plugin')
# create some long lasting components
my_component = context.add(Foo())
# you may run simple tasks
yield task()
# you may run server tasks
yield server()
a components and dependency injection solution
Dependency injection relies on registered adapters, which may be a function, a method, a class, a classmethod or a generic classmthod.
Dependencies are looked up in components or may be provided via, arguments.
from buvar import di
class Bar:
pass
class Foo:
def __init__(self, bar: Bar = None):
self.bar = bar
@classmethod
async def adapt(cls, baz: str) -> Foo:
return Foo()
async def adapt(bar: Bar) -> Foo
foo = Foo(bar)
return foo
async def task():
foo = await di.nject(Foo, baz="baz")
assert foo.bar is None
bar = Bar()
foo = await di.nject(Foo, bar=bar)
assert foo.bar is bar
async def prepare():
di.register(Foo.adapt)
di.register(adapt)
a config source
buvar.config.ConfigSource is just a dict, which merges arbitrary dicts into one. It serves a the single source of truth for application variability.
You can load a section of config values into your custom attrs class instance. ConfigSource will override values by environment variables if present.
config.toml
log_level = "DEBUG"
show_warnings = "yes"
[foobar]
some = "value"
export APP_FOOBAR_SOME=thing
import attr
import toml
from buvar import config
@attr.s(auto_attribs=True)
class GeneralConfig:
log_level: str = "INFO"
show_warnings: bool = config.bool_var(False)
@attr.s(auto_attribs=True)
class FoobarConfig:
some: str
source = config.ConfigSource(toml.load('config.toml'), env_prefix="APP")
general_config = source.load(GeneralConfig)
assert general_config == GeneralConfig(log_level="DEBUG", show_warnings=True)
foobar_config = source.load(FoobarConfig, 'foobar')
assert foobar_config.some == "thing"
There is a shortcut to the above approach provided by buvar.config.Config, which requires to be subclassed from it with a distinct section attribute. If one adds a buvar.config.ConfigSource component, he will receive the mapped config in one call.
from buvar import config, plugin
@attr.s(auto_attribs=True)
class GeneralConfig(config.Config):
log_level: str = "INFO"
show_warnings: bool = config.bool_var(False)
@attr.s(auto_attribs=True)
class FoobarConfig(config.Config, section="foobar"):
some: str
async def prepare(load: plugin.Loader):
# this would by typically placed in the main entry point
source = context.add(config.ConfigSource(toml.load('config.toml'), env_prefix="APP"))
# to provide the adapter to di, which could also be done inthe main entry point
await load(config)
foobar_config = await di.nject(FoobarConfig)
a structlog
Just structlog boilerplate.
import sys
from buvar import log
log.setup_logging(sys.stdout.isatty(), general_config.log_level)
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 Distributions
Hashes for buvar-0.37.0-cp38-cp38-manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7bb912fd072c20bd4f7fecb4b4f08c298045a06c85f26a1d809db8ddf1e19c06 |
|
MD5 | 6ad208f6b2ad2e4975d06a19691ba577 |
|
BLAKE2b-256 | fad8d2ba87eaa5fd157f93b2458996645365d8af82f5e3d645a4bbd7b146a8d0 |
Hashes for buvar-0.37.0-cp37-cp37m-manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 33e94a10753e7c2c7eec0b616fc45ce2bc7a77fa3483c08107582652f0d2bd62 |
|
MD5 | 1a3b9fb1ad3d7b535b57c8b8546f6937 |
|
BLAKE2b-256 | 1a1717e3477588efb2808f9e205e3b24e012d4651cb2dcb35fd077ea2dcfb910 |