Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9df248e
aiogram, fastapi integrations in framework
Tishka17 Jan 29, 2024
eff9ae5
fastapi, aiogram examples
Tishka17 Jan 30, 2024
d82fc80
Merge branch 'develop' into feature/integrations
Tishka17 Jan 30, 2024
dd8e0c6
pass args to container getter, fix naming
Tishka17 Jan 30, 2024
14f9151
Merge pull request #24 from reagento/feature/integrations
Tishka17 Jan 31, 2024
57790f3
Telebot example
Tishka17 Jan 31, 2024
88125aa
add litestar integration example
andiserg Feb 1, 2024
269d1d2
fix return type
Tishka17 Feb 1, 2024
98ddfef
Merge pull request #25 from reagento/feature/integrations
Tishka17 Feb 1, 2024
b3784f0
reformat code, fix naming
andiserg Feb 3, 2024
45ba0d0
fix code formatting
andiserg Feb 3, 2024
999622b
more verbode example
Tishka17 Feb 3, 2024
c0029b7
Fix running tests
Tishka17 Feb 3, 2024
ece14af
add examples note
Tishka17 Feb 3, 2024
8841d5c
base asgi middleware
Tishka17 Feb 4, 2024
eaa02ea
Merge pull request #26 from AndrewSergienko/feature/litestar_integration
Tishka17 Feb 4, 2024
efe5ac1
Merge branch 'develop' into feature/integrations
Tishka17 Feb 4, 2024
83c7356
create asgi middleware
andiserg Feb 4, 2024
f3cffa4
create litestar after response handler
andiserg Feb 4, 2024
3f56066
Merge branch 'reagento:develop' into feature/litestar_integration
andiserg Feb 4, 2024
182da82
sort imports
Tishka17 Feb 4, 2024
93db3a9
Merge pull request #27 from reagento/feature/integrations
Tishka17 Feb 4, 2024
1ed99da
Merge branch 'feature/integrations' into feature/litestar_integration
andiserg Feb 4, 2024
5882dab
refactor litestar asgi middleware
andiserg Feb 4, 2024
08ba216
refactor: remove unnecessary functions
andiserg Feb 4, 2024
c2c9dd2
fix code formatting
andiserg Feb 4, 2024
5e6cea3
add event type checking
andiserg Feb 5, 2024
1317a8d
refactor: add return to litestar middleware
andiserg Feb 6, 2024
7999231
use tox to check integrations
Tishka17 Feb 7, 2024
9a3ce18
Merge pull request #29 from reagento/feature/integrations
Tishka17 Feb 7, 2024
c33f487
Merge pull request #28 from AndrewSergienko/feature/litestar_integration
Tishka17 Feb 7, 2024
0a9b575
Real world example tests
Tishka17 Feb 7, 2024
385756b
Merge pull request #30 from reagento/feature/real_world_tests
Tishka17 Feb 7, 2024
6d65466
Telebot integration tests
Tishka17 Feb 7, 2024
0d9a218
Merge pull request #31 from reagento/feature/integrations
Tishka17 Feb 8, 2024
89e95da
coverage and flask
Tishka17 Feb 8, 2024
d76caf0
Merge pull request #32 from reagento/feature/integrations
Tishka17 Feb 8, 2024
bddf2fd
feature: add litestar integration tests
andiserg Feb 8, 2024
6b635a7
fix code formatting
andiserg Feb 8, 2024
cbdedef
fix: change litestar minimal version in test requirements
andiserg Feb 8, 2024
7dc0389
Merge pull request #33 from AndrewSergienko/feature/litestar_integration
Tishka17 Feb 8, 2024
0d7f73d
badges
Tishka17 Feb 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ jobs:

- name: Run tests
run: |
pytest
tox
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
## DIshka (from russian "small DI")
[![PyPI version](https://badge.fury.io/py/dishka.svg)](https://badge.fury.io/py/dishka)
[![downloads](https://img.shields.io/pypi/dm/dishka.svg)](https://pypistats.org/packages/dishka)
[![license](https://img.shields.io/github/license/reagento/dishka)](https://github.com/reagento/dishka/blob/master/LICENSE)
[![license](https://img.shields.io/badge/💬-Telegram-blue)](https://t.me/reagento_ru)

Small DI framework with scopes and agreeable API.

Expand Down
51 changes: 9 additions & 42 deletions examples/aiogram_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,13 @@
import logging
import os
import random
from inspect import Parameter
from typing import Annotated, Container, Iterable
from typing import Annotated, Iterable

from aiogram import BaseMiddleware, Bot, Dispatcher, Router
from aiogram import Bot, Dispatcher, Router
from aiogram.types import Message, TelegramObject, User

from dishka import Provider, Scope, make_async_container, provide
from dishka.inject import Depends, wrap_injection


# framework level
def inject(func):
getter = lambda kwargs: kwargs["container"]
additional_params = [Parameter(
name="container",
annotation=Container,
kind=Parameter.KEYWORD_ONLY,
)]

return wrap_injection(
func=func,
remove_depends=True,
container_getter=getter,
additional_params=additional_params,
is_async=True,
)


class ContainerMiddleware(BaseMiddleware):
def __init__(self, container):
self.container = container

async def __call__(
self, handler, event, data,
):
async with self.container({TelegramObject: event}) as subcontainer:
data["container"] = subcontainer
return await handler(event, data)
from dishka import Provider, Scope, provide
from dishka.integrations.aiogram import Depends, inject, setup_dishka


# app dependency logic
Expand Down Expand Up @@ -73,14 +42,12 @@ async def start(
async def main():
# real main
logging.basicConfig(level=logging.INFO)
async with make_async_container(MyProvider()) as container:
bot = Bot(token=API_TOKEN)
dp = Dispatcher()
for observer in dp.observers.values():
observer.middleware(ContainerMiddleware(container))
dp.include_router(router)
bot = Bot(token=API_TOKEN)
dp = Dispatcher()
dp.include_router(router)
setup_dishka(providers=[MyProvider()], router=dp)
await dp.start_polling(bot)

await dp.start_polling(bot)


if __name__ == '__main__':
Expand Down
62 changes: 7 additions & 55 deletions examples/benchmarks/fastapi_app.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,13 @@
import logging
from contextlib import asynccontextmanager
from inspect import Parameter
from typing import Annotated, Callable, Iterable, NewType, get_type_hints
from typing import Annotated, Callable, Iterable, NewType

import uvicorn
from fastapi import APIRouter
from fastapi import Depends as FastapiDepends
from fastapi import FastAPI, Request

from dishka import Provider, Scope, make_async_container, provide
from dishka.inject import Depends, wrap_injection


# framework level
def inject(func):
hints = get_type_hints(func)
requests_param = next(
(name for name, hint in hints.items() if hint is Request),
None,
)
if requests_param:
getter = lambda kwargs: kwargs[requests_param].state.container
additional_params = []
else:
getter = lambda kwargs: kwargs["___r___"].state.container
additional_params = [Parameter(
name="___r___",
annotation=Request,
kind=Parameter.KEYWORD_ONLY,
)]

return wrap_injection(
func=func,
remove_depends=True,
container_getter=getter,
additional_params=additional_params,
is_async=True,
)


def container_middleware():
async def add_request_container(request: Request, call_next):
async with request.app.state.container(
{Request: request}
) as subcontainer:
request.state.container = subcontainer
return await call_next(request)

return add_request_container
from fastapi import FastAPI

from dishka import Provider, Scope, provide
from dishka.integrations.fastapi import Depends, DishkaApp, inject


class Stub:
Expand Down Expand Up @@ -143,23 +103,15 @@ def new_a(b: B = FastapiDepends(Stub(B)), c: C = FastapiDepends(Stub(C))):
return A(b, c)


@asynccontextmanager
async def lifespan(app: FastAPI):
async with make_async_container(MyProvider()) as container:
app.state.container = container
yield


def create_app() -> FastAPI:
logging.basicConfig(level=logging.WARNING)

app = FastAPI(lifespan=lifespan)
app.middleware("http")(container_middleware())
app = FastAPI()
app.dependency_overrides[A] = new_a
app.dependency_overrides[B] = lambda: B(1)
app.dependency_overrides[C] = lambda: C(1)
app.include_router(router)
return app
return DishkaApp(providers=[MyProvider()], app=app)


if __name__ == "__main__":
Expand Down
80 changes: 17 additions & 63 deletions examples/fastapi_app.py
Original file line number Diff line number Diff line change
@@ -1,57 +1,16 @@
import logging
from abc import abstractmethod
from contextlib import asynccontextmanager
from inspect import Parameter
from typing import (
Annotated, get_type_hints, Protocol, Any, get_origin,
get_args,
)
from typing import Annotated, Protocol

import uvicorn
from fastapi import APIRouter
from fastapi import FastAPI, Request
from fastapi import APIRouter, FastAPI

from dishka import (
Depends, wrap_injection, Provider, Scope, make_async_container, provide,
Provider, Scope, provide,
)
from dishka.integrations.fastapi import (
Depends, inject, DishkaApp,
)


# framework level
def inject(func):
hints = get_type_hints(func)
requests_param = next(
(name for name, hint in hints.items() if hint is Request),
None,
)
if requests_param:
getter = lambda kwargs: kwargs[requests_param].state.container
additional_params = []
else:
getter = lambda kwargs: kwargs["___r___"].state.container
additional_params = [Parameter(
name="___r___",
annotation=Request,
kind=Parameter.KEYWORD_ONLY,
)]

return wrap_injection(
func=func,
remove_depends=True,
container_getter=getter,
additional_params=additional_params,
is_async=True,
)


def container_middleware():
async def add_request_container(request: Request, call_next):
async with request.app.state.container(
{Request: request}
) as subcontainer:
request.state.container = subcontainer
return await call_next(request)

return add_request_container


# app core
Expand Down Expand Up @@ -99,24 +58,19 @@ async def index(
return result


# app configuration
@asynccontextmanager
async def lifespan(app: FastAPI):
async with make_async_container(
AdaptersProvider(), InteractorProvider(),
) as container:
app.state.container = container
yield


def create_app() -> FastAPI:
logging.basicConfig(level=logging.WARNING)
def create_app():
logging.basicConfig(
level=logging.WARNING,
format='%(asctime)s %(process)-7s %(module)-20s %(message)s',
)

app = FastAPI(lifespan=lifespan)
app.middleware("http")(container_middleware())
app = FastAPI()
app.include_router(router)
return app
return DishkaApp(
providers=[AdaptersProvider(), InteractorProvider()],
app=app,
)


if __name__ == "__main__":
uvicorn.run(create_app(), host="0.0.0.0", port=8000)
uvicorn.run(create_app(), host="0.0.0.0", port=8000, lifespan="on")
66 changes: 66 additions & 0 deletions examples/flask_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from abc import abstractmethod
from typing import Annotated, Protocol

from flask import Flask

from dishka import (
Provider, Scope, provide,
)
from dishka.integrations.flask import (
Depends, inject, setup_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)


# presentation layer
app = Flask(__name__)


@app.get("/")
@inject
def index(
*,
interactor: Annotated[Interactor, Depends()],
) -> str:
result = interactor()
return result


container = setup_dishka(
providers=[AdaptersProvider(), InteractorProvider()],
app=app,
)
try:
app.run()
finally:
container.close()
Loading