Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Aiogram integration inject doesn't work with middlewares #185

Open
MassonNN opened this issue Jul 26, 2024 · 4 comments
Open

Aiogram integration inject doesn't work with middlewares #185

MassonNN opened this issue Jul 26, 2024 · 4 comments
Labels
enhancement New feature or request integrations

Comments

@MassonNN
Copy link

Description

As you know, aiogram integration, like any other, has a special function for preparing the main router to propagate the container into the handlers, middlewares, and etc. - setup_dishka(). But it works only with polling and webhooks, and not with manual update feeding via dp.feed_update.

Code example

Works good

async def start_bot():
    """Start the bot as coroutine."""
    bot_container = make_async_container(
        BotProvider(),
    )

    dp = await bot_container.get(Dispatcher)
    bot = await bot_container.get(Bot)

    setup_dishka(router=dp, container=bot_container, auto_inject=True)

    await dp.start_polling(bot)

And doesnt work:

async def start_bot():
    """Start the bot as coroutine."""
    bot_container = make_async_container(
        BotProvider(),
    )

    dp = await bot_container.get(Dispatcher)
    bot = await bot_container.get(Bot)

    setup_dishka(router=dp, container=bot_container, auto_inject=True)

    await dp.feed_update(bot, update=manual_update)  # KeyError: 'dishka_container'

It doesn't work because aiogram uses special kwargs on the feed_update() method and ignores dishka injection previously, as it is useful only for testing and some add-on libraries.

@Tishka17
Copy link
Member

Tishka17 commented Jul 26, 2024

Can we see a stacktrace? I do not see any problems from my side, feed_update is called by aiogram itself: https://github.com/aiogram/aiogram/blob/a3d6c1615ee07eb50577b6a1b6323a8657fd9f20/aiogram/dispatcher/dispatcher.py#L309

@MassonNN
Copy link
Author

MassonNN commented Jul 26, 2024

Can we see a stacktrace? I do not see any problems from my side, feed_update is called by aiogram itself: https://github.com/aiogram/aiogram/blob/a3d6c1615ee07eb50577b6a1b6323a8657fd9f20/aiogram/dispatcher/dispatcher.py#L309

I researched this and found that it originated from the Dispatcher side and because middleware uses @Inject on the call method. So this isn't a problem with feed_update method. Here is another mre that explains this problem:

import asyncio
import datetime
from unittest.mock import AsyncMock

from aiogram import Dispatcher, BaseMiddleware
from aiogram.types import Update, Message, Chat
from dishka import make_async_container, FromDishka, Provider, Scope
from dishka.integrations.aiogram import setup_dishka, inject


class Some:
    pass


class TestMiddleware(BaseMiddleware):
    @inject
    async def __call__(
            self,
            handler,
            event,
            data,
            md: FromDishka[Some]
    ):
        print(md)
        return await handler(event, data)


async def start_bot():
    provider = Provider()
    provider.provide(source=lambda: Some(), provides=Some, scope=Scope.APP)
    bot_container = make_async_container(provider)

    dp = Dispatcher()
    dp.update.outer_middleware(TestMiddleware())
    bot = AsyncMock()

    setup_dishka(router=dp, container=bot_container, auto_inject=True)

    await dp.feed_update(
        bot,
        update=Update(
            update_id=0,
            message=Message(message_id=0, date=datetime.datetime.now(), chat=Chat(id=0, type="private"))
        )
    )


if __name__ == '__main__':
    asyncio.run(start_bot())

Stacktrace:

Traceback (most recent call last):
  File "/mre.py", line 49, in <module>
    asyncio.run(start_bot())
  File "/.pyenv/versions/3.10.2/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/.pyenv/versions/3.10.2/lib/python3.10/asyncio/base_events.py", line 641, in run_until_complete
    return future.result()
  File "/mre.py", line 39, in start_bot
    await dp.feed_update(
  File "/.venv/lib/python3.10/site-packages/aiogram/dispatcher/dispatcher.py", line 158, in feed_update
    response = await self.update.wrap_outer_middleware(
  File "/.venv/lib/python3.10/site-packages/aiogram/dispatcher/middlewares/error.py", line 25, in __call__
    return await handler(event, data)
  File "/.venv/lib/python3.10/site-packages/aiogram/dispatcher/middlewares/user_context.py", line 49, in __call__
    return await handler(event, data)
  File "/.venv/lib/python3.10/site-packages/aiogram/fsm/middleware.py", line 43, in __call__
    return await handler(event, data)
  File "/.venv/lib/python3.10/site-packages/dishka/integrations/base.py", line 147, in autoinjected_func
    container = container_getter(args, kwargs)
  File "/.venv/lib/python3.10/site-packages/dishka/integrations/aiogram.py", line 31, in <lambda>
    container_getter=lambda _, p: p[CONTAINER_NAME],
KeyError: 'dishka_container'

@Tishka17
Copy link
Member

Thanks,

Middlewares in aiogram have different logic comparing to handlers so you cannot reuse @inject there. Instead, you can get dishka_container manually from data dictionary and use its .get methods.

I'll think about how can we add more automatic here, but it is more like enhancement than a bug

@Tishka17 Tishka17 changed the title Aiogram integration doesn't work with dp.feed_update() Aiogram integration inject doesn't work with middlewares Jul 26, 2024
@Tishka17 Tishka17 added enhancement New feature or request integrations labels Jul 26, 2024
@IvanKirpichnikov
Copy link
Member

def aiogram_middleware_inject(func):
    return wrap_injection(
        func=func,
        is_async=True,
        container_getter=lambda args, kwargs: args[3][CONTAINER_KEY],
    )

here is the finished inject decorator

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
enhancement New feature or request integrations
Projects
None yet
Development

No branches or pull requests

3 participants