Skip to content

Commit

Permalink
Added lost files
Browse files Browse the repository at this point in the history
  • Loading branch information
JrooTJunior committed May 12, 2021
1 parent 7821025 commit 7dd80d2
Show file tree
Hide file tree
Showing 7 changed files with 429 additions and 0 deletions.
113 changes: 113 additions & 0 deletions docs2/dispatcher/middlewares.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
===========
Middlewares
===========

**aiogram** provides powerful mechanism for customizing event handlers via middlewares.

Middlewares in bot framework seems like Middlewares mechanism in web-frameworks
like `aiohttp <https://docs.aiohttp.org/en/stable/web_advanced.html#aiohttp-web-middlewares>`_,
`fastapi <https://fastapi.tiangolo.com/tutorial/middleware/>`_,
`Django <https://docs.djangoproject.com/en/3.0/topics/http/middleware/>`_ or etc.)
with small difference - here is implemented two layers of middlewares (before and after filters).

.. note::

Middleware is function that triggered on every event received from
Telegram Bot API in many points on processing pipeline.

Base theory
===========

As many books and other literature in internet says:

Middleware is reusable software that leverages patterns and frameworks to bridge
the gap between the functional requirements of applications and the underlying operating systems,
network protocol stacks, and databases.

Middleware can modify, extend or reject processing event in many places of pipeline.

Basics
======

Middleware instance can be applied for every type of Telegram Event (Update, Message, etc.) in two places

1. Outer scope - before processing filters (:code:`<router>.<event>.outer_middleware(...)`)
2. Inner scope - after processing filters but before handler (:code:`<router>.<event>.middleware(...)`)

.. image:: ../_static/basics_middleware.png
:alt: Middleware basics

.. attention::

Middleware should be subclass of :code:`BaseMiddleware` (:code:`from aiogram import BaseMiddleware`) or any async callable

Arguments specification
=======================

.. autoclass:: aiogram.dispatcher.middlewares.base.BaseMiddleware
:members:
:show-inheritance:
:member-order: bysource
:special-members: __init__, __call__
:undoc-members: True


Examples
========

.. danger::

Middleware should always call :code:`await handler(event, data)` to propagate event for next middleware/handler


Class-based
-----------
.. code-block:: python
from aiogram import BaseMiddleware
from aiogram.api.types import Message
class CounterMiddleware(BaseMiddleware[Message]):
def __init__(self) -> None:
self.counter = 0
async def __call__(
self,
handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]],
event: Message,
data: Dict[str, Any]
) -> Any:
self.counter += 1
data['counter'] = self.counter
return await handler(event, data)
and then

.. code-block:: python3
router = Router()
router.message.middleware(CounterMiddleware())
Function-based
--------------

.. code-block:: python3
@dispatcher.update.outer_middleware()
async def database_transaction_middleware(
handler: Callable[[Update, Dict[str, Any]], Awaitable[Any]],
event: Update,
data: Dict[str, Any]
) -> Any:
async with database.transaction():
return await handler(event, data)
Facts
=====

1. Middlewares from outer scope will be called on every incoming event
2. Middlewares from inner scope will be called only when filters pass
3. Inner middlewares is always calls for :class:`aiogram.types.update.Update` event type in due to all incoming updates going to specific event type handler through built in update handler
49 changes: 49 additions & 0 deletions tests/test_api/test_methods/test_create_chat_invite_link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import pytest

from aiogram.methods import CreateChatInviteLink, Request
from aiogram.types import ChatInviteLink, User
from tests.mocked_bot import MockedBot


class TestCreateChatInviteLink:
@pytest.mark.asyncio
async def test_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
CreateChatInviteLink,
ok=True,
result=ChatInviteLink(
invite_link="https://t.me/username",
creator=User(id=42, is_bot=False, first_name="User"),
is_primary=False,
is_revoked=False,
),
)

response: ChatInviteLink = await CreateChatInviteLink(
chat_id=-42,
)
request: Request = bot.get_request()
assert request.method == "createChatInviteLink"
# assert request.data == {"chat_id": -42}
assert response == prepare_result.result

@pytest.mark.asyncio
async def test_bot_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
CreateChatInviteLink,
ok=True,
result=ChatInviteLink(
invite_link="https://t.me/username",
creator=User(id=42, is_bot=False, first_name="User"),
is_primary=False,
is_revoked=False,
),
)

response: ChatInviteLink = await bot.create_chat_invite_link(
chat_id=-42,
)
request: Request = bot.get_request()
assert request.method == "createChatInviteLink"
# assert request.data == {"chat_id": -42}
assert response == prepare_result.result
49 changes: 49 additions & 0 deletions tests/test_api/test_methods/test_edit_chat_invite_link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import pytest

from aiogram.methods import EditChatInviteLink, Request
from aiogram.types import ChatInviteLink, User
from tests.mocked_bot import MockedBot


class TestEditChatInviteLink:
@pytest.mark.asyncio
async def test_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
EditChatInviteLink,
ok=True,
result=ChatInviteLink(
invite_link="https://t.me/username2",
creator=User(id=42, is_bot=False, first_name="User"),
is_primary=False,
is_revoked=False,
),
)

response: ChatInviteLink = await EditChatInviteLink(
chat_id=-42, invite_link="https://t.me/username", member_limit=1
)
request: Request = bot.get_request()
assert request.method == "editChatInviteLink"
# assert request.data == {}
assert response == prepare_result.result

@pytest.mark.asyncio
async def test_bot_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
EditChatInviteLink,
ok=True,
result=ChatInviteLink(
invite_link="https://t.me/username2",
creator=User(id=42, is_bot=False, first_name="User"),
is_primary=False,
is_revoked=False,
),
)

response: ChatInviteLink = await bot.edit_chat_invite_link(
chat_id=-42, invite_link="https://t.me/username", member_limit=1
)
request: Request = bot.get_request()
assert request.method == "editChatInviteLink"
# assert request.data == {}
assert response == prepare_result.result
51 changes: 51 additions & 0 deletions tests/test_api/test_methods/test_revoke_chat_invite_link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pytest

from aiogram.methods import Request, RevokeChatInviteLink
from aiogram.types import ChatInviteLink, User
from tests.mocked_bot import MockedBot


class TestRevokeChatInviteLink:
@pytest.mark.asyncio
async def test_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
RevokeChatInviteLink,
ok=True,
result=ChatInviteLink(
invite_link="https://t.me/username",
creator=User(id=42, is_bot=False, first_name="User"),
is_primary=False,
is_revoked=True,
),
)

response: ChatInviteLink = await RevokeChatInviteLink(
chat_id=-42,
invite_link="https://t.me/username",
)
request: Request = bot.get_request()
assert request.method == "revokeChatInviteLink"
# assert request.data == {}
assert response == prepare_result.result

@pytest.mark.asyncio
async def test_bot_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(
RevokeChatInviteLink,
ok=True,
result=ChatInviteLink(
invite_link="https://t.me/username",
creator=User(id=42, is_bot=False, first_name="User"),
is_primary=False,
is_revoked=True,
),
)

response: ChatInviteLink = await bot.revoke_chat_invite_link(
chat_id=-42,
invite_link="https://t.me/username",
)
request: Request = bot.get_request()
assert request.method == "revokeChatInviteLink"
# assert request.data == {}
assert response == prepare_result.result
15 changes: 15 additions & 0 deletions tests/test_api/test_types/test_message_entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import pytest

from aiogram.types import MessageEntity
from tests.deprecated import check_deprecated


class TestMessageEntity:
def test_extract(self):
entity = MessageEntity(type="hashtag", length=4, offset=5)
assert entity.extract("#foo #bar #baz") == "#bar"

def test_get_text(self):
entity = MessageEntity(type="hashtag", length=4, offset=5)
with check_deprecated("3.2", exception=AttributeError):
assert entity.get_text("#foo #bar #baz") == "#bar"
Empty file.

0 comments on commit 7dd80d2

Please sign in to comment.