From 88125aa744f31e9304eff8a5142a7efb0965bc06 Mon Sep 17 00:00:00 2001 From: Andrew Srg Date: Thu, 1 Feb 2024 21:27:58 +0200 Subject: [PATCH 1/3] add litestar integration example --- examples/litestar_app.py | 70 +++++++++++++++++++++++++++++ src/dishka/integrations/litestar.py | 51 +++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 examples/litestar_app.py create mode 100644 src/dishka/integrations/litestar.py diff --git a/examples/litestar_app.py b/examples/litestar_app.py new file mode 100644 index 00000000..6a43b193 --- /dev/null +++ b/examples/litestar_app.py @@ -0,0 +1,70 @@ +import logging +from abc import abstractmethod +from typing import Protocol, Annotated + +import uvicorn +from litestar import Controller, get, Litestar + +from dishka import Provider, Scope, provide +from dishka.integrations.base import Depends +from dishka.integrations.litestar import inject, setup_dishka, startup_dishka, make_container_before_request, \ + shutdown_dishka + + +# app core +class DbGateway(Protocol): + @abstractmethod + def get(self) -> str: + raise NotImplementedError + + +class FakeDbGateway(DbGateway): + def get(self) -> str: + return "Hello" + + +class Interactor: + def __init__(self, db: DbGateway): + self.db = db + + def __call__(self) -> str: + return self.db.get() + + +# app dependency logic +class AdaptersProvider(Provider): + @provide(scope=Scope.REQUEST) + def get_db(self) -> DbGateway: + return FakeDbGateway() + + +class InteractorProvider(Provider): + i1 = provide(Interactor, scope=Scope.REQUEST) + + +class MainController(Controller): + path = '/' + + @get() + @inject + async def index(self, *, interactor: Annotated[Interactor, Depends()]) -> str: + result = interactor() + return result + + +def create_app(): + logging.basicConfig( + level=logging.WARNING, + format='%(asctime)s %(process)-7s %(module)-20s %(message)s', + ) + app = Litestar( + route_handlers=[MainController], + on_startup=[startup_dishka], + on_shutdown=[shutdown_dishka], + before_request=make_container_before_request + ) + return setup_dishka(app, [InteractorProvider(), AdaptersProvider()]) + + +if __name__ == "__main__": + uvicorn.run(create_app(), host="0.0.0.0", port=8000) diff --git a/src/dishka/integrations/litestar.py b/src/dishka/integrations/litestar.py new file mode 100644 index 00000000..b37c31d6 --- /dev/null +++ b/src/dishka/integrations/litestar.py @@ -0,0 +1,51 @@ +from inspect import Parameter +from typing import get_type_hints, Sequence, Optional + +from litestar import Request, Litestar + +from dishka import make_async_container, Provider +from dishka.integrations.base import wrap_injection + + +def inject(func): + hints = get_type_hints(func) + request_param = next( + (name for name, hint in hints.items() if hint is Request), + None, + ) + if request_param: + additional_params = [] + else: + request_param = "request" + additional_params = [Parameter( + name=request_param, + annotation=Optional[Request], + kind=Parameter.KEYWORD_ONLY, + )] + + return wrap_injection( + func=func, + remove_depends=True, + container_getter=lambda _, r: r[request_param].state.dishka_container, + additional_params=additional_params, + is_async=True, + ) + + +async def make_container_before_request(request: Request): + request_container = await request.app.state.dishka_container().__aenter__() + request.state.dishka_container = request_container + + +async def startup_dishka(app: Litestar): + container = await app.state.dishka_container_wrapper.__aenter__() + app.state.dishka_container = container + + +async def shutdown_dishka(app: Litestar): + await app.state.dishka_container_wrapper.__aexit__(None, None, None) + + +def setup_dishka(app: Litestar, providers: Sequence[Provider]) -> Litestar: + app.state.dishka_container_wrapper = make_async_container(*providers) + return app From b3784f08ec12aca6eecf0fab6a27b08c3266e849 Mon Sep 17 00:00:00 2001 From: Andrew Srg Date: Sat, 3 Feb 2024 09:52:19 +0200 Subject: [PATCH 2/3] reformat code, fix naming --- examples/litestar_app.py | 9 +++++++-- src/dishka/integrations/litestar.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/litestar_app.py b/examples/litestar_app.py index 6a43b193..53883a93 100644 --- a/examples/litestar_app.py +++ b/examples/litestar_app.py @@ -7,8 +7,13 @@ from dishka import Provider, Scope, provide from dishka.integrations.base import Depends -from dishka.integrations.litestar import inject, setup_dishka, startup_dishka, make_container_before_request, \ +from dishka.integrations.litestar import ( + inject, + setup_dishka, + startup_dishka, + make_dishka_container, shutdown_dishka +) # app core @@ -61,7 +66,7 @@ def create_app(): route_handlers=[MainController], on_startup=[startup_dishka], on_shutdown=[shutdown_dishka], - before_request=make_container_before_request + before_request=make_dishka_container ) return setup_dishka(app, [InteractorProvider(), AdaptersProvider()]) diff --git a/src/dishka/integrations/litestar.py b/src/dishka/integrations/litestar.py index b37c31d6..e6f4de88 100644 --- a/src/dishka/integrations/litestar.py +++ b/src/dishka/integrations/litestar.py @@ -32,7 +32,7 @@ def inject(func): ) -async def make_container_before_request(request: Request): +async def make_dishka_container(request: Request): request_container = await request.app.state.dishka_container().__aenter__() request.state.dishka_container = request_container From 45ba0d076331717f14b10dbd8d64356e4a59005b Mon Sep 17 00:00:00 2001 From: Andrew Srg Date: Sat, 3 Feb 2024 09:57:00 +0200 Subject: [PATCH 3/3] fix code formatting --- src/dishka/integrations/litestar.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dishka/integrations/litestar.py b/src/dishka/integrations/litestar.py index e6f4de88..4afade76 100644 --- a/src/dishka/integrations/litestar.py +++ b/src/dishka/integrations/litestar.py @@ -1,9 +1,9 @@ from inspect import Parameter -from typing import get_type_hints, Sequence, Optional +from typing import Optional, Sequence, get_type_hints -from litestar import Request, Litestar +from litestar import Litestar, Request -from dishka import make_async_container, Provider +from dishka import Provider, make_async_container from dishka.integrations.base import wrap_injection