[3.x] Bot API 5.5 (#777)

* Re-generate API, cover changes

* Added patchnotes
This commit is contained in:
Alex Root Junior 2021-12-12 17:21:01 +02:00 committed by GitHub
parent 92ec44d8d2
commit 9ec689b562
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 333 additions and 15 deletions

View file

@ -1 +1 @@
5.4 5.5

View file

@ -1 +1 @@
Fixed: Missing ChatMemberHandler import in aiogram/dispatcher/handler Fixed: Missing :code:`ChatMemberHandler` import in :code:`aiogram/dispatcher/handler`

1
CHANGES/777.misc Normal file
View file

@ -0,0 +1 @@
Added full support of `Bot API 5.5 <https://core.telegram.org/bots/api-changelog#december-7-2021>`_

View file

@ -82,13 +82,16 @@ reformat:
# ================================================================================================= # =================================================================================================
# Tests # Tests
# ================================================================================================= # =================================================================================================
.PHONY: test-run-services
test-run-services:
docker-compose -f tests/docker-compose.yml -p aiogram3-dev up -d
.PHONY: test .PHONY: test
test: test: test-run-services
$(py) pytest --cov=aiogram --cov-config .coveragerc tests/ --redis $(redis_connection) $(py) pytest --cov=aiogram --cov-config .coveragerc tests/ --redis $(redis_connection)
.PHONY: test-coverage .PHONY: test-coverage
test-coverage: test-coverage: test-run-services
mkdir -p $(reports_dir)/tests/ mkdir -p $(reports_dir)/tests/
$(py) pytest --cov=aiogram --cov-config .coveragerc --html=$(reports_dir)/tests/index.html tests/ --redis $(redis_connection) $(py) pytest --cov=aiogram --cov-config .coveragerc --html=$(reports_dir)/tests/index.html tests/ --redis $(redis_connection)

View file

@ -13,7 +13,7 @@ aiogram
:target: https://pypi.python.org/pypi/aiogram :target: https://pypi.python.org/pypi/aiogram
:alt: Supported python versions :alt: Supported python versions
.. image:: https://img.shields.io/badge/Telegram%20Bot%20API-5.4-blue.svg?logo=telegram .. image:: https://img.shields.io/badge/Telegram%20Bot%20API-5.5-blue.svg?logo=telegram
:target: https://core.telegram.org/bots/api :target: https://core.telegram.org/bots/api
:alt: Telegram Bot API :alt: Telegram Bot API

View file

@ -37,4 +37,4 @@ __all__ = (
) )
__version__ = "3.0.0a19" __version__ = "3.0.0a19"
__api_version__ = "5.4" __api_version__ = "5.5"

View file

@ -29,6 +29,7 @@ from ..methods import (
AnswerShippingQuery, AnswerShippingQuery,
ApproveChatJoinRequest, ApproveChatJoinRequest,
BanChatMember, BanChatMember,
BanChatSenderChat,
Close, Close,
CopyMessage, CopyMessage,
CreateChatInviteLink, CreateChatInviteLink,
@ -102,6 +103,7 @@ from ..methods import (
StopPoll, StopPoll,
TelegramMethod, TelegramMethod,
UnbanChatMember, UnbanChatMember,
UnbanChatSenderChat,
UnpinAllChatMessages, UnpinAllChatMessages,
UnpinChatMessage, UnpinChatMessage,
UploadStickerFile, UploadStickerFile,
@ -1637,6 +1639,50 @@ class Bot(ContextInstanceMixin["Bot"]):
) )
return await self(call, request_timeout=request_timeout) return await self(call, request_timeout=request_timeout)
async def ban_chat_sender_chat(
self,
chat_id: Union[int, str],
sender_chat_id: int,
request_timeout: Optional[int] = None,
) -> bool:
"""
Use this method to ban a channel chat in a supergroup or a channel. Until the chat is `unbanned <https://core.telegram.org/bots/api#unbanchatsenderchat>`_, the owner of the banned chat won't be able to send messages on behalf of **any of their channels**. The bot must be an administrator in the supergroup or channel for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
Source: https://core.telegram.org/bots/api#banchatsenderchat
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
:param sender_chat_id: Unique identifier of the target sender chat
:param request_timeout: Request timeout
:return: Returns True on success.
"""
call = BanChatSenderChat(
chat_id=chat_id,
sender_chat_id=sender_chat_id,
)
return await self(call, request_timeout=request_timeout)
async def unban_chat_sender_chat(
self,
chat_id: Union[int, str],
sender_chat_id: int,
request_timeout: Optional[int] = None,
) -> bool:
"""
Use this method to unban a previously banned channel chat in a supergroup or channel. The bot must be an administrator for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
Source: https://core.telegram.org/bots/api#unbanchatsenderchat
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
:param sender_chat_id: Unique identifier of the target sender chat
:param request_timeout: Request timeout
:return: Returns True on success.
"""
call = UnbanChatSenderChat(
chat_id=chat_id,
sender_chat_id=sender_chat_id,
)
return await self(call, request_timeout=request_timeout)
async def set_chat_permissions( async def set_chat_permissions(
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],

View file

@ -16,8 +16,8 @@ INTERNAL_UPDATE_TYPES = frozenset({"update", "error"})
class Router: class Router:
""" """
Router can route update and it nested update types like messages, callback query, polls and all other event types. Router can route update, and it nested update types like messages, callback query,
Here is used event-observer pattern. polls and all other event types.
Event handlers can be registered in observer by two ways: Event handlers can be registered in observer by two ways:

View file

@ -5,6 +5,7 @@ from .answer_pre_checkout_query import AnswerPreCheckoutQuery
from .answer_shipping_query import AnswerShippingQuery from .answer_shipping_query import AnswerShippingQuery
from .approve_chat_join_request import ApproveChatJoinRequest from .approve_chat_join_request import ApproveChatJoinRequest
from .ban_chat_member import BanChatMember from .ban_chat_member import BanChatMember
from .ban_chat_sender_chat import BanChatSenderChat
from .base import Request, Response, TelegramMethod from .base import Request, Response, TelegramMethod
from .close import Close from .close import Close
from .copy_message import CopyMessage from .copy_message import CopyMessage
@ -78,6 +79,7 @@ from .set_webhook import SetWebhook
from .stop_message_live_location import StopMessageLiveLocation from .stop_message_live_location import StopMessageLiveLocation
from .stop_poll import StopPoll from .stop_poll import StopPoll
from .unban_chat_member import UnbanChatMember from .unban_chat_member import UnbanChatMember
from .unban_chat_sender_chat import UnbanChatSenderChat
from .unpin_all_chat_messages import UnpinAllChatMessages from .unpin_all_chat_messages import UnpinAllChatMessages
from .unpin_chat_message import UnpinChatMessage from .unpin_chat_message import UnpinChatMessage
from .upload_sticker_file import UploadStickerFile from .upload_sticker_file import UploadStickerFile
@ -120,6 +122,8 @@ __all__ = (
"RestrictChatMember", "RestrictChatMember",
"PromoteChatMember", "PromoteChatMember",
"SetChatAdministratorCustomTitle", "SetChatAdministratorCustomTitle",
"BanChatSenderChat",
"UnbanChatSenderChat",
"SetChatPermissions", "SetChatPermissions",
"ExportChatInviteLink", "ExportChatInviteLink",
"CreateChatInviteLink", "CreateChatInviteLink",

View file

@ -0,0 +1,28 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Dict, Union
from .base import Request, TelegramMethod
if TYPE_CHECKING:
from ..client.bot import Bot
class BanChatSenderChat(TelegramMethod[bool]):
"""
Use this method to ban a channel chat in a supergroup or a channel. Until the chat is `unbanned <https://core.telegram.org/bots/api#unbanchatsenderchat>`_, the owner of the banned chat won't be able to send messages on behalf of **any of their channels**. The bot must be an administrator in the supergroup or channel for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
Source: https://core.telegram.org/bots/api#banchatsenderchat
"""
__returning__ = bool
chat_id: Union[int, str]
"""Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)"""
sender_chat_id: int
"""Unique identifier of the target sender chat"""
def build_request(self, bot: Bot) -> Request:
data: Dict[str, Any] = self.dict()
return Request(method="banChatSenderChat", data=data)

View file

@ -0,0 +1,28 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Dict, Union
from .base import Request, TelegramMethod
if TYPE_CHECKING:
from ..client.bot import Bot
class UnbanChatSenderChat(TelegramMethod[bool]):
"""
Use this method to unban a previously banned channel chat in a supergroup or channel. The bot must be an administrator for this to work and must have the appropriate administrator rights. Returns :code:`True` on success.
Source: https://core.telegram.org/bots/api#unbanchatsenderchat
"""
__returning__ = bool
chat_id: Union[int, str]
"""Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)"""
sender_chat_id: int
"""Unique identifier of the target sender chat"""
def build_request(self, bot: Bot) -> Request:
data: Dict[str, Any] = self.dict()
return Request(method="unbanChatSenderChat", data=data)

View file

@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Optional
from .base import TelegramObject from .base import TelegramObject
if TYPE_CHECKING: if TYPE_CHECKING:
from ..methods import BanChatSenderChat, UnbanChatSenderChat
from .chat_location import ChatLocation from .chat_location import ChatLocation
from .chat_permissions import ChatPermissions from .chat_permissions import ChatPermissions
from .chat_photo import ChatPhoto from .chat_photo import ChatPhoto
@ -34,6 +35,8 @@ class Chat(TelegramObject):
"""*Optional*. Chat photo. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" """*Optional*. Chat photo. Returned only in :class:`aiogram.methods.get_chat.GetChat`."""
bio: Optional[str] = None bio: Optional[str] = None
"""*Optional*. Bio of the other party in a private chat. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" """*Optional*. Bio of the other party in a private chat. Returned only in :class:`aiogram.methods.get_chat.GetChat`."""
has_private_forwards: Optional[bool] = None
"""*Optional*. True, if privacy settings of the other party in the private chat allows to use :code:`tg://user?id=<user_id>` links only in chats with the user. Returned only in :class:`aiogram.methods.get_chat.GetChat`."""
description: Optional[str] = None description: Optional[str] = None
"""*Optional*. Description, for groups, supergroups and channel chats. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" """*Optional*. Description, for groups, supergroups and channel chats. Returned only in :class:`aiogram.methods.get_chat.GetChat`."""
invite_link: Optional[str] = None invite_link: Optional[str] = None
@ -46,6 +49,8 @@ class Chat(TelegramObject):
"""*Optional*. For supergroups, the minimum allowed delay between consecutive messages sent by each unpriviledged user; in seconds. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" """*Optional*. For supergroups, the minimum allowed delay between consecutive messages sent by each unpriviledged user; in seconds. Returned only in :class:`aiogram.methods.get_chat.GetChat`."""
message_auto_delete_time: Optional[int] = None message_auto_delete_time: Optional[int] = None
"""*Optional*. The time after which all messages sent to the chat will be automatically deleted; in seconds. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" """*Optional*. The time after which all messages sent to the chat will be automatically deleted; in seconds. Returned only in :class:`aiogram.methods.get_chat.GetChat`."""
has_protected_content: Optional[bool] = None
"""*Optional*. True, if messages from the chat can't be forwarded to other chats. Returned only in :class:`aiogram.methods.get_chat.GetChat`."""
sticker_set_name: Optional[str] = None sticker_set_name: Optional[str] = None
"""*Optional*. For supergroups, name of group sticker set. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" """*Optional*. For supergroups, name of group sticker set. Returned only in :class:`aiogram.methods.get_chat.GetChat`."""
can_set_sticker_set: Optional[bool] = None can_set_sticker_set: Optional[bool] = None
@ -70,3 +75,19 @@ class Chat(TelegramObject):
short_id = str(self.id).replace("-100", "") short_id = str(self.id).replace("-100", "")
shift = int(-1 * pow(10, len(short_id) + 2)) shift = int(-1 * pow(10, len(short_id) + 2))
return shift - self.id return shift - self.id
def ban_sender_chat(self, sender_chat_id: int) -> BanChatSenderChat:
from ..methods import BanChatSenderChat
return BanChatSenderChat(
chat_id=self.id,
sender_chat_id=sender_chat_id,
)
def unban_sender_chat(self, sender_chat_id: int) -> UnbanChatSenderChat:
from ..methods import UnbanChatSenderChat
return UnbanChatSenderChat(
chat_id=self.id,
sender_chat_id=sender_chat_id,
)

View file

@ -19,7 +19,7 @@ class InlineKeyboardButton(MutableTelegramObject):
text: str text: str
"""Label text on the button""" """Label text on the button"""
url: Optional[str] = None url: Optional[str] = None
"""*Optional*. HTTP or tg:// url to be opened when button is pressed""" """*Optional*. HTTP or tg:// url to be opened when the button is pressed. Links :code:`tg://user?id=<user_id>` can be used to mention a user by their ID without using a username, if this is allowed by their privacy settings."""
login_url: Optional[LoginUrl] = None login_url: Optional[LoginUrl] = None
"""*Optional*. An HTTP URL used to automatically authorize the user. Can be used as a replacement for the `Telegram Login Widget <https://core.telegram.org/widgets/login>`_.""" """*Optional*. An HTTP URL used to automatically authorize the user. Can be used as a replacement for the `Telegram Login Widget <https://core.telegram.org/widgets/login>`_."""
callback_data: Optional[str] = None callback_data: Optional[str] = None

View file

@ -79,10 +79,8 @@ class BufferedInputFile(InputFile):
async def read(self, chunk_size: int) -> AsyncGenerator[bytes, None]: async def read(self, chunk_size: int) -> AsyncGenerator[bytes, None]:
buffer = io.BytesIO(self.data) buffer = io.BytesIO(self.data)
chunk = buffer.read(chunk_size) while chunk := buffer.read(chunk_size):
while chunk:
yield chunk yield chunk
chunk = buffer.read(chunk_size)
class FSInputFile(InputFile): class FSInputFile(InputFile):

View file

@ -85,9 +85,9 @@ class Message(TelegramObject):
chat: Chat chat: Chat
"""Conversation the message belongs to""" """Conversation the message belongs to"""
from_user: Optional[User] = Field(None, alias="from") from_user: Optional[User] = Field(None, alias="from")
"""*Optional*. Sender, empty for messages sent to channels""" """*Optional*. Sender of the message; empty for messages sent to channels. For backward compatibility, the field contains a fake sender user in non-channel chats, if the message was sent on behalf of a chat."""
sender_chat: Optional[Chat] = None sender_chat: Optional[Chat] = None
"""*Optional*. Sender of the message, sent on behalf of a chat. The channel itself for channel messages. The supergroup itself for messages from anonymous group administrators. The linked channel for messages automatically forwarded to the discussion group""" """*Optional*. Sender of the message, sent on behalf of a chat. For example, the channel itself for channel posts, the supergroup itself for messages from anonymous group administrators, the linked channel for messages automatically forwarded to the discussion group. For backward compatibility, the field *from* contains a fake sender user in non-channel chats, if the message was sent on behalf of a chat."""
forward_from: Optional[User] = None forward_from: Optional[User] = None
"""*Optional*. For forwarded messages, sender of the original message""" """*Optional*. For forwarded messages, sender of the original message"""
forward_from_chat: Optional[Chat] = None forward_from_chat: Optional[Chat] = None
@ -100,12 +100,16 @@ class Message(TelegramObject):
"""*Optional*. Sender's name for messages forwarded from users who disallow adding a link to their account in forwarded messages""" """*Optional*. Sender's name for messages forwarded from users who disallow adding a link to their account in forwarded messages"""
forward_date: Optional[int] = None forward_date: Optional[int] = None
"""*Optional*. For forwarded messages, date the original message was sent in Unix time""" """*Optional*. For forwarded messages, date the original message was sent in Unix time"""
is_automatic_forward: Optional[bool] = None
"""*Optional*. True, if the message is a channel post that was automatically forwarded to the connected discussion group"""
reply_to_message: Optional[Message] = None reply_to_message: Optional[Message] = None
"""*Optional*. For replies, the original message. Note that the Message object in this field will not contain further *reply_to_message* fields even if it itself is a reply.""" """*Optional*. For replies, the original message. Note that the Message object in this field will not contain further *reply_to_message* fields even if it itself is a reply."""
via_bot: Optional[User] = None via_bot: Optional[User] = None
"""*Optional*. Bot through which the message was sent""" """*Optional*. Bot through which the message was sent"""
edit_date: Optional[int] = None edit_date: Optional[int] = None
"""*Optional*. Date the message was last edited in Unix time""" """*Optional*. Date the message was last edited in Unix time"""
has_protected_content: Optional[bool] = None
"""*Optional*. True, if the message can't be forwarded"""
media_group_id: Optional[str] = None media_group_id: Optional[str] = None
"""*Optional*. The unique identifier of a media message group this message belongs to""" """*Optional*. The unique identifier of a media message group this message belongs to"""
author_signature: Optional[str] = None author_signature: Optional[str] = None

View file

@ -0,0 +1,51 @@
#################
banChatSenderChat
#################
Returns: :obj:`bool`
.. automodule:: aiogram.methods.ban_chat_sender_chat
:members:
:member-order: bysource
:undoc-members: True
Usage
=====
As bot method
-------------
.. code-block::
result: bool = await bot.ban_chat_sender_chat(...)
Method as object
----------------
Imports:
- :code:`from aiogram.methods.ban_chat_sender_chat import BanChatSenderChat`
- alias: :code:`from aiogram.methods import BanChatSenderChat`
In handlers with current bot
----------------------------
.. code-block:: python
result: bool = await BanChatSenderChat(...)
With specific bot
~~~~~~~~~~~~~~~~~
.. code-block:: python
result: bool = await bot(BanChatSenderChat(...))
As reply into Webhook in handler
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
return BanChatSenderChat(...)

View file

@ -54,6 +54,8 @@ Available methods
restrict_chat_member restrict_chat_member
promote_chat_member promote_chat_member
set_chat_administrator_custom_title set_chat_administrator_custom_title
ban_chat_sender_chat
unban_chat_sender_chat
set_chat_permissions set_chat_permissions
export_chat_invite_link export_chat_invite_link
create_chat_invite_link create_chat_invite_link

View file

@ -0,0 +1,51 @@
###################
unbanChatSenderChat
###################
Returns: :obj:`bool`
.. automodule:: aiogram.methods.unban_chat_sender_chat
:members:
:member-order: bysource
:undoc-members: True
Usage
=====
As bot method
-------------
.. code-block::
result: bool = await bot.unban_chat_sender_chat(...)
Method as object
----------------
Imports:
- :code:`from aiogram.methods.unban_chat_sender_chat import UnbanChatSenderChat`
- alias: :code:`from aiogram.methods import UnbanChatSenderChat`
In handlers with current bot
----------------------------
.. code-block:: python
result: bool = await UnbanChatSenderChat(...)
With specific bot
~~~~~~~~~~~~~~~~~
.. code-block:: python
result: bool = await bot(UnbanChatSenderChat(...))
As reply into Webhook in handler
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
return UnbanChatSenderChat(...)

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "aiogram" name = "aiogram"
version = "3.0.0-alpha.18" version = "3.0.0-alpha.19"
description = "Modern and fully asynchronous framework for Telegram Bot API" description = "Modern and fully asynchronous framework for Telegram Bot API"
authors = [ authors = [
"Alex Root Junior <jroot.junior@gmail.com>", "Alex Root Junior <jroot.junior@gmail.com>",

View file

@ -0,0 +1,32 @@
import pytest
from aiogram.methods import BanChatSenderChat, Request
from tests.mocked_bot import MockedBot
class TestBanChatSenderChat:
@pytest.mark.asyncio
async def test_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(BanChatSenderChat, ok=True, result=True)
response: bool = await BanChatSenderChat(
chat_id=-42,
sender_chat_id=-1337,
)
request: Request = bot.get_request()
assert request.method == "banChatSenderChat"
# 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(BanChatSenderChat, ok=True, result=True)
response: bool = await bot.ban_chat_sender_chat(
chat_id=-42,
sender_chat_id=-1337,
)
request: Request = bot.get_request()
assert request.method == "banChatSenderChat"
# assert request.data == {}
assert response == prepare_result.result

View file

@ -0,0 +1,32 @@
import pytest
from aiogram.methods import Request, UnbanChatSenderChat
from tests.mocked_bot import MockedBot
class TestUnbanChatSenderChat:
@pytest.mark.asyncio
async def test_method(self, bot: MockedBot):
prepare_result = bot.add_result_for(UnbanChatSenderChat, ok=True, result=True)
response: bool = await UnbanChatSenderChat(
chat_id=-42,
sender_chat_id=-1337,
)
request: Request = bot.get_request()
assert request.method == "unbanChatSenderChat"
# 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(UnbanChatSenderChat, ok=True, result=True)
response: bool = await bot.unban_chat_sender_chat(
chat_id=-42,
sender_chat_id=-1337,
)
request: Request = bot.get_request()
assert request.method == "unbanChatSenderChat"
# assert request.data == {}
assert response == prepare_result.result

View file

@ -0,0 +1,17 @@
from aiogram.types import Chat
class TestChat:
def test_ban_sender_chat(self):
chat = Chat(id=-42, type="supergroup")
method = chat.ban_sender_chat(sender_chat_id=-1337)
assert method.chat_id == chat.id
assert method.sender_chat_id == -1337
def test_unban_sender_chat(self):
chat = Chat(id=-42, type="supergroup")
method = chat.unban_sender_chat(sender_chat_id=-1337)
assert method.chat_id == chat.id
assert method.sender_chat_id == -1337