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 context 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 configuration and may be fully overridden by environment vars
- structlog boilerplate for json/tty logging
You bootstrap like following:
from buvar import plugin plugin.stage("some.module.with.prepare")
# some.module.with.prepare from buvar import context, plugin class Foo: ... async def task(): asyncio.sleep(1) async def server(): my_component = context.get(Foo) await asyncio.Future() # there is also plugin.Teardown and plugin.Cancel 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 kwargs.
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) yield task()
a config source
buvar.config.ConfigSource is just a dict, which merges arbitrary dicts into one. It serves as 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 CLI 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 in the main entry point await load(config) foobar_config = await di.nject(FoobarConfig)
a structlog
Just structlog boilerplate.
import sys from buvar import log log_config = log.LogConfig(tty=sys.stdout.isatty(), level="DEBUG") log_config.setup()
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.
Filename, size | File type | Python version | Upload date | Hashes |
---|---|---|---|---|
Filename, size buvar-0.41.6-cp37-cp37m-manylinux2014_x86_64.whl (512.2 kB) | File type Wheel | Python version cp37 | Upload date | Hashes View |
Filename, size buvar-0.41.6-cp38-cp38-manylinux2014_x86_64.whl (575.1 kB) | File type Wheel | Python version cp38 | Upload date | Hashes View |
Filename, size buvar-0.41.6-cp39-cp39-manylinux2014_x86_64.whl (557.3 kB) | File type Wheel | Python version cp39 | Upload date | Hashes View |
Filename, size buvar-0.41.6.tar.gz (128.8 kB) | File type Source | Python version None | Upload date | Hashes View |
Hashes for buvar-0.41.6-cp37-cp37m-manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e76986d69e54e16ba2fddd1a7654af51f9b0a0d090cb97cf9b12960ff117a267 |
|
MD5 | 4191580f3c1b5b4355867662ec9e971b |
|
BLAKE2-256 | ce47cf9006b94eddf8513b3cfbc1894418c368d46364e5b79f7533dcec33038d |
Hashes for buvar-0.41.6-cp38-cp38-manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 19ece5b026389dce9b9696ae733356687ed78c4a47f105cce3538896964fb228 |
|
MD5 | a962596db5a0546367a3651dd72cde9b |
|
BLAKE2-256 | 91c40ddef7ab61c7ff773c60ae841cdf992042aa7f175a6354e5ad148b6cda78 |
Hashes for buvar-0.41.6-cp39-cp39-manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c60bd336fb4e449dab1766d6bf9affc6b9873a4932c30d3dd4de561fca245fdb |
|
MD5 | e0ad177c7a06297211e2c1671136d3b8 |
|
BLAKE2-256 | 8d77890e7fa0554bc82b24faa137d6e0e7ab3bdb12458096c32eaa564aab7ec1 |