diff --git a/readthedocs/misc/v2-migration-guide.rst b/readthedocs/misc/v2-migration-guide.rst index 27a4a783..e3f9be6a 100644 --- a/readthedocs/misc/v2-migration-guide.rst +++ b/readthedocs/misc/v2-migration-guide.rst @@ -386,14 +386,17 @@ Note that you do not need to ``await`` the call to ``.start()`` if you are going in a context-manager (but it's okay if you put the ``await``). -download_file has been removed from the client ----------------------------------------------- - -Instead, ``client.download_media`` should be used. +Several methods have been removed from the client +------------------------------------------------- +``client.download_file`` has been removed. Instead, ``client.download_media`` should be used. The now-removed ``client.download_file`` method was a lower level implementation which should have not been exposed at all. +``client.build_reply_markup`` has been removed. Manually calling this method was purely an +optimization (the buttons won't need to be transformed into a reply markup every time they're +used). This means you can just remove any calls to this method and things will continue to work. + Support for bot-API style file_id has been removed -------------------------------------------------- diff --git a/telethon/_client/buttons.py b/telethon/_client/buttons.py deleted file mode 100644 index 599ebc96..00000000 --- a/telethon/_client/buttons.py +++ /dev/null @@ -1,66 +0,0 @@ -import typing - -from .._misc import utils, hints -from .. import _tl -from ..types import _custom - - -def build_reply_markup( - buttons: 'typing.Optional[hints.MarkupLike]', - inline_only: bool = False) -> 'typing.Optional[_tl.TypeReplyMarkup]': - if not buttons: - return None - - try: - if buttons.SUBCLASS_OF_ID == 0xe2e10ef2: - return buttons # crc32(b'ReplyMarkup'): - except AttributeError: - pass - - if not utils.is_list_like(buttons): - buttons = [buttons] - if not utils.is_list_like(buttons[0]): - buttons = [[b] for b in buttons] - - is_inline = False - is_normal = False - resize = None - single_use = None - selective = None - - rows = [] - for row in buttons: - current = [] - for button in row: - if isinstance(button, _custom.Button): - if button.resize is not None: - resize = button.resize - if button.single_use is not None: - single_use = button.single_use - if button.selective is not None: - selective = button.selective - - button = button.button - elif isinstance(button, _custom.MessageButton): - button = button.button - - inline = _custom.Button._is_inline(button) - is_inline |= inline - is_normal |= not inline - - if button.SUBCLASS_OF_ID == 0xbad74a3: - # 0xbad74a3 == crc32(b'KeyboardButton') - current.append(button) - - if current: - rows.append(_tl.KeyboardButtonRow(current)) - - if inline_only and is_normal: - raise ValueError('You cannot use non-inline buttons here') - elif is_inline == is_normal and is_normal: - raise ValueError('You cannot mix inline with normal buttons') - elif is_inline: - return _tl.ReplyInlineMarkup(rows) - # elif is_normal: - return _tl.ReplyKeyboardMarkup( - rows, resize=resize, single_use=single_use, selective=selective) diff --git a/telethon/_client/messages.py b/telethon/_client/messages.py index 5b7ca110..66d3512e 100644 --- a/telethon/_client/messages.py +++ b/telethon/_client/messages.py @@ -430,7 +430,7 @@ async def send_message( if buttons is None: markup = message.reply_markup else: - markup = self.build_reply_markup(buttons) + markup = _custom.button.build_reply_markup(buttons) if silent is None: silent = message.silent @@ -480,7 +480,7 @@ async def send_message( clear_draft=clear_draft, silent=silent, background=background, - reply_markup=self.build_reply_markup(buttons), + reply_markup=_custom.button.build_reply_markup(buttons), schedule_date=schedule ) @@ -593,7 +593,7 @@ async def edit_message( no_webpage=not link_preview, entities=formatting_entities, media=media, - reply_markup=self.build_reply_markup(buttons) + reply_markup=_custom.button.build_reply_markup(buttons) ) # Invoke `messages.editInlineBotMessage` from the right datacenter. # Otherwise, Telegram will error with `MESSAGE_ID_INVALID` and do nothing. @@ -615,7 +615,7 @@ async def edit_message( no_webpage=not link_preview, entities=formatting_entities, media=media, - reply_markup=self.build_reply_markup(buttons), + reply_markup=_custom.button.build_reply_markup(buttons), schedule_date=schedule ) msg = self._get_response_message(request, await self(request), entity) diff --git a/telethon/_client/telegramclient.py b/telethon/_client/telegramclient.py index 5812296c..1e23440a 100644 --- a/telethon/_client/telegramclient.py +++ b/telethon/_client/telegramclient.py @@ -5,7 +5,7 @@ import typing import logging from . import ( - account, auth, bots, buttons, chats, dialogs, downloads, messageparse, messages, + account, auth, bots, chats, dialogs, downloads, messageparse, messages, telegrambaseclient, updates, uploads, users ) from .. import helpers, version, _tl @@ -684,46 +684,6 @@ class TelegramClient: # endregion Bots - # region Buttons - - @staticmethod - def build_reply_markup( - buttons: 'typing.Optional[hints.MarkupLike]', - inline_only: bool = False) -> 'typing.Optional[_tl.TypeReplyMarkup]': - """ - Builds a :tl:`ReplyInlineMarkup` or :tl:`ReplyKeyboardMarkup` for - the given buttons. - - Does nothing if either no buttons are provided or the provided - argument is already a reply markup. - - You should consider using this method if you are going to reuse - the markup very often. Otherwise, it is not necessary. - - This method is **not** asynchronous (don't use ``await`` on it). - - Arguments - buttons (`hints.MarkupLike`): - The button, list of buttons, array of buttons or markup - to convert into a markup. - - inline_only (`bool`, optional): - Whether the buttons **must** be inline buttons only or not. - - Example - .. code-block:: python - - from telethon import Button - - markup = client.build_reply_markup(Button.inline('hi')) - # later - await client.send_message(chat, 'click me', buttons=markup) - """ - from . import buttons as b - return b.build_reply_markup(buttons=buttons, inline_only=inline_only) - - # endregion Buttons - # region Chats @forward_call(chats.get_participants) diff --git a/telethon/_client/uploads.py b/telethon/_client/uploads.py index 912954b0..a141d199 100644 --- a/telethon/_client/uploads.py +++ b/telethon/_client/uploads.py @@ -182,7 +182,7 @@ async def send_file( if not media: raise TypeError('Cannot use {!r} as file'.format(file)) - markup = self.build_reply_markup(buttons) + markup = _custom.button.build_reply_markup(buttons) request = _tl.fn.messages.SendMedia( entity, media, reply_to_msg_id=reply_to, message=caption, entities=msg_entities, reply_markup=markup, silent=silent, diff --git a/telethon/types/_custom/button.py b/telethon/types/_custom/button.py index 4dbcab99..ffac7c99 100644 --- a/telethon/types/_custom/button.py +++ b/telethon/types/_custom/button.py @@ -1,3 +1,4 @@ +from .messagebutton import MessageButton from ... import _tl from ..._misc import utils @@ -306,3 +307,84 @@ class Button: documentation for more information on using games. """ return _tl.KeyboardButtonGame(text) + + +def build_reply_markup( + buttons: 'typing.Optional[hints.MarkupLike]', + inline_only: bool = False) -> 'typing.Optional[_tl.TypeReplyMarkup]': + """ + Builds a :tl:`ReplyInlineMarkup` or :tl:`ReplyKeyboardMarkup` for + the given buttons. + + Does nothing if either no buttons are provided or the provided + argument is already a reply markup. + + You should consider using this method if you are going to reuse + the markup very often. Otherwise, it is not necessary. + + This method is **not** asynchronous (don't use ``await`` on it). + + Arguments + buttons (`hints.MarkupLike`): + The button, list of buttons, array of buttons or markup + to convert into a markup. + + inline_only (`bool`, optional): + Whether the buttons **must** be inline buttons only or not. + """ + if not buttons: + return None + + try: + if buttons.SUBCLASS_OF_ID == 0xe2e10ef2: + return buttons # crc32(b'ReplyMarkup'): + except AttributeError: + pass + + if not utils.is_list_like(buttons): + buttons = [buttons] + if not utils.is_list_like(buttons[0]): + buttons = [[b] for b in buttons] + + is_inline = False + is_normal = False + resize = None + single_use = None + selective = None + + rows = [] + for row in buttons: + current = [] + for button in row: + if isinstance(button, Button): + if button.resize is not None: + resize = button.resize + if button.single_use is not None: + single_use = button.single_use + if button.selective is not None: + selective = button.selective + + button = button.button + elif isinstance(button, MessageButton): + button = button.button + + inline = Button._is_inline(button) + is_inline |= inline + is_normal |= not inline + + if button.SUBCLASS_OF_ID == 0xbad74a3: + # 0xbad74a3 == crc32(b'KeyboardButton') + current.append(button) + + if current: + rows.append(_tl.KeyboardButtonRow(current)) + + if inline_only and is_normal: + raise ValueError('You cannot use non-inline buttons here') + elif is_inline == is_normal and is_normal: + raise ValueError('You cannot mix inline with normal buttons') + elif is_inline: + return _tl.ReplyInlineMarkup(rows) + # elif is_normal: + return _tl.ReplyKeyboardMarkup( + rows, resize=resize, single_use=single_use, selective=selective) diff --git a/telethon/types/_custom/inlinebuilder.py b/telethon/types/_custom/inlinebuilder.py index b401ab04..3fea2fc2 100644 --- a/telethon/types/_custom/inlinebuilder.py +++ b/telethon/types/_custom/inlinebuilder.py @@ -2,6 +2,7 @@ import hashlib from ... import _tl from ..._misc import utils +from ...types import _custom _TYPE_TO_MIMES = { 'gif': ['image/gif'], # 'video/mp4' too, but that's used for video @@ -391,7 +392,7 @@ class InlineBuilder: 'text geo contact game'.split(), args) if x[1]) or 'none') ) - markup = self._client.build_reply_markup(buttons, inline_only=True) + markup = _custom.button.build_reply_markup(buttons, inline_only=True) if text is not None: text, msg_entities = await self._client._parse_message_text( text, parse_mode