From ba62b167c66759a95fa2d7b0fd7609980a2f5aa9 Mon Sep 17 00:00:00 2001 From: Oliver Berger Date: Mon, 22 Feb 2021 23:29:14 +0100 Subject: [PATCH] fix: task factory was reset to early Task were not stacking context. --- .bumpversion.cfg | 2 +- VERSION | 2 +- setup.py | 2 +- src/buvar/__init__.py | 2 +- src/buvar/plugin.py | 36 ++++++++++++++++++------------------ tests/test_di.py | 27 +++++++++++++++++++++++++++ tests/test_plugin.py | 25 +++++++++++++++++++++++++ 7 files changed, 74 insertions(+), 22 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index a5a51d7..4f82dae 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.41.5 +current_version = 0.41.6 commit = False tag = False diff --git a/VERSION b/VERSION index fc4d6ca..63f3da2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.41.5 +0.41.6 diff --git a/setup.py b/setup.py index 7185605..24998f3 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ def finalize_options(self): setup_kwargs = { "name": "buvar", - "version": "0.41.5", + "version": "0.41.6", "description": "Asyncio plugins, components, dependency injection and configs", "long_description": description, "long_description_content_type": "text/x-rst", diff --git a/src/buvar/__init__.py b/src/buvar/__init__.py index 731ef28..3b0fddd 100644 --- a/src/buvar/__init__.py +++ b/src/buvar/__init__.py @@ -1,4 +1,4 @@ -__version__ = "0.41.5" +__version__ = "0.41.6" __version_info__ = tuple(__version__.split(".")) diff --git a/src/buvar/plugin.py b/src/buvar/plugin.py index cff2eeb..ca88f0e 100644 --- a/src/buvar/plugin.py +++ b/src/buvar/plugin.py @@ -191,30 +191,30 @@ async def run(tasks, *, evt_cancel=None): if evt_cancel is None: evt_cancel = context.add(Cancel()) - # we elevate context stack for tasks + # we automatically elevate context stack for tasks factory = context.set_task_factory() try: fut_tasks = asyncio.gather(*map(asyncio.create_task, tasks)) + + # stop staging if we finish in any way + fut_tasks.add_done_callback(lambda _: evt_cancel.set()) + + # wait for exit + await evt_cancel.wait() + + if not fut_tasks.done(): + # we were explicitelly stopped by cancel event + fut_tasks.cancel() + try: + await fut_tasks + except asyncio.CancelledError: + # silence our shutdown + pass + else: + return fut_tasks.result() finally: factory.reset() - # stop staging if we finish in any way - fut_tasks.add_done_callback(lambda _: evt_cancel.set()) - - # wait for exit - await evt_cancel.wait() - - if not fut_tasks.done(): - # we were explicitelly stopped by cancel event - fut_tasks.cancel() - try: - await fut_tasks - except asyncio.CancelledError: - # silence our shutdown - pass - else: - return fut_tasks.result() - def collect_plugin_args(plugin): hints = typing.get_type_hints(plugin) diff --git a/tests/test_di.py b/tests/test_di.py index 3b3885d..2ad602c 100644 --- a/tests/test_di.py +++ b/tests/test_di.py @@ -245,3 +245,30 @@ def adapt(cls, str: str) -> "Foo": foo = await adapters.nject(Foo) assert isinstance(foo, Foo) + + +@pytest.mark.asyncio +async def test_nject_deep_dependency_by_arg(adapters): + class Foo: + ... + + class Bar: + def __init__(self, foo): + self.foo = foo + + @classmethod + def adapt_foo(cls, foo: Foo) -> "Bar": + return cls(foo=foo) + + class Baz: + def __init__(self, bar): + self.bar = bar + + @classmethod + def adapt_bar(cls, bar: Bar) -> "Baz": + return cls(bar=bar) + + adapters.register(Bar.adapt_foo, Baz.adapt_bar) + + baz = await adapters.nject(Baz, foo=Foo()) + assert isinstance(baz, Baz) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 4b7e8b4..528a3be 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -11,6 +11,31 @@ def test_run(event_loop): assert e.value.args[1] == "foo_plugin" +def test_run_task_factory(event_loop): + import asyncio + from buvar import plugin, context + + async def prepare(): + async def task(): + async def _sub1(): + context.add("foo") + await asyncio.sleep(0) + assert "foo" == context.get(str) + + async def _sub2(): + context.add("bar") + await asyncio.sleep(0) + assert "bar" == context.get(str) + + await asyncio.gather( + asyncio.create_task(_sub1()), asyncio.create_task(_sub2()) + ) + + yield task() + + result = plugin.stage(prepare, loop=event_loop) + + def test_run_relative_out_of_packages(event_loop): from buvar import plugin