From 3731a628856daf15d6c7ff21c41a905409203eee Mon Sep 17 00:00:00 2001 From: He <123play123.loggin@gmail.com> Date: Tue, 8 Feb 2022 07:25:15 +0700 Subject: [PATCH 1/9] Deleting deprecated CHOSEN_INLINE_QUERY (#805) * Deleting deprecated CHOSEN_INLINE_QUERY * Del from comments CHOSEN_INLINE_QUERY --- aiogram/dispatcher/dispatcher.py | 6 +++--- aiogram/types/update.py | 8 +------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/aiogram/dispatcher/dispatcher.py b/aiogram/dispatcher/dispatcher.py index 60aeed49..5b3cafd3 100644 --- a/aiogram/dispatcher/dispatcher.py +++ b/aiogram/dispatcher/dispatcher.py @@ -768,7 +768,7 @@ class Dispatcher(DataMixin, ContextInstanceMixin): .. code-block:: python3 - dp.register_chosen_inline_handler(some_chosen_inline_handler, lambda chosen_inline_query: True) + dp.register_chosen_inline_handler(some_chosen_inline_handler, lambda chosen_inline_result: True) :param callback: :param state: @@ -793,8 +793,8 @@ class Dispatcher(DataMixin, ContextInstanceMixin): .. code-block:: python3 - @dp.chosen_inline_handler(lambda chosen_inline_query: True) - async def some_chosen_inline_handler(chosen_inline_query: types.ChosenInlineResult) + @dp.chosen_inline_handler(lambda chosen_inline_result: True) + async def some_chosen_inline_handler(chosen_inline_result: types.ChosenInlineResult) :param state: :param custom_filters: diff --git a/aiogram/types/update.py b/aiogram/types/update.py index 4d5a74d5..957fdfa6 100644 --- a/aiogram/types/update.py +++ b/aiogram/types/update.py @@ -11,7 +11,7 @@ from .poll import Poll, PollAnswer from .pre_checkout_query import PreCheckoutQuery from .shipping_query import ShippingQuery from .chat_join_request import ChatJoinRequest -from ..utils import helper, deprecated +from ..utils import helper class Update(base.TelegramObject): @@ -70,12 +70,6 @@ class AllowedUpdates(helper.Helper): CHAT_MEMBER = helper.ListItem() # chat_member CHAT_JOIN_REQUEST = helper.ListItem() # chat_join_request - CHOSEN_INLINE_QUERY = deprecated.DeprecatedReadOnlyClassVar( - "`CHOSEN_INLINE_QUERY` is a deprecated value for allowed update. " - "Use `CHOSEN_INLINE_RESULT`", - new_value_getter=lambda cls: cls.CHOSEN_INLINE_RESULT, - ) - @classmethod def default(cls): return [] From b39672f9b6641dea538d9176546e60f97dc55f74 Mon Sep 17 00:00:00 2001 From: Oleg A Date: Tue, 8 Feb 2022 03:29:53 +0300 Subject: [PATCH 2/9] [2.x] Don't save error as a file (#813) * fix: don't save error as file Raise an aiohttp.ClientResponseError if the response status is 400 or higher #799 * fix tests Co-authored-by: darksidecat <58224121+darksidecat@users.noreply.github.com> --- aiogram/bot/base.py | 8 +++- tests/test_bot/test_bot_download_file.py | 35 +++++++++++------ tests/types/test_mixins.py | 48 +++++++++++++++--------- 3 files changed, 60 insertions(+), 31 deletions(-) diff --git a/aiogram/bot/base.py b/aiogram/bot/base.py index f885e6dc..8fd20949 100644 --- a/aiogram/bot/base.py +++ b/aiogram/bot/base.py @@ -277,7 +277,13 @@ class BaseBot: dest = destination if isinstance(destination, io.IOBase) else open(destination, 'wb') session = await self.get_session() - async with session.get(url, timeout=timeout, proxy=self.proxy, proxy_auth=self.proxy_auth) as response: + async with session.get( + url, + timeout=timeout, + proxy=self.proxy, + proxy_auth=self.proxy_auth, + raise_for_status=True, + ) as response: while True: chunk = await response.content.read(chunk_size) if not chunk: diff --git a/tests/test_bot/test_bot_download_file.py b/tests/test_bot/test_bot_download_file.py index 195a06f7..11b16934 100644 --- a/tests/test_bot/test_bot_download_file.py +++ b/tests/test_bot/test_bot_download_file.py @@ -1,11 +1,14 @@ import os from io import BytesIO from pathlib import Path +from unittest.mock import AsyncMock import pytest +from aiohttp import ClientResponseError from aiogram import Bot from aiogram.types import File +from aiogram.utils.json import json from tests import TOKEN from tests.types.dataset import FILE @@ -14,12 +17,9 @@ pytestmark = pytest.mark.asyncio @pytest.fixture(name='bot') async def bot_fixture(): - async def get_file(): - return File(**FILE) - """ Bot fixture """ _bot = Bot(TOKEN) - _bot.get_file = get_file + _bot.get_file = AsyncMock(return_value=File(**FILE)) yield _bot session = await _bot.get_session() await session.close() @@ -37,43 +37,54 @@ def tmppath(tmpdir, request): os.chdir(request.config.invocation_dir) +@pytest.fixture() +def get_file_response(aresponses): + aresponses.add(response=aresponses.Response(body=json.dumps(FILE))) + + class TestBotDownload: - async def test_download_file(self, tmppath, bot, file): + async def test_download_file(self, tmppath, bot, file, get_file_response): f = await bot.download_file(file_path=file.file_path) assert len(f.read()) != 0 - async def test_download_file_destination(self, tmppath, bot, file): + async def test_download_file_destination(self, tmppath, bot, file, get_file_response): await bot.download_file(file_path=file.file_path, destination="test.file") assert os.path.isfile(tmppath.joinpath('test.file')) - async def test_download_file_destination_with_dir(self, tmppath, bot, file): + async def test_download_file_destination_with_dir(self, tmppath, bot, file, get_file_response): await bot.download_file(file_path=file.file_path, destination=os.path.join('dir_name', 'file_name')) assert os.path.isfile(tmppath.joinpath('dir_name', 'file_name')) - async def test_download_file_destination_raise_file_not_found(self, tmppath, bot, file): + async def test_download_file_destination_raise_file_not_found(self, tmppath, bot, file, get_file_response): with pytest.raises(FileNotFoundError): await bot.download_file(file_path=file.file_path, destination=os.path.join('dir_name', 'file_name'), make_dirs=False) - async def test_download_file_destination_io_bytes(self, tmppath, bot, file): + async def test_download_file_destination_io_bytes(self, tmppath, bot, file, get_file_response): f = BytesIO() await bot.download_file(file_path=file.file_path, destination=f) assert len(f.read()) != 0 - async def test_download_file_raise_value_error(self, tmppath, bot, file): + async def test_download_file_raise_value_error(self, tmppath, bot, file, get_file_response): with pytest.raises(ValueError): await bot.download_file(file_path=file.file_path, destination="a", destination_dir="b") - async def test_download_file_destination_dir(self, tmppath, bot, file): + async def test_download_file_destination_dir(self, tmppath, bot, file, get_file_response): await bot.download_file(file_path=file.file_path, destination_dir='test_dir') assert os.path.isfile(tmppath.joinpath('test_dir', file.file_path)) - async def test_download_file_destination_dir_raise_file_not_found(self, tmppath, bot, file): + async def test_download_file_destination_dir_raise_file_not_found(self, tmppath, bot, file, get_file_response): with pytest.raises(FileNotFoundError): await bot.download_file(file_path=file.file_path, destination_dir='test_dir', make_dirs=False) assert os.path.isfile(tmppath.joinpath('test_dir', file.file_path)) + + async def test_download_file_404(self, tmppath, bot, file): + with pytest.raises(ClientResponseError) as exc_info: + await bot.download_file(file_path=file.file_path) + + assert exc_info.value.status == 404 diff --git a/tests/types/test_mixins.py b/tests/types/test_mixins.py index 4ee4381a..c3f816c8 100644 --- a/tests/types/test_mixins.py +++ b/tests/types/test_mixins.py @@ -1,12 +1,15 @@ import os from io import BytesIO from pathlib import Path +from unittest.mock import AsyncMock import pytest +from aiohttp import ClientResponseError from aiogram import Bot from aiogram.types import File from aiogram.types.mixins import Downloadable +from aiogram.utils.json import json from tests import TOKEN from tests.types.dataset import FILE @@ -18,7 +21,8 @@ async def bot_fixture(): """ Bot fixture """ _bot = Bot(TOKEN) yield _bot - await (await _bot.get_session()).close() + session = await _bot.get_session() + await session.close() @pytest.fixture @@ -30,73 +34,81 @@ def tmppath(tmpdir, request): @pytest.fixture def downloadable(bot): - async def get_file(): - return File(**FILE) - downloadable = Downloadable() - downloadable.get_file = get_file + downloadable.get_file = AsyncMock(return_value=File(**FILE)) downloadable.bot = bot return downloadable +@pytest.fixture() +def get_file_response(aresponses): + aresponses.add(response=aresponses.Response(body=json.dumps(FILE))) + + class TestDownloadable: - async def test_download_make_dirs_false_nodir(self, tmppath, downloadable): + async def test_download_make_dirs_false_nodir(self, tmppath, downloadable, get_file_response): with pytest.raises(FileNotFoundError): await downloadable.download(make_dirs=False) - async def test_download_make_dirs_false_mkdir(self, tmppath, downloadable): + async def test_download_make_dirs_false_mkdir(self, tmppath, downloadable, get_file_response): os.mkdir('voice') await downloadable.download(make_dirs=False) assert os.path.isfile(tmppath.joinpath(FILE["file_path"])) - async def test_download_make_dirs_true(self, tmppath, downloadable): + async def test_download_make_dirs_true(self, tmppath, downloadable, get_file_response): await downloadable.download(make_dirs=True) assert os.path.isfile(tmppath.joinpath(FILE["file_path"])) - async def test_download_deprecation_warning(self, tmppath, downloadable): + async def test_download_deprecation_warning(self, tmppath, downloadable, get_file_response): with pytest.deprecated_call(): await downloadable.download("test.file") - async def test_download_destination(self, tmppath, downloadable): + async def test_download_destination(self, tmppath, downloadable, get_file_response): with pytest.deprecated_call(): await downloadable.download("test.file") assert os.path.isfile(tmppath.joinpath('test.file')) - async def test_download_destination_dir_exist(self, tmppath, downloadable): + async def test_download_destination_dir_exist(self, tmppath, downloadable, get_file_response): os.mkdir("test_folder") with pytest.deprecated_call(): await downloadable.download("test_folder") assert os.path.isfile(tmppath.joinpath('test_folder', FILE["file_path"])) - async def test_download_destination_with_dir(self, tmppath, downloadable): + async def test_download_destination_with_dir(self, tmppath, downloadable, get_file_response): with pytest.deprecated_call(): await downloadable.download(os.path.join('dir_name', 'file_name')) assert os.path.isfile(tmppath.joinpath('dir_name', 'file_name')) - async def test_download_destination_io_bytes(self, tmppath, downloadable): + async def test_download_destination_io_bytes(self, tmppath, downloadable, get_file_response): file = BytesIO() with pytest.deprecated_call(): await downloadable.download(file) assert len(file.read()) != 0 - async def test_download_raise_value_error(self, tmppath, downloadable): + async def test_download_raise_value_error(self, tmppath, downloadable, get_file_response): with pytest.raises(ValueError): await downloadable.download(destination_dir="a", destination_file="b") - async def test_download_destination_dir(self, tmppath, downloadable): + async def test_download_destination_dir(self, tmppath, downloadable, get_file_response): await downloadable.download(destination_dir='test_dir') assert os.path.isfile(tmppath.joinpath('test_dir', FILE["file_path"])) - async def test_download_destination_file(self, tmppath, downloadable): + async def test_download_destination_file(self, tmppath, downloadable, get_file_response): await downloadable.download(destination_file='file_name') assert os.path.isfile(tmppath.joinpath('file_name')) - async def test_download_destination_file_with_dir(self, tmppath, downloadable): + async def test_download_destination_file_with_dir(self, tmppath, downloadable, get_file_response): await downloadable.download(destination_file=os.path.join('dir_name', 'file_name')) assert os.path.isfile(tmppath.joinpath('dir_name', 'file_name')) - async def test_download_io_bytes(self, tmppath, downloadable): + async def test_download_io_bytes(self, tmppath, downloadable, get_file_response): file = BytesIO() await downloadable.download(destination_file=file) assert len(file.read()) != 0 + + async def test_download_404(self, tmppath, downloadable): + with pytest.raises(ClientResponseError) as exc_info: + await downloadable.download(destination_file='file_name') + + assert exc_info.value.status == 404 From 24e933bdde4f1eb1532aabcf860111ea4a9b79d8 Mon Sep 17 00:00:00 2001 From: Oleg A Date: Tue, 8 Feb 2022 03:30:41 +0300 Subject: [PATCH 3/9] Fix: default parent for `__setitem__` (#806) * fix: self is default parent * chore: mv bot fixture * chore: add update_chat test * fix: string CHAT_PHOTO data --- aiogram/types/base.py | 2 +- tests/conftest.py | 16 +++++++++++++++ tests/test_bot.py | 8 -------- tests/test_dispatcher.py | 8 -------- tests/test_message.py | 10 +--------- tests/types/dataset.py | 42 ++++++++++++++++++++++++++++++++++++++++ tests/types/test_chat.py | 16 +++++++++++++-- 7 files changed, 74 insertions(+), 28 deletions(-) diff --git a/aiogram/types/base.py b/aiogram/types/base.py index 5bb29472..cca3d5f1 100644 --- a/aiogram/types/base.py +++ b/aiogram/types/base.py @@ -240,7 +240,7 @@ class TelegramObject(ContextInstanceMixin, metaclass=MetaTelegramObject): :return: """ if key in self.props: - return self.props[key].set_value(self, value, self.conf.get('parent', None)) + return self.props[key].set_value(self, value, self.conf.get('parent', self)) self.values[key] = value # Log warning when Telegram silently adds new Fields diff --git a/tests/conftest.py b/tests/conftest.py index b56c7b77..455f8b0d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,12 @@ +import asyncio + import aioredis import pytest from _pytest.config import UsageError +from aiogram import Bot +from . import TOKEN + try: import aioredis.util except ImportError: @@ -72,3 +77,14 @@ def redis_options(request): raise UsageError(f"Invalid redis URI {redis_uri!r}: {e}") raise UsageError("Unsupported aioredis version") + + +@pytest.fixture(name='bot') +async def bot_fixture(): + """Bot fixture.""" + bot = Bot(TOKEN) + yield bot + session = await bot.get_session() + if session and not session.closed: + await session.close() + await asyncio.sleep(0.2) diff --git a/tests/test_bot.py b/tests/test_bot.py index b2da7952..eea20b44 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -6,14 +6,6 @@ from . import FakeTelegram, TOKEN, BOT_ID pytestmark = pytest.mark.asyncio -@pytest.fixture(name='bot') -async def bot_fixture(): - """ Bot fixture """ - _bot = Bot(TOKEN, parse_mode=types.ParseMode.MARKDOWN_V2) - yield _bot - await _bot.close() - - async def test_get_me(bot: Bot): """ getMe method test """ from .types.dataset import USER diff --git a/tests/test_dispatcher.py b/tests/test_dispatcher.py index 81ae565c..e38d7c4a 100644 --- a/tests/test_dispatcher.py +++ b/tests/test_dispatcher.py @@ -5,14 +5,6 @@ from aiogram import Dispatcher, Bot pytestmark = pytest.mark.asyncio -@pytest.fixture(name='bot') -async def bot_fixture(): - """ Bot fixture """ - _bot = Bot(token='123456789:AABBCCDDEEFFaabbccddeeff-1234567890') - yield _bot - await _bot.close() - - class TestDispatcherInit: async def test_successful_init(self, bot): """ diff --git a/tests/test_message.py b/tests/test_message.py index 6fca789f..bc53dfbc 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -8,16 +8,8 @@ from . import FakeTelegram, TOKEN pytestmark = pytest.mark.asyncio -@pytest.fixture(name='bot') -async def bot_fixture(): - """ Bot fixture """ - _bot = Bot(TOKEN, parse_mode=types.ParseMode.HTML) - yield _bot - await _bot.close() - - @pytest.fixture() -async def message(bot): +async def message(bot: Bot): """ Message fixture :param bot: Telegram bot fixture diff --git a/tests/types/dataset.py b/tests/types/dataset.py index be23da9e..bd73f377 100644 --- a/tests/types/dataset.py +++ b/tests/types/dataset.py @@ -19,6 +19,14 @@ CHAT = { "type": "private", } +CHAT_PHOTO = { + "small_file_id": "small_file_id", + "small_file_unique_id": "small_file_unique_id", + "big_file_id": "big_file_id", + "big_file_unique_id": "big_file_unique_id", +} + + PHOTO = { "file_id": "AgADBAADFak0G88YZAf8OAug7bHyS9x2ZxkABHVfpJywcloRAAGAAQABAg", "file_size": 1101, @@ -485,3 +493,37 @@ REPLY_KEYBOARD_MARKUP = { "keyboard": [[{"text": "something here"}]], "resize_keyboard": True, } + +CHAT_PERMISSIONS = { + "can_send_messages": True, + "can_send_media_messages": True, + "can_send_polls": True, + "can_send_other_messages": True, + "can_add_web_page_previews": True, + "can_change_info": True, + "can_invite_users": True, + "can_pin_messages": True, +} + +CHAT_LOCATION = { + "location": LOCATION, + "address": "address", +} + +FULL_CHAT = { + **CHAT, + "photo": CHAT_PHOTO, + "bio": "bio", + "has_private_forwards": False, + "description": "description", + "invite_link": "invite_link", + "pinned_message": MESSAGE, + "permissions": CHAT_PERMISSIONS, + "slow_mode_delay": 10, + "message_auto_delete_time": 60, + "has_protected_content": True, + "sticker_set_name": "sticker_set_name", + "can_set_sticker_set": True, + "linked_chat_id": -1234567890, + "location": CHAT_LOCATION, +} diff --git a/tests/types/test_chat.py b/tests/types/test_chat.py index 1caa228d..c8e20146 100644 --- a/tests/types/test_chat.py +++ b/tests/types/test_chat.py @@ -1,5 +1,10 @@ -from aiogram import types -from .dataset import CHAT +import pytest + +from aiogram import Bot, types +from .dataset import CHAT, FULL_CHAT +from .. import FakeTelegram + +pytestmark = pytest.mark.asyncio chat = types.Chat(**CHAT) @@ -59,3 +64,10 @@ def test_chat_actions(): assert types.ChatActions.FIND_LOCATION == 'find_location' assert types.ChatActions.RECORD_VIDEO_NOTE == 'record_video_note' assert types.ChatActions.UPLOAD_VIDEO_NOTE == 'upload_video_note' + + +async def test_update_chat(bot: Bot): + Bot.set_current(bot) + async with FakeTelegram(message_data=FULL_CHAT): + await chat.update_chat() + assert chat.to_python() == types.Chat(**FULL_CHAT).to_python() From bb1c774bccd084248bf47338255d1d375949e40b Mon Sep 17 00:00:00 2001 From: Grigory Statsenko Date: Sun, 13 Feb 2022 15:56:15 +0300 Subject: [PATCH 4/9] Add support for custom kwargs for AsyncIOMotorClient in MongoStorage (#831) --- aiogram/contrib/fsm_storage/mongo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aiogram/contrib/fsm_storage/mongo.py b/aiogram/contrib/fsm_storage/mongo.py index 0055743a..7a128f1c 100644 --- a/aiogram/contrib/fsm_storage/mongo.py +++ b/aiogram/contrib/fsm_storage/mongo.py @@ -50,7 +50,7 @@ class MongoStorage(BaseStorage): self._uri = uri self._username = username self._password = password - self._kwargs = kwargs + self._kwargs = kwargs # custom client options like SSL configuration, etc. self._mongo: Optional[AsyncIOMotorClient] = None self._db: Optional[AsyncIOMotorDatabase] = None @@ -63,7 +63,7 @@ class MongoStorage(BaseStorage): if self._uri: try: - self._mongo = AsyncIOMotorClient(self._uri) + self._mongo = AsyncIOMotorClient(self._uri, **self._kwargs) except pymongo.errors.ConfigurationError as e: if "query() got an unexpected keyword argument 'lifetime'" in e.args[0]: import logging From 4a4eb51bd407c2591d12ee265e9e4c1bd356ac1d Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Sun, 20 Feb 2022 17:11:04 +0200 Subject: [PATCH 5/9] Changed skip updates method (#842) --- aiogram/dispatcher/dispatcher.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aiogram/dispatcher/dispatcher.py b/aiogram/dispatcher/dispatcher.py index 5b3cafd3..7abe1d8d 100644 --- a/aiogram/dispatcher/dispatcher.py +++ b/aiogram/dispatcher/dispatcher.py @@ -216,11 +216,11 @@ class Dispatcher(DataMixin, ContextInstanceMixin): async def skip_updates(self): """ You can skip old incoming updates from queue. - This method is not recommended to use if you use payments or you bot has high-load. + This method is not recommended for using in production. - :return: None + Note that the webhook will be deleted! """ - await self.bot.get_updates(offset=-1, timeout=1) + await self.bot.delete_webhook(drop_pending_updates=True) async def process_updates(self, updates, fast: bool = True): """ From fe48a4a0141c5e4a264004e0a069dbad65f1dec7 Mon Sep 17 00:00:00 2001 From: viuipan <37146584+viuipan@users.noreply.github.com> Date: Wed, 2 Mar 2022 02:04:47 +0300 Subject: [PATCH 6/9] fix issue 812 (#843) --- aiogram/types/input_message_content.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aiogram/types/input_message_content.py b/aiogram/types/input_message_content.py index 8406bd05..6b8bad22 100644 --- a/aiogram/types/input_message_content.py +++ b/aiogram/types/input_message_content.py @@ -145,7 +145,7 @@ class InputTextMessageContent(InputMessageContent): """ message_text: base.String = fields.Field() parse_mode: typing.Optional[base.String] = fields.Field() - caption_entities: typing.Optional[typing.List[MessageEntity]] = fields.Field() + entities: typing.Optional[typing.List[MessageEntity]] = fields.Field() disable_web_page_preview: base.Boolean = fields.Field() def safe_get_parse_mode(self): @@ -164,7 +164,7 @@ class InputTextMessageContent(InputMessageContent): self, message_text: base.String, parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + entities: typing.Optional[typing.List[MessageEntity]] = None, disable_web_page_preview: typing.Optional[base.Boolean] = None, ): if parse_mode is None: @@ -175,7 +175,7 @@ class InputTextMessageContent(InputMessageContent): super().__init__( message_text=message_text, parse_mode=parse_mode, - caption_entities=caption_entities, + entities=entities, disable_web_page_preview=disable_web_page_preview, ) From 613cfb8df087bca5e9bcc5a2f3df8bbda1233094 Mon Sep 17 00:00:00 2001 From: Vishwa Kumaresh Date: Sat, 5 Mar 2022 06:04:53 +0530 Subject: [PATCH 7/9] fix: setup.py (#856) Changed requires_python to python_requires --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a381507a..afa3f673 100755 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ setup( url='https://github.com/aiogram/aiogram', license='MIT', author='Alex Root Junior', - requires_python='>=3.7', + python_requires='>=3.7', author_email='jroot.junior@gmail.com', description='Is a pretty simple and fully asynchronous framework for Telegram Bot API', long_description=get_description(), From 51d3ad7d94a19be9533f699652d8b395830078ad Mon Sep 17 00:00:00 2001 From: Wendirad Demelash <53967346+Wendirad@users.noreply.github.com> Date: Sat, 26 Mar 2022 18:23:35 +0300 Subject: [PATCH 8/9] Fix indentation for `ban_chat_member` function doc string (#867) * Added classifier for Python 3.10 * Fix indentation for `ban_chat_member` function doc string Co-authored-by: Alex Root Junior --- aiogram/bot/bot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index 91c0b283..e2f7fd24 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -1704,9 +1704,9 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): datetime.datetime, datetime.timedelta, None]` :param revoke_messages: Pass True to delete all messages from - the chat for the user that is being removed. If False, the user - will be able to see messages in the group that were sent before - the user was removed. Always True for supergroups and channels. + the chat for the user that is being removed. If False, the user + will be able to see messages in the group that were sent before + the user was removed. Always True for supergroups and channels. :type revoke_messages: :obj:`typing.Optional[base.Boolean]` :return: Returns True on success From 0e2beb24c23ae4e0c2d54e58138f3fbb3591bed3 Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Sat, 16 Apr 2022 18:09:58 +0300 Subject: [PATCH 9/9] Added support of Telegram BOt API 6.0 --- Makefile | 2 +- README.md | 2 +- README.rst | 2 +- aiogram/__init__.py | 4 +- aiogram/bot/api.py | 7 + aiogram/bot/bot.py | 127 +- aiogram/types/__init__.py | 21 + aiogram/types/chat_administrator_rights.py | 21 + aiogram/types/chat_member.py | 2 +- aiogram/types/inline_keyboard.py | 10 +- aiogram/types/menu_button.py | 86 ++ aiogram/types/message.py | 1142 +++++++++-------- aiogram/types/reply_keyboard.py | 4 + aiogram/types/sent_web_app_message.py | 11 + aiogram/types/video_chat_ended.py | 13 + .../types/video_chat_participants_invited.py | 16 + aiogram/types/video_chat_scheduled.py | 14 + aiogram/types/video_chat_started.py | 11 + aiogram/types/web_app_data.py | 12 + aiogram/types/web_app_info.py | 11 + aiogram/types/webhook_info.py | 1 + docs/source/index.rst | 2 +- test.html | 22 + 23 files changed, 969 insertions(+), 574 deletions(-) create mode 100644 aiogram/types/chat_administrator_rights.py create mode 100644 aiogram/types/menu_button.py create mode 100644 aiogram/types/sent_web_app_message.py create mode 100644 aiogram/types/video_chat_ended.py create mode 100644 aiogram/types/video_chat_participants_invited.py create mode 100644 aiogram/types/video_chat_scheduled.py create mode 100644 aiogram/types/video_chat_started.py create mode 100644 aiogram/types/web_app_data.py create mode 100644 aiogram/types/web_app_info.py create mode 100644 test.html diff --git a/Makefile b/Makefile index 662ad49f..51d5af96 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VENV_NAME := venv +VENV_NAME := .venv PYTHON := $(VENV_NAME)/bin/python AIOGRAM_VERSION := $(shell $(PYTHON) -c "import aiogram;print(aiogram.__version__)") diff --git a/README.md b/README.md index 75736386..6db8833f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![PyPi status](https://img.shields.io/pypi/status/aiogram.svg?style=flat-square)](https://pypi.python.org/pypi/aiogram) [![Downloads](https://img.shields.io/pypi/dm/aiogram.svg?style=flat-square)](https://pypi.python.org/pypi/aiogram) [![Supported python versions](https://img.shields.io/pypi/pyversions/aiogram.svg?style=flat-square)](https://pypi.python.org/pypi/aiogram) -[![Telegram Bot API](https://img.shields.io/badge/Telegram%20Bot%20API-5.7-blue.svg?style=flat-square&logo=telegram)](https://core.telegram.org/bots/api) +[![Telegram Bot API](https://img.shields.io/badge/Telegram%20Bot%20API-6.0-blue.svg?style=flat-square&logo=telegram)](https://core.telegram.org/bots/api) [![Documentation Status](https://img.shields.io/readthedocs/aiogram?style=flat-square)](http://docs.aiogram.dev/en/latest/?badge=latest) [![Github issues](https://img.shields.io/github/issues/aiogram/aiogram.svg?style=flat-square)](https://github.com/aiogram/aiogram/issues) [![MIT License](https://img.shields.io/pypi/l/aiogram.svg?style=flat-square)](https://opensource.org/licenses/MIT) diff --git a/README.rst b/README.rst index 47a7cb9d..1b521252 100644 --- a/README.rst +++ b/README.rst @@ -21,7 +21,7 @@ AIOGramBot :target: https://pypi.python.org/pypi/aiogram :alt: Supported python versions -.. image:: https://img.shields.io/badge/Telegram%20Bot%20API-5.7-blue.svg?style=flat-square&logo=telegram +.. image:: https://img.shields.io/badge/Telegram%20Bot%20API-6.0-blue.svg?style=flat-square&logo=telegram :target: https://core.telegram.org/bots/api :alt: Telegram Bot API diff --git a/aiogram/__init__.py b/aiogram/__init__.py index 6c8d3f4c..e3144b31 100644 --- a/aiogram/__init__.py +++ b/aiogram/__init__.py @@ -43,5 +43,5 @@ __all__ = ( 'utils', ) -__version__ = '2.19' -__api_version__ = '5.7' +__version__ = '2.20' +__api_version__ = '6.0' diff --git a/aiogram/bot/api.py b/aiogram/bot/api.py index 5f609227..f2cc7234 100644 --- a/aiogram/bot/api.py +++ b/aiogram/bot/api.py @@ -278,6 +278,13 @@ class Methods(Helper): # Inline mode ANSWER_INLINE_QUERY = Item() # answerInlineQuery + ANSWER_WEB_APP_QUERY = Item() # answerWebAppQuery + SET_CHAT_MENU_BUTTON = Item() # setChatMenuButton + GET_CHAT_MENU_BUTTON = Item() # getChatMenuButton + + SET_MY_DEFAULT_ADMINISTRATOR_RIGHTS = Item() # setMyDefaultAdministratorRights + GET_MY_DEFAULT_ADMINISTRATOR_RIGHTS = Item() # getMyDefaultAdministratorRights + # Payments SEND_INVOICE = Item() # sendInvoice ANSWER_SHIPPING_QUERY = Item() # answerShippingQuery diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index e2f7fd24..461f68b2 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -8,7 +8,7 @@ import warnings from .base import BaseBot, api from .. import types from ..types import base -from ..utils.deprecated import deprecated, removed_argument +from ..utils.deprecated import deprecated from ..utils.exceptions import ValidationError from ..utils.mixins import DataMixin, ContextInstanceMixin from ..utils.payload import generate_payload, prepare_arg, prepare_attachment, prepare_file @@ -1089,7 +1089,8 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): # Check MediaGroup quantity if not (1 <= len(media.media) <= 10): - raise ValidationError("Media group must include 2-10 items as written in docs, but also it works with 1 element") + raise ValidationError( + "Media group must include 2-10 items as written in docs, but also it works with 1 element") files = dict(media.get_files()) @@ -1834,6 +1835,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): can_restrict_members: typing.Optional[base.Boolean] = None, can_pin_messages: typing.Optional[base.Boolean] = None, can_promote_members: typing.Optional[base.Boolean] = None, + can_manage_video_chats: typing.Optional[base.Boolean] = None, ) -> base.Boolean: """ Use this method to promote or demote a user in a supergroup or a channel. @@ -1885,9 +1887,17 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): directly or indirectly (promoted by administrators that were appointed by him) :type can_promote_members: :obj:`typing.Optional[base.Boolean]` + :param can_manage_video_chats: Pass True, if the administrator can manage video chats + :return: Returns True on success :rtype: :obj:`base.Boolean` """ + if can_manage_voice_chats: + warnings.warn( + "Argument `can_manage_voice_chats` was renamed to `can_manage_video_chats` and will be removed in aiogram 2.21") + can_manage_video_chats = can_manage_voice_chats + can_manage_voice_chats = None + payload = generate_payload(**locals()) return await self.request(api.Methods.PROMOTE_CHAT_MEMBER, payload) @@ -1910,11 +1920,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): return await self.request(api.Methods.SET_CHAT_ADMINISTRATOR_CUSTOM_TITLE, payload) - @removed_argument("until_date", "2.19") async def ban_chat_sender_chat( - self, - chat_id: typing.Union[base.Integer, base.String], - sender_chat_id: base.Integer, + self, + chat_id: typing.Union[base.Integer, base.String], + sender_chat_id: base.Integer, ): """Ban a channel chat in a supergroup or a channel. @@ -1937,9 +1946,9 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): return await self.request(api.Methods.BAN_CHAT_SENDER_CHAT, payload) async def unban_chat_sender_chat( - self, - chat_id: typing.Union[base.Integer, base.String], - sender_chat_id: base.Integer, + self, + chat_id: typing.Union[base.Integer, base.String], + sender_chat_id: base.Integer, ): """Unban a previously banned channel chat in a supergroup or channel. @@ -2587,6 +2596,87 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.GET_MY_COMMANDS, payload) return [types.BotCommand(**bot_command_data) for bot_command_data in result] + async def set_chat_menu_button(self, chat_id: typing.Optional[base.Integer] = None, + menu_button: typing.Optional[types.MenuButton] = None) -> bool: + """ + Use this method to change bot's menu button in a private chat, or the default menu button. + + Returns True on success. + + Source https://core.telegram.org/bots/api#setchatmenubutton + + :param chat_id: Unique identifier for the target private chat. + If not specified, default bot's menu button will be changed + :param menu_button: + A JSON-serialized object for the new bot's menu button. Defaults to MenuButtonDefault + :return: Returns True on success. + """ + menu_button = prepare_arg(menu_button) + payload = generate_payload(**locals()) + + return await self.request(api.Methods.SET_CHAT_MENU_BUTTON, payload) + + async def get_chat_menu_button(self, chat_id: typing.Optional[base.Integer] = None) -> typing.Union[ + "types.MenuButtonCommands", + "types.MenuButtonDefault", + "types.MenuButtonWebApp", + ]: + """ + Use this method to get the current value of the bot's menu button in a private chat, + or the default menu button. + + Returns MenuButton on success. + + Source https://core.telegram.org/bots/api#getchatmenu + + :param chat_id: Unique identifier for the target private chat. If not specified, + default bot's menu button will be returned + :return: Returns MenuButton on success. + """ + payload = generate_payload(**locals()) + + result = await self.request(api.Methods.GET_CHAT_MENU_BUTTON, payload) + return types.MenuButton.resolve(**result) + + async def set_my_default_administrator_rights(self, rights: typing.Optional[types.ChatAdministratorRights] = None, + for_channels: typing.Optional[base.Boolean] = None) -> base.Boolean: + """ + Use this method to change default administrator rights of the bot for adding it as an administrator + to groups or channels. + Returns True on success. + + Source: https://core.telegram.org/bots/api#setmydefaultadministratorrights + + :param rights: A JSON-serialized object, describing new default administrator rights. + If not specified, the default administrator rights will be cleared. + :param for_channels: + Pass True to change default administrator rights of the bot in channels. + Otherwise, default administrator rights of the bot for groups and supergroups will be changed. + :return: Returns True on success. + """ + rights = prepare_arg(rights) + payload = generate_payload(**locals()) + + return await self.request(api.Methods.SET_MY_DEFAULT_ADMINISTRATOR_RIGHTS, payload) + + async def get_my_default_administrator_rights(self, + for_channels: typing.Optional[base.Boolean] = None + ) -> types.ChatAdministratorRights: + """ + Use this method to get the current default administrator rights of the bot. + Returns ChatAdministratorRights on success. + + Source: https://core.telegram.org/bots/api#getmydefaultadministratorrights + + :param for_channels: Pass True to get default administrator rights of the bot in channels. + Otherwise, default administrator rights of the bot for groups and supergroups will be returned. + :return: + """ + payload = generate_payload(**locals()) + + result = await self.request(api.Methods.GET_MY_DEFAULT_ADMINISTRATOR_RIGHTS, payload) + return types.ChatAdministratorRights(**result) + async def edit_message_text(self, text: base.String, chat_id: typing.Union[base.Integer, base.String, None] = None, @@ -3133,6 +3223,25 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): return await self.request(api.Methods.ANSWER_INLINE_QUERY, payload) + async def answer_web_app_query(self, web_app_query_id: base.String, + result: types.InlineQueryResult) -> types.SentWebAppMessage: + """ + Use this method to set result of interaction with web app and send corresponding message + on behalf of the user to the chat from which the query originated. + On success, SentWebAppMessage is returned. + + Source https://core.telegram.org/bots/api#answerwebappquery + + :param web_app_query_id: Unique identifier for the answered query + :param result: A JSON-serialized object with a description of the message to send + :return: On success, SentWebAppMessage is returned. + """ + result = prepare_arg(result) + payload = generate_payload(**locals()) + + response = await self.request(api.Methods.ANSWER_WEB_APP_QUERY, payload) + return types.SentWebAppMessage(**response) + # === Payments === # https://core.telegram.org/bots/api#payments diff --git a/aiogram/types/__init__.py b/aiogram/types/__init__.py index 9378b32b..2c272fef 100644 --- a/aiogram/types/__init__.py +++ b/aiogram/types/__init__.py @@ -11,6 +11,7 @@ from .bot_command_scope import BotCommandScope, BotCommandScopeAllChatAdministra from .callback_game import CallbackGame from .callback_query import CallbackQuery from .chat import Chat, ChatActions, ChatType +from .chat_administrator_rights import ChatAdministratorRights from .chat_invite_link import ChatInviteLink from .chat_join_request import ChatJoinRequest from .chat_location import ChatLocation @@ -48,6 +49,7 @@ from .labeled_price import LabeledPrice from .location import Location from .login_url import LoginUrl from .mask_position import MaskPosition +from .menu_button import MenuButton, MenuButtonCommands, MenuButtonWebApp, MenuButtonDefault from .message import ContentType, ContentTypes, Message, ParseMode from .message_auto_delete_timer_changed import MessageAutoDeleteTimerChanged from .message_entity import MessageEntity, MessageEntityType @@ -64,6 +66,7 @@ from .pre_checkout_query import PreCheckoutQuery from .proximity_alert_triggered import ProximityAlertTriggered from .reply_keyboard import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove, KeyboardButtonPollType from .response_parameters import ResponseParameters +from .sent_web_app_message import SentWebAppMessage from .shipping_address import ShippingAddress from .shipping_option import ShippingOption from .shipping_query import ShippingQuery @@ -75,12 +78,18 @@ from .user import User from .user_profile_photos import UserProfilePhotos from .venue import Venue from .video import Video +from .video_chat_ended import VideoChatEnded +from .video_chat_participants_invited import VideoChatParticipantsInvited +from .video_chat_scheduled import VideoChatScheduled +from .video_chat_started import VideoChatStarted from .video_note import VideoNote from .voice import Voice from .voice_chat_ended import VoiceChatEnded from .voice_chat_participants_invited import VoiceChatParticipantsInvited from .voice_chat_scheduled import VoiceChatScheduled from .voice_chat_started import VoiceChatStarted +from .web_app_data import WebAppData +from .web_app_info import WebAppInfo from .webhook_info import WebhookInfo __all__ = ( @@ -102,6 +111,7 @@ __all__ = ( 'CallbackQuery', 'Chat', 'ChatActions', + 'ChatAdministratorRights', 'ChatInviteLink', 'ChatJoinRequest', 'ChatLocation', @@ -174,6 +184,10 @@ __all__ = ( 'Location', 'LoginUrl', 'MaskPosition', + 'MenuButton', + 'MenuButtonCommands', + 'MenuButtonWebApp', + 'MenuButtonDefault', 'MediaGroup', 'Message', 'MessageAutoDeleteTimerChanged', @@ -201,6 +215,7 @@ __all__ = ( 'ReplyKeyboardMarkup', 'ReplyKeyboardRemove', 'ResponseParameters', + 'SentWebAppMessage', 'ShippingAddress', 'ShippingOption', 'ShippingQuery', @@ -212,12 +227,18 @@ __all__ = ( 'UserProfilePhotos', 'Venue', 'Video', + 'VideoChatEnded', + 'VideoChatParticipantsInvited', + 'VideoChatScheduled', + 'VideoChatStarted', 'VideoNote', 'Voice', 'VoiceChatEnded', 'VoiceChatParticipantsInvited', 'VoiceChatScheduled', 'VoiceChatStarted', + 'WebAppData', + 'WebAppInfo', 'WebhookInfo', 'base', 'fields', diff --git a/aiogram/types/chat_administrator_rights.py b/aiogram/types/chat_administrator_rights.py new file mode 100644 index 00000000..20be595b --- /dev/null +++ b/aiogram/types/chat_administrator_rights.py @@ -0,0 +1,21 @@ +from . import base +from . import fields + + +class ChatAdministratorRights(base.TelegramObject): + """ + Represents rights of an administrator in a chat. + + Source: https://core.telegram.org/bots/api#chatadministratorrights + """ + is_anonymous: base.Boolean = fields.Field() + can_manage_chat: base.Boolean = fields.Field() + can_delete_messages: base.Boolean = fields.Field() + can_manage_video_chats: base.Boolean = fields.Field() + can_restrict_members: base.Boolean = fields.Field() + can_promote_members: base.Boolean = fields.Field() + can_change_info: base.Boolean = fields.Field() + can_invite_users: base.Boolean = fields.Field() + can_post_messages: base.Boolean = fields.Field() + can_edit_messages: base.Boolean = fields.Field() + can_pin_messages: base.Boolean = fields.Field() diff --git a/aiogram/types/chat_member.py b/aiogram/types/chat_member.py index ecbf9d2c..689d7f46 100644 --- a/aiogram/types/chat_member.py +++ b/aiogram/types/chat_member.py @@ -5,7 +5,6 @@ from . import base, fields from .user import User from ..utils import helper - T = typing.TypeVar('T') @@ -153,6 +152,7 @@ class ChatMemberAdministrator(ChatMember): can_edit_messages: base.Boolean = fields.Field() can_delete_messages: base.Boolean = fields.Field() can_manage_voice_chats: base.Boolean = fields.Field() + can_manage_video_chats: base.Boolean = fields.Field() can_restrict_members: base.Boolean = fields.Field() can_promote_members: base.Boolean = fields.Field() can_change_info: base.Boolean = fields.Field() diff --git a/aiogram/types/inline_keyboard.py b/aiogram/types/inline_keyboard.py index 195c1e67..16d97e58 100644 --- a/aiogram/types/inline_keyboard.py +++ b/aiogram/types/inline_keyboard.py @@ -4,6 +4,7 @@ from . import base from . import fields from .callback_game import CallbackGame from .login_url import LoginUrl +from .web_app_info import WebAppInfo class InlineKeyboardMarkup(base.TelegramObject): @@ -95,6 +96,7 @@ class InlineKeyboardButton(base.TelegramObject): switch_inline_query_current_chat: base.String = fields.Field() callback_game: CallbackGame = fields.Field(base=CallbackGame) pay: base.Boolean = fields.Field() + web_app: WebAppInfo = fields.Field(base=WebAppInfo) def __init__(self, text: base.String, url: base.String = None, @@ -103,7 +105,9 @@ class InlineKeyboardButton(base.TelegramObject): switch_inline_query: base.String = None, switch_inline_query_current_chat: base.String = None, callback_game: CallbackGame = None, - pay: base.Boolean = None, **kwargs): + pay: base.Boolean = None, + web_app: WebAppInfo = None, + **kwargs): super(InlineKeyboardButton, self).__init__(text=text, url=url, login_url=login_url, @@ -111,4 +115,6 @@ class InlineKeyboardButton(base.TelegramObject): switch_inline_query=switch_inline_query, switch_inline_query_current_chat=switch_inline_query_current_chat, callback_game=callback_game, - pay=pay, **kwargs) + pay=pay, + web_app=web_app, + **kwargs) diff --git a/aiogram/types/menu_button.py b/aiogram/types/menu_button.py new file mode 100644 index 00000000..1fd9cf30 --- /dev/null +++ b/aiogram/types/menu_button.py @@ -0,0 +1,86 @@ +import typing + +from . import base +from . import fields +from .web_app_info import WebAppInfo +from ..utils import helper +from ..utils.helper import Item + + +class MenuButton(base.TelegramObject): + """ + This object describes the bot's menu button in a private chat. It should be one of + + - MenuButtonCommands + - MenuButtonWebApp + - MenuButtonDefault + + If a menu button other than MenuButtonDefault is set for a private chat, + then it is applied in the chat. + Otherwise the default menu button is applied. + By default, the menu button opens the list of bot commands. + """ + type: base.String = fields.Field(default='default') + + @classmethod + def resolve(cls, **kwargs) -> typing.Union[ + "MenuButtonCommands", + "MenuButtonDefault", + "MenuButtonWebApp", + ]: + type_ = kwargs.get('type') + mapping = { + MenuButtonType.DEFAULT: MenuButtonDefault, + MenuButtonType.COMMANDS: MenuButtonCommands, + MenuButtonType.WEB_APP: MenuButtonWebApp, + } + class_ = mapping.get(type_) + if not class_: + raise ValueError(f'Unknown MenuButton type: {type_}') + return class_(**kwargs) + + +class MenuButtonCommands(MenuButton): + """ + Represents a menu button, which opens the bot's list of commands. + + Source: https://core.telegram.org/bots/api#menubuttoncommands + """ + type: base.String = fields.Field(default='commands') + + def __init__(self, **kwargs): + super().__init__(type='commands', **kwargs) + + +class MenuButtonWebApp(MenuButton): + """ + Represents a menu button, which launches a Web App. + + Source: https://core.telegram.org/bots/api#menubuttonwebapp + """ + type: base.String = fields.Field(default='web_app') + text: base.String = fields.Field() + web_app: WebAppInfo = fields.Field(base=WebAppInfo) + + def __init__(self, text: base.String, web_app: WebAppInfo, **kwargs): + super().__init__(type='web_app', text=text, web_app=web_app, **kwargs) + + +class MenuButtonDefault(MenuButton): + """ + Describes that no specific value for the menu button was set. + + Source: https://core.telegram.org/bots/api#menubuttondefault + """ + type: base.String = fields.Field(default='default') + + def __init__(self, **kwargs): + super().__init__(type='default', **kwargs) + + +class MenuButtonType(helper.Helper): + mode = helper.HelperMode.lowercase + + DEFAULT = Item() + COMMANDS = Item() + WEB_APP = Item() diff --git a/aiogram/types/message.py b/aiogram/types/message.py index 10ef8776..5edb4a3e 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -30,12 +30,17 @@ from .successful_payment import SuccessfulPayment from .user import User from .venue import Venue from .video import Video +from .video_chat_ended import VideoChatEnded +from .video_chat_participants_invited import VideoChatParticipantsInvited +from .video_chat_scheduled import VideoChatScheduled +from .video_chat_started import VideoChatStarted from .video_note import VideoNote from .voice import Voice from .voice_chat_ended import VoiceChatEnded from .voice_chat_participants_invited import VoiceChatParticipantsInvited from .voice_chat_scheduled import VoiceChatScheduled from .voice_chat_started import VoiceChatStarted +from .web_app_data import WebAppData from ..utils import helper from ..utils import markdown as md from ..utils.text_decorations import html_decoration, markdown_decoration @@ -106,6 +111,11 @@ class Message(base.TelegramObject): voice_chat_ended: VoiceChatEnded = fields.Field(base=VoiceChatEnded) voice_chat_participants_invited: VoiceChatParticipantsInvited = fields.Field(base=VoiceChatParticipantsInvited) reply_markup: InlineKeyboardMarkup = fields.Field(base=InlineKeyboardMarkup) + web_app_data: WebAppData = fields.Field(base=WebAppData) + video_chat_scheduled: VideoChatScheduled = fields.Field(base=VideoChatScheduled) + video_chat_started: VideoChatStarted = fields.Field(base=VideoChatStarted) + video_chat_ended: VideoChatEnded = fields.Field(base=VideoChatEnded) + video_chat_participants_invited: VideoChatParticipantsInvited = fields.Field(base=VideoChatParticipantsInvited) @property @functools.lru_cache() @@ -178,6 +188,16 @@ class Message(base.TelegramObject): return ContentType.VOICE_CHAT_ENDED if self.voice_chat_participants_invited: return ContentType.VOICE_CHAT_PARTICIPANTS_INVITED + if self.web_app_data: + return ContentType.WEB_APP_DATA + if self.video_chat_scheduled: + return ContentType.VIDEO_CHAT_SCHEDULED + if self.video_chat_started: + return ContentType.VIDEO_CHAT_STARTED + if self.video_chat_ended: + return ContentType.VIDEO_CHAT_ENDED + if self.video_chat_participants_invited: + return ContentType.VIDEO_CHAT_PARTICIPANTS_INVITED return ContentType.UNKNOWN @@ -309,22 +329,22 @@ class Message(base.TelegramObject): return md.link(text, url) async def answer( - self, - text: base.String, - parse_mode: typing.Optional[base.String] = None, - entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_web_page_preview: typing.Optional[base.Boolean] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + text: base.String, + parse_mode: typing.Optional[base.String] = None, + entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_web_page_preview: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Answer to this message @@ -379,22 +399,22 @@ class Message(base.TelegramObject): ) async def answer_photo( - self, - photo: typing.Union[base.InputFile, base.String], - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + photo: typing.Union[base.InputFile, base.String], + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send photos. @@ -451,26 +471,26 @@ class Message(base.TelegramObject): ) async def answer_audio( - self, - audio: typing.Union[base.InputFile, base.String], - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - duration: typing.Optional[base.Integer] = None, - performer: typing.Optional[base.String] = None, - title: typing.Optional[base.String] = None, - thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + audio: typing.Union[base.InputFile, base.String], + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + duration: typing.Optional[base.Integer] = None, + performer: typing.Optional[base.String] = None, + title: typing.Optional[base.String] = None, + thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send audio files, if you want Telegram clients to display them in the music player. @@ -547,26 +567,26 @@ class Message(base.TelegramObject): ) async def answer_animation( - self, - animation: typing.Union[base.InputFile, base.String], - duration: typing.Optional[base.Integer] = None, - width: typing.Optional[base.Integer] = None, - height: typing.Optional[base.Integer] = None, - thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + animation: typing.Union[base.InputFile, base.String], + duration: typing.Optional[base.Integer] = None, + width: typing.Optional[base.Integer] = None, + height: typing.Optional[base.Integer] = None, + thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). @@ -645,24 +665,24 @@ class Message(base.TelegramObject): ) async def answer_document( - self, - document: typing.Union[base.InputFile, base.String], - thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_content_type_detection: typing.Optional[base.Boolean] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + document: typing.Union[base.InputFile, base.String], + thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_content_type_detection: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send general files. On success, the sent Message is @@ -734,27 +754,27 @@ class Message(base.TelegramObject): ) async def answer_video( - self, - video: typing.Union[base.InputFile, base.String], - duration: typing.Optional[base.Integer] = None, - width: typing.Optional[base.Integer] = None, - height: typing.Optional[base.Integer] = None, - thumb: typing.Union[base.InputFile, base.String, None] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - supports_streaming: typing.Optional[base.Boolean] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + video: typing.Union[base.InputFile, base.String], + duration: typing.Optional[base.Integer] = None, + width: typing.Optional[base.Integer] = None, + height: typing.Optional[base.Integer] = None, + thumb: typing.Union[base.InputFile, base.String, None] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + supports_streaming: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send video files, Telegram clients support mp4 videos @@ -833,23 +853,23 @@ class Message(base.TelegramObject): ) async def answer_voice( - self, - voice: typing.Union[base.InputFile, base.String], - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - duration: typing.Optional[base.Integer] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + voice: typing.Union[base.InputFile, base.String], + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + duration: typing.Optional[base.Integer] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send audio files, if you want Telegram clients to display the file @@ -914,22 +934,22 @@ class Message(base.TelegramObject): ) async def answer_video_note( - self, - video_note: typing.Union[base.InputFile, base.String], - duration: typing.Optional[base.Integer] = None, - length: typing.Optional[base.Integer] = None, - thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + video_note: typing.Union[base.InputFile, base.String], + duration: typing.Optional[base.Integer] = None, + length: typing.Optional[base.Integer] = None, + thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. @@ -986,12 +1006,12 @@ class Message(base.TelegramObject): ) async def answer_media_group( - self, - media: typing.Union[MediaGroup, typing.List], - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply: base.Boolean = False, + self, + media: typing.Union[MediaGroup, typing.List], + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply: base.Boolean = False, ) -> typing.List[Message]: """ Use this method to send a group of photos, videos, documents or audios as @@ -1032,24 +1052,24 @@ class Message(base.TelegramObject): ) async def answer_location( - self, - latitude: base.Float, - longitude: base.Float, - live_period: typing.Optional[base.Integer] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - horizontal_accuracy: typing.Optional[base.Float] = None, - heading: typing.Optional[base.Integer] = None, - proximity_alert_radius: typing.Optional[base.Integer] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + latitude: base.Float, + longitude: base.Float, + live_period: typing.Optional[base.Integer] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + horizontal_accuracy: typing.Optional[base.Float] = None, + heading: typing.Optional[base.Integer] = None, + proximity_alert_radius: typing.Optional[base.Integer] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send point on the map. @@ -1116,26 +1136,26 @@ class Message(base.TelegramObject): ) async def answer_venue( - self, - latitude: base.Float, - longitude: base.Float, - title: base.String, - address: base.String, - foursquare_id: typing.Optional[base.String] = None, - foursquare_type: typing.Optional[base.String] = None, - google_place_id: typing.Optional[base.String] = None, - google_place_type: typing.Optional[base.String] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + latitude: base.Float, + longitude: base.Float, + title: base.String, + address: base.String, + foursquare_id: typing.Optional[base.String] = None, + foursquare_type: typing.Optional[base.String] = None, + google_place_id: typing.Optional[base.String] = None, + google_place_type: typing.Optional[base.String] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send information about a venue. @@ -1210,21 +1230,21 @@ class Message(base.TelegramObject): ) async def answer_contact( - self, - phone_number: base.String, - first_name: base.String, - last_name: typing.Optional[base.String] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + phone_number: base.String, + first_name: base.String, + last_name: typing.Optional[base.String] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send phone contacts. @@ -1275,19 +1295,19 @@ class Message(base.TelegramObject): ) async def answer_sticker( - self, - sticker: typing.Union[base.InputFile, base.String], - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + sticker: typing.Union[base.InputFile, base.String], + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send .webp stickers. @@ -1330,30 +1350,30 @@ class Message(base.TelegramObject): ) async def answer_poll( - self, - question: base.String, - options: typing.List[base.String], - is_anonymous: typing.Optional[base.Boolean] = None, - type: typing.Optional[base.String] = None, - allows_multiple_answers: typing.Optional[base.Boolean] = None, - correct_option_id: typing.Optional[base.Integer] = None, - explanation: typing.Optional[base.String] = None, - explanation_parse_mode: typing.Optional[base.String] = None, - explanation_entities: typing.Optional[typing.List[MessageEntity]] = None, - open_period: typing.Optional[base.Integer] = None, - close_date: typing.Union[base.Integer, datetime.datetime, datetime.timedelta, None] = None, - is_closed: typing.Optional[base.Boolean] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + question: base.String, + options: typing.List[base.String], + is_anonymous: typing.Optional[base.Boolean] = None, + type: typing.Optional[base.String] = None, + allows_multiple_answers: typing.Optional[base.Boolean] = None, + correct_option_id: typing.Optional[base.Integer] = None, + explanation: typing.Optional[base.String] = None, + explanation_parse_mode: typing.Optional[base.String] = None, + explanation_entities: typing.Optional[typing.List[MessageEntity]] = None, + open_period: typing.Optional[base.Integer] = None, + close_date: typing.Union[base.Integer, datetime.datetime, datetime.timedelta, None] = None, + is_closed: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send a native poll. On success, the sent Message is @@ -1454,19 +1474,19 @@ class Message(base.TelegramObject): ) async def answer_dice( - self, - emoji: typing.Optional[base.String] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = False, + self, + emoji: typing.Optional[base.String] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = False, ) -> Message: """ Use this method to send an animated emoji that will display a random value. @@ -1516,8 +1536,8 @@ class Message(base.TelegramObject): ) async def answer_chat_action( - self, - action: base.String, + self, + action: base.String, ) -> base.Boolean: """ Use this method when you need to tell the user that something is happening on the bot's side. @@ -1540,22 +1560,22 @@ class Message(base.TelegramObject): ) async def reply( - self, - text: base.String, - parse_mode: typing.Optional[base.String] = None, - entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_web_page_preview: typing.Optional[base.Boolean] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + text: base.String, + parse_mode: typing.Optional[base.String] = None, + entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_web_page_preview: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Reply to this message @@ -1610,22 +1630,22 @@ class Message(base.TelegramObject): ) async def reply_photo( - self, - photo: typing.Union[base.InputFile, base.String], - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + photo: typing.Union[base.InputFile, base.String], + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send photos. @@ -1682,26 +1702,26 @@ class Message(base.TelegramObject): ) async def reply_audio( - self, - audio: typing.Union[base.InputFile, base.String], - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - duration: typing.Optional[base.Integer] = None, - performer: typing.Optional[base.String] = None, - title: typing.Optional[base.String] = None, - thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + audio: typing.Union[base.InputFile, base.String], + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + duration: typing.Optional[base.Integer] = None, + performer: typing.Optional[base.String] = None, + title: typing.Optional[base.String] = None, + thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send audio files, if you want Telegram clients to display them in the music player. @@ -1778,26 +1798,26 @@ class Message(base.TelegramObject): ) async def reply_animation( - self, - animation: typing.Union[base.InputFile, base.String], - duration: typing.Optional[base.Integer] = None, - width: typing.Optional[base.Integer] = None, - height: typing.Optional[base.Integer] = None, - thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + animation: typing.Union[base.InputFile, base.String], + duration: typing.Optional[base.Integer] = None, + width: typing.Optional[base.Integer] = None, + height: typing.Optional[base.Integer] = None, + thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). @@ -1876,24 +1896,24 @@ class Message(base.TelegramObject): ) async def reply_document( - self, - document: typing.Union[base.InputFile, base.String], - thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_content_type_detection: typing.Optional[base.Boolean] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + document: typing.Union[base.InputFile, base.String], + thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_content_type_detection: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send general files. On success, the sent Message is @@ -1965,27 +1985,27 @@ class Message(base.TelegramObject): ) async def reply_video( - self, - video: typing.Union[base.InputFile, base.String], - duration: typing.Optional[base.Integer] = None, - width: typing.Optional[base.Integer] = None, - height: typing.Optional[base.Integer] = None, - thumb: typing.Union[base.InputFile, base.String, None] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - supports_streaming: typing.Optional[base.Boolean] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + video: typing.Union[base.InputFile, base.String], + duration: typing.Optional[base.Integer] = None, + width: typing.Optional[base.Integer] = None, + height: typing.Optional[base.Integer] = None, + thumb: typing.Union[base.InputFile, base.String, None] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + supports_streaming: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send video files, Telegram clients support mp4 videos @@ -2064,23 +2084,23 @@ class Message(base.TelegramObject): ) async def reply_voice( - self, - voice: typing.Union[base.InputFile, base.String], - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - duration: typing.Optional[base.Integer] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + voice: typing.Union[base.InputFile, base.String], + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + duration: typing.Optional[base.Integer] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send audio files, if you want Telegram clients to display the file @@ -2145,22 +2165,22 @@ class Message(base.TelegramObject): ) async def reply_video_note( - self, - video_note: typing.Union[base.InputFile, base.String], - duration: typing.Optional[base.Integer] = None, - length: typing.Optional[base.Integer] = None, - thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + video_note: typing.Union[base.InputFile, base.String], + duration: typing.Optional[base.Integer] = None, + length: typing.Optional[base.Integer] = None, + thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. @@ -2217,12 +2237,12 @@ class Message(base.TelegramObject): ) async def reply_media_group( - self, - media: typing.Union[MediaGroup, typing.List], - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply: base.Boolean = True, + self, + media: typing.Union[MediaGroup, typing.List], + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply: base.Boolean = True, ) -> typing.List[Message]: """ Use this method to send a group of photos, videos, documents or audios as @@ -2263,23 +2283,23 @@ class Message(base.TelegramObject): ) async def reply_location( - self, - latitude: base.Float, - longitude: base.Float, - live_period: typing.Optional[base.Integer] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - horizontal_accuracy: typing.Optional[base.Float] = None, - heading: typing.Optional[base.Integer] = None, - proximity_alert_radius: typing.Optional[base.Integer] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + latitude: base.Float, + longitude: base.Float, + live_period: typing.Optional[base.Integer] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + horizontal_accuracy: typing.Optional[base.Float] = None, + heading: typing.Optional[base.Integer] = None, + proximity_alert_radius: typing.Optional[base.Integer] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send point on the map. @@ -2341,26 +2361,26 @@ class Message(base.TelegramObject): ) async def reply_venue( - self, - latitude: base.Float, - longitude: base.Float, - title: base.String, - address: base.String, - foursquare_id: typing.Optional[base.String] = None, - foursquare_type: typing.Optional[base.String] = None, - google_place_id: typing.Optional[base.String] = None, - google_place_type: typing.Optional[base.String] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + latitude: base.Float, + longitude: base.Float, + title: base.String, + address: base.String, + foursquare_id: typing.Optional[base.String] = None, + foursquare_type: typing.Optional[base.String] = None, + google_place_id: typing.Optional[base.String] = None, + google_place_type: typing.Optional[base.String] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send information about a venue. @@ -2435,21 +2455,21 @@ class Message(base.TelegramObject): ) async def reply_contact( - self, - phone_number: base.String, - first_name: base.String, - last_name: typing.Optional[base.String] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + phone_number: base.String, + first_name: base.String, + last_name: typing.Optional[base.String] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send phone contacts. @@ -2500,30 +2520,30 @@ class Message(base.TelegramObject): ) async def reply_poll( - self, - question: base.String, - options: typing.List[base.String], - is_anonymous: typing.Optional[base.Boolean] = None, - type: typing.Optional[base.String] = None, - allows_multiple_answers: typing.Optional[base.Boolean] = None, - correct_option_id: typing.Optional[base.Integer] = None, - explanation: typing.Optional[base.String] = None, - explanation_parse_mode: typing.Optional[base.String] = None, - explanation_entities: typing.Optional[typing.List[MessageEntity]] = None, - open_period: typing.Optional[base.Integer] = None, - close_date: typing.Union[base.Integer, datetime.datetime, datetime.timedelta, None] = None, - is_closed: typing.Optional[base.Boolean] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + question: base.String, + options: typing.List[base.String], + is_anonymous: typing.Optional[base.Boolean] = None, + type: typing.Optional[base.String] = None, + allows_multiple_answers: typing.Optional[base.Boolean] = None, + correct_option_id: typing.Optional[base.Integer] = None, + explanation: typing.Optional[base.String] = None, + explanation_parse_mode: typing.Optional[base.String] = None, + explanation_entities: typing.Optional[typing.List[MessageEntity]] = None, + open_period: typing.Optional[base.Integer] = None, + close_date: typing.Union[base.Integer, datetime.datetime, datetime.timedelta, None] = None, + is_closed: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send a native poll. On success, the sent Message is @@ -2624,19 +2644,19 @@ class Message(base.TelegramObject): ) async def reply_sticker( - self, - sticker: typing.Union[base.InputFile, base.String], - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + sticker: typing.Union[base.InputFile, base.String], + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send .webp stickers. @@ -2679,19 +2699,19 @@ class Message(base.TelegramObject): ) async def reply_dice( - self, - emoji: typing.Optional[base.String] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, - None, - ] = None, - reply: base.Boolean = True, + self, + emoji: typing.Optional[base.String] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, + None, + ] = None, + reply: base.Boolean = True, ) -> Message: """ Use this method to send an animated emoji that will display a random value. @@ -2741,10 +2761,10 @@ class Message(base.TelegramObject): ) async def forward( - self, - chat_id: typing.Union[base.Integer, base.String], - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, + self, + chat_id: typing.Union[base.Integer, base.String], + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, ) -> Message: """ Forward this message @@ -2773,12 +2793,12 @@ class Message(base.TelegramObject): ) async def edit_text( - self, - text: base.String, - parse_mode: typing.Optional[base.String] = None, - entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_web_page_preview: typing.Optional[base.Boolean] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + self, + text: base.String, + parse_mode: typing.Optional[base.String] = None, + entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_web_page_preview: typing.Optional[base.Boolean] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, ) -> typing.Union[Message, base.Boolean]: """ Use this method to edit text and game messages sent by the bot or via the bot (for inline bots). @@ -2817,11 +2837,11 @@ class Message(base.TelegramObject): ) async def edit_caption( - self, - caption: base.String, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + self, + caption: base.String, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, ) -> typing.Union[Message, base.Boolean]: """ Use this method to edit captions of messages sent by the bot or via the bot @@ -2857,9 +2877,9 @@ class Message(base.TelegramObject): ) async def edit_media( - self, - media: InputMedia, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + self, + media: InputMedia, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, ) -> typing.Union[Message, base.Boolean]: """ Use this method to edit audio, document, photo, or video messages. @@ -2889,7 +2909,7 @@ class Message(base.TelegramObject): ) async def edit_reply_markup( - self, reply_markup: typing.Optional[InlineKeyboardMarkup] = None + self, reply_markup: typing.Optional[InlineKeyboardMarkup] = None ) -> typing.Union[Message, base.Boolean]: """ Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots). @@ -2919,10 +2939,10 @@ class Message(base.TelegramObject): ) async def edit_live_location( - self, - latitude: base.Float, - longitude: base.Float, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + self, + latitude: base.Float, + longitude: base.Float, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, ) -> typing.Union[Message, base.Boolean]: """ Use this method to edit live location messages sent by the bot or via the bot (for inline bots). @@ -2950,7 +2970,7 @@ class Message(base.TelegramObject): ) async def stop_live_location( - self, reply_markup: typing.Optional[InlineKeyboardMarkup] = None + self, reply_markup: typing.Optional[InlineKeyboardMarkup] = None ) -> typing.Union[Message, base.Boolean]: """ Use this method to stop updating a live location message sent by the bot or via the bot @@ -2986,8 +3006,8 @@ class Message(base.TelegramObject): return await self.bot.delete_message(self.chat.id, self.message_id) async def pin( - self, - disable_notification: typing.Optional[base.Boolean] = None, + self, + disable_notification: typing.Optional[base.Boolean] = None, ) -> base.Boolean: """ Use this method to add a message to the list of pinned messages in a chat. @@ -3028,16 +3048,16 @@ class Message(base.TelegramObject): ) async def send_copy( - self: Message, - chat_id: typing.Union[str, int], - disable_notification: typing.Optional[bool] = None, - protect_content: typing.Optional[base.Boolean] = None, - disable_web_page_preview: typing.Optional[bool] = None, - reply_to_message_id: typing.Optional[int] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[ - InlineKeyboardMarkup, ReplyKeyboardMarkup, None - ] = None, + self: Message, + chat_id: typing.Union[str, int], + disable_notification: typing.Optional[bool] = None, + protect_content: typing.Optional[base.Boolean] = None, + disable_web_page_preview: typing.Optional[bool] = None, + reply_to_message_id: typing.Optional[int] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[ + InlineKeyboardMarkup, ReplyKeyboardMarkup, None + ] = None, ) -> Message: """ Send copy of current message @@ -3148,19 +3168,19 @@ class Message(base.TelegramObject): raise TypeError("This type of message can't be copied.") async def copy_to( - self, - chat_id: typing.Union[base.Integer, base.String], - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - caption_entities: typing.Optional[typing.List[MessageEntity]] = None, - disable_notification: typing.Optional[base.Boolean] = None, - protect_content: typing.Optional[base.Boolean] = None, - reply_to_message_id: typing.Optional[base.Integer] = None, - allow_sending_without_reply: typing.Optional[base.Boolean] = None, - reply_markup: typing.Union[InlineKeyboardMarkup, - ReplyKeyboardMarkup, - ReplyKeyboardRemove, - ForceReply, None] = None, + self, + chat_id: typing.Union[base.Integer, base.String], + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_notification: typing.Optional[base.Boolean] = None, + protect_content: typing.Optional[base.Boolean] = None, + reply_to_message_id: typing.Optional[base.Integer] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[InlineKeyboardMarkup, + ReplyKeyboardMarkup, + ReplyKeyboardRemove, + ForceReply, None] = None, ) -> MessageId: return await self.bot.copy_message( chat_id=chat_id, @@ -3247,6 +3267,11 @@ class ContentType(helper.Helper): VOICE_CHAT_STARTED = helper.Item() # voice_chat_started VOICE_CHAT_ENDED = helper.Item() # voice_chat_ended VOICE_CHAT_PARTICIPANTS_INVITED = helper.Item() # voice_chat_participants_invited + WEB_APP_DATA = helper.Item() # web_app_data + VIDEO_CHAT_SCHEDULED = helper.Item() # video_chat_scheduled + VIDEO_CHAT_STARTED = helper.Item() # video_chat_started + VIDEO_CHAT_ENDED = helper.Item() # video_chat_ended + VIDEO_CHAT_PARTICIPANTS_INVITED = helper.Item() # video_chat_participants_invited UNKNOWN = helper.Item() # unknown ANY = helper.Item() # any @@ -3313,6 +3338,11 @@ class ContentTypes(helper.Helper): DELETE_CHAT_PHOTO = helper.ListItem() # delete_chat_photo GROUP_CHAT_CREATED = helper.ListItem() # group_chat_created PASSPORT_DATA = helper.ListItem() # passport_data + WEB_APP_DATA = helper.Item() # web_app_data + VIDEO_CHAT_SCHEDULED = helper.Item() # video_chat_scheduled + VIDEO_CHAT_STARTED = helper.Item() # video_chat_started + VIDEO_CHAT_ENDED = helper.Item() # video_chat_ended + VIDEO_CHAT_PARTICIPANTS_INVITED = helper.Item() # video_chat_participants_invited UNKNOWN = helper.ListItem() # unknown ANY = helper.ListItem() # any diff --git a/aiogram/types/reply_keyboard.py b/aiogram/types/reply_keyboard.py index 17b0a353..1a8609be 100644 --- a/aiogram/types/reply_keyboard.py +++ b/aiogram/types/reply_keyboard.py @@ -2,6 +2,7 @@ import typing from . import base from . import fields +from .web_app_info import WebAppInfo class KeyboardButtonPollType(base.TelegramObject): @@ -117,16 +118,19 @@ class KeyboardButton(base.TelegramObject): request_contact: base.Boolean = fields.Field() request_location: base.Boolean = fields.Field() request_poll: KeyboardButtonPollType = fields.Field() + web_app: WebAppInfo = fields.Field(base=WebAppInfo) def __init__(self, text: base.String, request_contact: base.Boolean = None, request_location: base.Boolean = None, request_poll: KeyboardButtonPollType = None, + web_app: WebAppInfo = None, **kwargs): super(KeyboardButton, self).__init__(text=text, request_contact=request_contact, request_location=request_location, request_poll=request_poll, + web_app=web_app, **kwargs) diff --git a/aiogram/types/sent_web_app_message.py b/aiogram/types/sent_web_app_message.py new file mode 100644 index 00000000..d48343e8 --- /dev/null +++ b/aiogram/types/sent_web_app_message.py @@ -0,0 +1,11 @@ +from . import base +from . import fields + + +class SentWebAppMessage(base.TelegramObject): + """ + Contains information about an inline message sent by a Web App on behalf of a user. + + Source: https://core.telegram.org/bots/api#sentwebappmessage + """ + inline_message_id: base.String = fields.Field() diff --git a/aiogram/types/video_chat_ended.py b/aiogram/types/video_chat_ended.py new file mode 100644 index 00000000..b73bf0d3 --- /dev/null +++ b/aiogram/types/video_chat_ended.py @@ -0,0 +1,13 @@ +from . import base +from . import fields +from . import mixins + + +class VideoChatEnded(base.TelegramObject, mixins.Downloadable): + """ + This object represents a service message about a video chat scheduled in the chat. + + https://core.telegram.org/bots/api#videochatended + """ + + duration: base.Integer = fields.Field() diff --git a/aiogram/types/video_chat_participants_invited.py b/aiogram/types/video_chat_participants_invited.py new file mode 100644 index 00000000..e7c33cb9 --- /dev/null +++ b/aiogram/types/video_chat_participants_invited.py @@ -0,0 +1,16 @@ +import typing + +from . import base +from . import fields +from . import mixins +from .user import User + + +class VideoChatParticipantsInvited(base.TelegramObject, mixins.Downloadable): + """ + This object represents a service message about new members invited to a video chat. + + https://core.telegram.org/bots/api#videochatparticipantsinvited + """ + + users: typing.List[User] = fields.ListField(base=User) diff --git a/aiogram/types/video_chat_scheduled.py b/aiogram/types/video_chat_scheduled.py new file mode 100644 index 00000000..375995e2 --- /dev/null +++ b/aiogram/types/video_chat_scheduled.py @@ -0,0 +1,14 @@ +from datetime import datetime + +from . import base +from . import fields + + +class VideoChatScheduled(base.TelegramObject): + """ + This object represents a service message about a video chat scheduled in the chat. + + https://core.telegram.org/bots/api#videochatscheduled + """ + + start_date: datetime = fields.DateTimeField() diff --git a/aiogram/types/video_chat_started.py b/aiogram/types/video_chat_started.py new file mode 100644 index 00000000..ec1aefd1 --- /dev/null +++ b/aiogram/types/video_chat_started.py @@ -0,0 +1,11 @@ +from . import base +from . import mixins + + +class VideoChatStarted(base.TelegramObject, mixins.Downloadable): + """ + his object represents a service message about a video chat started in the chat. Currently holds no information. + + https://core.telegram.org/bots/api#videochatstarted + """ + pass diff --git a/aiogram/types/web_app_data.py b/aiogram/types/web_app_data.py new file mode 100644 index 00000000..9c68d45e --- /dev/null +++ b/aiogram/types/web_app_data.py @@ -0,0 +1,12 @@ +from . import base +from . import fields + + +class WebAppData(base.TelegramObject): + """ + Contains data sent from a Web App to the bot. + + Source: https://core.telegram.org/bots/api#webappdata + """ + data: str = fields.Field() + button_text: str = fields.Field() diff --git a/aiogram/types/web_app_info.py b/aiogram/types/web_app_info.py new file mode 100644 index 00000000..31ac58b4 --- /dev/null +++ b/aiogram/types/web_app_info.py @@ -0,0 +1,11 @@ +from . import base +from . import fields + + +class WebAppInfo(base.TelegramObject): + """ + Contains information about a Web App. + + Source: https://core.telegram.org/bots/api#webappinfo + """ + url: base.String = fields.Field() diff --git a/aiogram/types/webhook_info.py b/aiogram/types/webhook_info.py index dc1a7cd9..8970c97a 100644 --- a/aiogram/types/webhook_info.py +++ b/aiogram/types/webhook_info.py @@ -18,3 +18,4 @@ class WebhookInfo(base.TelegramObject): last_error_message: base.String = fields.Field() max_connections: base.Integer = fields.Field() allowed_updates: typing.List[base.String] = fields.ListField() + last_synchronization_error_date: base.Integer = fields.DateTimeField() diff --git a/docs/source/index.rst b/docs/source/index.rst index 03292fd9..82505aba 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -22,7 +22,7 @@ Welcome to aiogram's documentation! :target: https://pypi.python.org/pypi/aiogram :alt: Supported python versions - .. image:: https://img.shields.io/badge/Telegram%20Bot%20API-5.7-blue.svg?style=flat-square&logo=telegram + .. image:: https://img.shields.io/badge/Telegram%20Bot%20API-6.0-blue.svg?style=flat-square&logo=telegram :target: https://core.telegram.org/bots/api :alt: Telegram Bot API diff --git a/test.html b/test.html new file mode 100644 index 00000000..61f09a01 --- /dev/null +++ b/test.html @@ -0,0 +1,22 @@ + + + + + + + + + + Hello, world! + + +

Hello, world!

+
not inited
+ + + + + \ No newline at end of file