diff --git a/client/src/telethon/_impl/client/client/client.py b/client/src/telethon/_impl/client/client/client.py index 7896bff2..bacf8782 100644 --- a/client/src/telethon/_impl/client/client/client.py +++ b/client/src/telethon/_impl/client/client/client.py @@ -23,7 +23,7 @@ from ...session import ( ) from ...tl import Request, abcs from ..events import Event -from ..events.filters import Filter +from ..events.filters import FilterType from ..types import ( AdminRight, AlbumBuilder, @@ -36,6 +36,7 @@ from ..types import ( Group, InFileLike, InlineResult, + KeyboardType, LoginToken, Message, OutFileLike, @@ -45,7 +46,6 @@ from ..types import ( RecentAction, User, ) -from ..types import buttons as btns from .auth import ( bot_sign_in, check_password, @@ -216,6 +216,7 @@ class Client: datacenter: Optional[DataCenter] = None, connector: Optional[Connector] = None, ) -> None: + assert isinstance(__package__, str) base_logger = logger or logging.getLogger(__package__[: __package__.index(".")]) self._sender: Optional[Sender] = None @@ -251,12 +252,13 @@ class Client: self._message_box = MessageBox(base_logger=base_logger) self._chat_hashes = ChatHashCache(None) self._last_update_limit_warn: Optional[float] = None - self._updates: asyncio.Queue[ - tuple[abcs.Update, dict[int, Peer]] - ] = asyncio.Queue(maxsize=self._config.update_queue_limit or 0) + self._updates: asyncio.Queue[tuple[abcs.Update, dict[int, Peer]]] = ( + asyncio.Queue(maxsize=self._config.update_queue_limit or 0) + ) self._dispatcher: Optional[asyncio.Task[None]] = None self._handlers: dict[ - Type[Event], list[tuple[Callable[[Any], Awaitable[Any]], Optional[Filter]]] + Type[Event], + list[tuple[Callable[[Any], Awaitable[Any]], Optional[FilterType]]], ] = {} self._check_all_handlers = check_all_handlers @@ -270,7 +272,7 @@ class Client: handler: Callable[[AnyEvent], Awaitable[Any]], /, event_cls: Type[AnyEvent], - filter: Optional[Filter] = None, + filter: Optional[FilterType] = None, ) -> None: """ Register a callable to be invoked when the provided event type occurs. @@ -571,7 +573,7 @@ class Client: markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: """ Edit a message. @@ -586,10 +588,10 @@ class Client: :param markdown: See :ref:`formatting`. :param html: See :ref:`formatting`. :param link_preview: See :ref:`formatting`. - :param buttons: - The buttons to use for the message. + :param keyboard: + The keyboard to use for the message. - Only bot accounts can send buttons. + Only bot accounts can send keyboard. :return: The edited message. @@ -615,7 +617,7 @@ class Client: markdown=markdown, html=html, link_preview=link_preview, - buttons=buttons, + keyboard=keyboard, ) async def forward_messages( @@ -759,7 +761,7 @@ class Client: def get_handler_filter( self, handler: Callable[[AnyEvent], Awaitable[Any]], / - ) -> Optional[Filter]: + ) -> Optional[FilterType]: """ Get the filter associated to the given event handler. @@ -1034,7 +1036,7 @@ class Client: return await is_authorized(self) def on( - self, event_cls: Type[AnyEvent], /, filter: Optional[Filter] = None + self, event_cls: Type[AnyEvent], /, filter: Optional[FilterType] = None ) -> Callable[ [Callable[[AnyEvent], Awaitable[Any]]], Callable[[AnyEvent], Awaitable[Any]] ]: @@ -1393,7 +1395,7 @@ class Client: caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: """ Send an audio file. @@ -1437,7 +1439,7 @@ class Client: caption_markdown=caption_markdown, caption_html=caption_html, reply_to=reply_to, - buttons=buttons, + keyboard=keyboard, ) async def send_file( @@ -1466,7 +1468,7 @@ class Client: caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]], + keyboard: Optional[KeyboardType], ) -> Message: """ Send any type of file with any amount of attributes. @@ -1620,7 +1622,7 @@ class Client: caption_markdown=caption_markdown, caption_html=caption_html, reply_to=reply_to, - buttons=buttons, + keyboard=keyboard, ) async def send_message( @@ -1633,7 +1635,7 @@ class Client: html: Optional[str] = None, link_preview: bool = False, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: """ Send a message. @@ -1649,10 +1651,10 @@ class Client: :param reply_to: The message identifier of the message to reply to. - :param buttons: - The buttons to use for the message. + :param keyboard: + The keyboard to use for the message. - Only bot accounts can send buttons. + Only bot accounts can send keyboard. .. rubric:: Example @@ -1668,7 +1670,7 @@ class Client: html=html, link_preview=link_preview, reply_to=reply_to, - buttons=buttons, + keyboard=keyboard, ) async def send_photo( @@ -1687,7 +1689,7 @@ class Client: caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: """ Send a photo file. @@ -1733,7 +1735,7 @@ class Client: caption_markdown=caption_markdown, caption_html=caption_html, reply_to=reply_to, - buttons=buttons, + keyboard=keyboard, ) async def send_video( @@ -1755,7 +1757,7 @@ class Client: caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]], + keyboard: Optional[KeyboardType], ) -> Message: """ Send a video file. @@ -1802,7 +1804,7 @@ class Client: caption_markdown=caption_markdown, caption_html=caption_html, reply_to=reply_to, - buttons=buttons, + keyboard=keyboard, ) async def set_chat_default_restrictions( @@ -1851,7 +1853,7 @@ class Client: self, handler: Callable[[AnyEvent], Awaitable[Any]], /, - filter: Optional[Filter] = None, + filter: Optional[FilterType] = None, ) -> None: """ Set the filter to use for the given event handler. diff --git a/client/src/telethon/_impl/client/client/files.py b/client/src/telethon/_impl/client/client/files.py index f7a91645..8edb034e 100644 --- a/client/src/telethon/_impl/client/client/files.py +++ b/client/src/telethon/_impl/client/client/files.py @@ -13,13 +13,11 @@ from ..types import ( AsyncList, File, InFileLike, + KeyboardType, Message, OutFileLike, OutWrapper, Peer, -) -from ..types import buttons as btns -from ..types import ( expand_stripped_size, generate_random_id, parse_message, @@ -59,7 +57,7 @@ async def send_photo( caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: return await send_file( self, @@ -79,7 +77,7 @@ async def send_photo( caption_markdown=caption_markdown, caption_html=caption_html, reply_to=reply_to, - buttons=buttons, + keyboard=keyboard, ) @@ -100,7 +98,7 @@ async def send_audio( caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: return await send_file( self, @@ -117,7 +115,7 @@ async def send_audio( caption_markdown=caption_markdown, caption_html=caption_html, reply_to=reply_to, - buttons=buttons, + keyboard=keyboard, ) @@ -140,7 +138,7 @@ async def send_video( caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]], + keyboard: Optional[KeyboardType], ) -> Message: return await send_file( self, @@ -159,7 +157,7 @@ async def send_video( caption_markdown=caption_markdown, caption_html=caption_html, reply_to=reply_to, - buttons=buttons, + keyboard=keyboard, ) @@ -189,7 +187,7 @@ async def send_file( caption_markdown: Optional[str] = None, caption_html: Optional[str] = None, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]], + keyboard: Optional[KeyboardType], ) -> Message: message, entities = parse_message( text=caption, markdown=caption_markdown, html=caption_html, allow_empty=True @@ -198,7 +196,7 @@ async def send_file( # Re-send existing file. if isinstance(file, File): return await do_send_file( - self, chat, file._input_media, message, entities, reply_to, buttons + self, chat, file._input_media, message, entities, reply_to, keyboard ) # URLs are handled early as they can't use any other attributes either. @@ -222,7 +220,7 @@ async def send_file( spoiler=False, url=file, ttl_seconds=None ) return await do_send_file( - self, chat, input_media, message, entities, reply_to, buttons + self, chat, input_media, message, entities, reply_to, keyboard ) input_file, name = await upload(self, file, size, name) @@ -288,7 +286,7 @@ async def send_file( ) return await do_send_file( - self, chat, input_media, message, entities, reply_to, buttons + self, chat, input_media, message, entities, reply_to, keyboard ) @@ -299,7 +297,7 @@ async def do_send_file( message: str, entities: Optional[list[abcs.MessageEntity]], reply_to: Optional[int], - buttons: Optional[list[btns.Button] | list[list[btns.Button]]], + keyboard: Optional[KeyboardType], ) -> Message: random_id = generate_random_id() return client._build_message_map( @@ -319,7 +317,7 @@ async def do_send_file( media=input_media, message=message, random_id=random_id, - reply_markup=btns.build_keyboard(buttons), + reply_markup=keyboard._raw if keyboard else None, entities=entities, schedule_date=None, send_as=None, diff --git a/client/src/telethon/_impl/client/client/messages.py b/client/src/telethon/_impl/client/client/messages.py index 13d31985..23f038a9 100644 --- a/client/src/telethon/_impl/client/client/messages.py +++ b/client/src/telethon/_impl/client/client/messages.py @@ -6,9 +6,16 @@ from typing import TYPE_CHECKING, Literal, Optional, Self from ...session import ChannelRef, PeerRef from ...tl import abcs, functions, types -from ..types import AsyncList, Message, Peer, build_chat_map -from ..types import buttons as btns -from ..types import generate_random_id, parse_message, peer_id +from ..types import ( + AsyncList, + KeyboardType, + Message, + Peer, + build_chat_map, + generate_random_id, + parse_message, + peer_id, +) if TYPE_CHECKING: from .client import Client @@ -24,7 +31,7 @@ async def send_message( html: Optional[str] = None, link_preview: bool = False, reply_to: Optional[int] = None, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: random_id = generate_random_id() @@ -71,7 +78,7 @@ async def send_message( ), message=message, random_id=random_id, - reply_markup=btns.build_keyboard(buttons), + reply_markup=keyboard._raw if keyboard else None, entities=entities, schedule_date=None, send_as=None, @@ -121,7 +128,7 @@ async def edit_message( markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[list[btns.Button] | list[list[btns.Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: message, entities = parse_message( text=text, markdown=markdown, html=html, allow_empty=False @@ -134,7 +141,7 @@ async def edit_message( id=message_id, message=message, media=None, - reply_markup=btns.build_keyboard(buttons), + reply_markup=keyboard._raw if keyboard else None, entities=entities, schedule_date=None, ) diff --git a/client/src/telethon/_impl/client/client/updates.py b/client/src/telethon/_impl/client/client/updates.py index 00096378..388785f9 100644 --- a/client/src/telethon/_impl/client/client/updates.py +++ b/client/src/telethon/_impl/client/client/updates.py @@ -9,7 +9,7 @@ from ...session import Gap from ...tl import abcs from ..events import Continue from ..events import Event as EventBase -from ..events.filters import Filter +from ..events.filters import FilterType from ..types import build_chat_map if TYPE_CHECKING: @@ -21,7 +21,7 @@ UPDATE_LIMIT_EXCEEDED_LOG_COOLDOWN = 300 def on( - self: Client, event_cls: Type[Event], /, filter: Optional[Filter] = None + self: Client, event_cls: Type[Event], /, filter: Optional[FilterType] = None ) -> Callable[[Callable[[Event], Awaitable[Any]]], Callable[[Event], Awaitable[Any]]]: def wrapper( handler: Callable[[Event], Awaitable[Any]], @@ -37,7 +37,7 @@ def add_event_handler( handler: Callable[[Event], Awaitable[Any]], /, event_cls: Type[Event], - filter: Optional[Filter] = None, + filter: Optional[FilterType] = None, ) -> None: self._handlers.setdefault(event_cls, []).append((handler, filter)) @@ -55,7 +55,7 @@ def remove_event_handler( def get_handler_filter( self: Client, handler: Callable[[Event], Awaitable[Any]], / -) -> Optional[Filter]: +) -> Optional[FilterType]: for handlers in self._handlers.values(): for h, f in handlers: if h == handler: @@ -67,7 +67,7 @@ def set_handler_filter( self: Client, handler: Callable[[Event], Awaitable[Any]], /, - filter: Optional[Filter] = None, + filter: Optional[FilterType] = None, ) -> None: for handlers in self._handlers.values(): for i, (h, _) in enumerate(handlers): diff --git a/client/src/telethon/_impl/client/events/filters/__init__.py b/client/src/telethon/_impl/client/events/filters/__init__.py index cca00c36..f6f3a7ae 100644 --- a/client/src/telethon/_impl/client/events/filters/__init__.py +++ b/client/src/telethon/_impl/client/events/filters/__init__.py @@ -1,12 +1,12 @@ from .callback import Data -from .combinators import All, Any, Filter, Not +from .combinators import All, Any, FilterType, Not from .common import Chats, ChatType, Senders from .messages import Command, Forward, Incoming, Media, Outgoing, Reply, Text __all__ = [ "All", "Any", - "Filter", + "FilterType", "Not", "Chats", "ChatType", diff --git a/client/src/telethon/_impl/client/events/filters/combinators.py b/client/src/telethon/_impl/client/events/filters/combinators.py index 7835526d..ff03dfeb 100644 --- a/client/src/telethon/_impl/client/events/filters/combinators.py +++ b/client/src/telethon/_impl/client/events/filters/combinators.py @@ -6,7 +6,7 @@ from typing import Awaitable, TypeAlias from ..event import Event -Filter: TypeAlias = Callable[[Event], bool | Awaitable[bool]] +FilterType: TypeAlias = Callable[[Event], bool | Awaitable[bool]] class Combinable(abc.ABC): @@ -22,7 +22,7 @@ class Combinable(abc.ABC): Multiple ``~`` will toggle between using :class:`Not` and not using it. """ - def __or__(self, other: typing.Any) -> Filter: + def __or__(self, other: typing.Any) -> FilterType: if not callable(other): return NotImplemented @@ -30,7 +30,7 @@ class Combinable(abc.ABC): rhs = other.filters if isinstance(other, Any) else (other,) return Any(*lhs, *rhs) # type: ignore [arg-type] - def __and__(self, other: typing.Any) -> Filter: + def __and__(self, other: typing.Any) -> FilterType: if not callable(other): return NotImplemented @@ -38,7 +38,7 @@ class Combinable(abc.ABC): rhs = other.filters if isinstance(other, All) else (other,) return All(*lhs, *rhs) # type: ignore [arg-type] - def __invert__(self) -> Filter: + def __invert__(self) -> FilterType: return self.filter if isinstance(self, Not) else Not(self) # type: ignore [return-value] @abc.abstractmethod @@ -72,11 +72,13 @@ class Any(Combinable): __slots__ = ("_filters",) - def __init__(self, filter1: Filter, filter2: Filter, *filters: Filter) -> None: + def __init__( + self, filter1: FilterType, filter2: FilterType, *filters: FilterType + ) -> None: self._filters = (filter1, filter2, *filters) @property - def filters(self) -> tuple[Filter, ...]: + def filters(self) -> tuple[FilterType, ...]: """ The filters being checked, in order. """ @@ -116,11 +118,13 @@ class All(Combinable): __slots__ = ("_filters",) - def __init__(self, filter1: Filter, filter2: Filter, *filters: Filter) -> None: + def __init__( + self, filter1: FilterType, filter2: FilterType, *filters: FilterType + ) -> None: self._filters = (filter1, filter2, *filters) @property - def filters(self) -> tuple[Filter, ...]: + def filters(self) -> tuple[FilterType, ...]: """ The filters being checked, in order. """ @@ -158,11 +162,11 @@ class Not(Combinable): __slots__ = ("_filter",) - def __init__(self, filter: Filter) -> None: + def __init__(self, filter: FilterType) -> None: self._filter = filter @property - def filter(self) -> Filter: + def filter(self) -> FilterType: """ The filter being negated. """ diff --git a/client/src/telethon/_impl/client/types/__init__.py b/client/src/telethon/_impl/client/types/__init__.py index 1082664a..df726a69 100644 --- a/client/src/telethon/_impl/client/types/__init__.py +++ b/client/src/telethon/_impl/client/types/__init__.py @@ -14,6 +14,7 @@ from .file import ( try_get_url_path, ) from .inline_result import InlineResult +from .keyboard import InlineKeyboard, Keyboard, KeyboardType from .login_token import LoginToken from .message import ( Message, @@ -60,4 +61,7 @@ __all__ = [ "Participant", "PasswordToken", "RecentAction", + "Keyboard", + "InlineKeyboard", + "KeyboardType", ] diff --git a/client/src/telethon/_impl/client/types/buttons/__init__.py b/client/src/telethon/_impl/client/types/buttons/__init__.py index 89e7c4a0..974b5824 100644 --- a/client/src/telethon/_impl/client/types/buttons/__init__.py +++ b/client/src/telethon/_impl/client/types/buttons/__init__.py @@ -1,7 +1,7 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING from ....tl import abcs, types from .button import Button @@ -18,45 +18,6 @@ if TYPE_CHECKING: from ..message import Message -def as_concrete_row(row: abcs.KeyboardButtonRow) -> types.KeyboardButtonRow: - assert isinstance(row, types.KeyboardButtonRow) - return row - - -def build_keyboard( - btns: Optional[list[Button] | list[list[Button]]], -) -> Optional[abcs.ReplyMarkup]: - # list[button] -> list[list[button]] - # This does allow for "invalid" inputs (mixing lists and non-lists), but that's acceptable. - buttons_lists_iter = ( - button if isinstance(button, list) else [button] for button in (btns or []) - ) - # Remove empty rows (also making it easy to check if all-empty). - buttons_lists = [bs for bs in buttons_lists_iter if bs] - - if not buttons_lists: - return None - - rows: list[abcs.KeyboardButtonRow] = [ - types.KeyboardButtonRow(buttons=[btn._raw for btn in btns]) - for btns in buttons_lists - ] - - # Guaranteed to have at least one, first one used to check if it's inline. - # If the user mixed inline with non-inline, Telegram will complain. - if isinstance(buttons_lists[0][0], InlineButton): - return types.ReplyInlineMarkup(rows=rows) - else: - return types.ReplyKeyboardMarkup( - resize=False, - single_use=False, - selective=False, - persistent=False, - rows=rows, - placeholder=None, - ) - - def create_button(message: Message, raw: abcs.KeyboardButton) -> Button: """ Create a custom button from a Telegram button. diff --git a/client/src/telethon/_impl/client/types/buttons/button.py b/client/src/telethon/_impl/client/types/buttons/button.py index 558e8ef6..6c6b8bae 100644 --- a/client/src/telethon/_impl/client/types/buttons/button.py +++ b/client/src/telethon/_impl/client/types/buttons/button.py @@ -1,7 +1,7 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, TypeAlias from ....tl import types @@ -9,7 +9,7 @@ if TYPE_CHECKING: from ..message import Message -ButtonTypes = ( +RawButtonType: TypeAlias = ( types.KeyboardButton | types.KeyboardButtonUrl | types.KeyboardButtonCallback @@ -53,7 +53,7 @@ class Button: f"Can't instantiate abstract class {self.__class__.__name__}" ) - self._raw: ButtonTypes = types.KeyboardButton(text=text) + self._raw: RawButtonType = types.KeyboardButton(text=text) self._msg: Optional[weakref.ReferenceType[Message]] = None @property diff --git a/client/src/telethon/_impl/client/types/keyboard.py b/client/src/telethon/_impl/client/types/keyboard.py new file mode 100644 index 00000000..a9e51e15 --- /dev/null +++ b/client/src/telethon/_impl/client/types/keyboard.py @@ -0,0 +1,53 @@ +from typing import Optional, TypeAlias + +from ...tl import abcs, types +from .buttons.button import Button + + +def _build_keyboard_rows( + btns: list[Button] | list[list[Button]], +) -> list[abcs.KeyboardButtonRow]: + # list[button] -> list[list[button]] + # This does allow for "invalid" inputs (mixing lists and non-lists), but that's acceptable. + buttons_lists_iter = [ + button if isinstance(button, list) else [button] for button in (btns or []) + ] + # Remove empty rows (also making it easy to check if all-empty). + buttons_lists = [bs for bs in buttons_lists_iter if bs] + + return [ + types.KeyboardButtonRow(buttons=[btn._raw for btn in btns]) + for btns in buttons_lists + ] + + +class Keyboard: + __slots__ = ("_raw",) + + def __init__( + self, + buttons: list[Button] | list[list[Button]], + resize: bool, + single_use: bool, + selective: bool, + persistent: bool, + placeholder: Optional[str], + ) -> None: + self._raw = types.ReplyKeyboardMarkup( + resize=resize, + single_use=single_use, + selective=selective, + persistent=persistent, + rows=_build_keyboard_rows(buttons), + placeholder=placeholder, + ) + + +class InlineKeyboard: + __slots__ = ("_raw",) + + def __init__(self, buttons: list[Button] | list[list[Button]]) -> None: + self._raw = types.ReplyInlineMarkup(rows=_build_keyboard_rows(buttons)) + + +KeyboardType: TypeAlias = Keyboard | InlineKeyboard diff --git a/client/src/telethon/_impl/client/types/message.py b/client/src/telethon/_impl/client/types/message.py index 074d5dca..4d37263d 100644 --- a/client/src/telethon/_impl/client/types/message.py +++ b/client/src/telethon/_impl/client/types/message.py @@ -2,7 +2,7 @@ from __future__ import annotations import datetime import time -from typing import TYPE_CHECKING, Any, Optional, Self, Sequence +from typing import TYPE_CHECKING, Any, Optional, Self, Sequence, cast from ...session import PeerRef from ...tl import abcs, types @@ -12,8 +12,9 @@ from ..parsers import ( parse_html_message, parse_markdown_message, ) -from .buttons import Button, as_concrete_row, create_button +from .buttons import Button, create_button from .file import File +from .keyboard import KeyboardType from .meta import NoPublicConstructor from .peer import Peer, expand_peer, peer_id @@ -333,7 +334,7 @@ class Message(metaclass=NoPublicConstructor): markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[list[Button] | list[list[Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: """ Alias for :meth:`telethon.Client.send_message`. @@ -342,7 +343,7 @@ class Message(metaclass=NoPublicConstructor): :param markdown: See :ref:`formatting`. :param html: See :ref:`formatting`. :param link_preview: See :meth:`~telethon.Client.send_message`. - :param buttons: See :meth:`~telethon.Client.send_message`. + :param keyboard: See :meth:`~telethon.Client.send_message`. """ return await self._client.send_message( self.chat, @@ -350,7 +351,7 @@ class Message(metaclass=NoPublicConstructor): markdown=markdown, html=html, link_preview=link_preview, - buttons=buttons, + keyboard=keyboard, ) async def reply( @@ -360,7 +361,7 @@ class Message(metaclass=NoPublicConstructor): markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[list[Button] | list[list[Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: """ Alias for :meth:`telethon.Client.send_message` with the ``reply_to`` parameter set to this message. @@ -369,7 +370,7 @@ class Message(metaclass=NoPublicConstructor): :param markdown: See :ref:`formatting`. :param html: See :ref:`formatting`. :param link_preview: See :meth:`~telethon.Client.send_message`. - :param buttons: See :meth:`~telethon.Client.send_message`. + :param keyboard: See :meth:`~telethon.Client.send_message`. """ return await self._client.send_message( self.chat, @@ -378,7 +379,7 @@ class Message(metaclass=NoPublicConstructor): html=html, link_preview=link_preview, reply_to=self.id, - buttons=buttons, + keyboard=keyboard, ) async def delete(self, *, revoke: bool = True) -> None: @@ -395,7 +396,7 @@ class Message(metaclass=NoPublicConstructor): markdown: Optional[str] = None, html: Optional[str] = None, link_preview: bool = False, - buttons: Optional[list[Button] | list[list[Button]]] = None, + keyboard: Optional[KeyboardType] = None, ) -> Message: """ Alias for :meth:`telethon.Client.edit_message`. @@ -404,7 +405,7 @@ class Message(metaclass=NoPublicConstructor): :param markdown: See :ref:`formatting`. :param html: See :ref:`formatting`. :param link_preview: See :meth:`~telethon.Client.send_message`. - :param buttons: See :meth:`~telethon.Client.send_message`. + :param keyboard: See :meth:`~telethon.Client.send_message`. """ return await self._client.edit_message( self.chat, @@ -413,7 +414,7 @@ class Message(metaclass=NoPublicConstructor): markdown=markdown, html=html, link_preview=link_preview, - buttons=buttons, + keyboard=keyboard, ) async def forward(self, target: Peer | PeerRef) -> Message: @@ -476,8 +477,11 @@ class Message(metaclass=NoPublicConstructor): return None return [ - [create_button(self, button) for button in row.buttons] - for row in map(as_concrete_row, markup.rows) + [ + create_button(self, button) + for button in cast(types.KeyboardButtonRow, row).buttons + ] + for row in markup.rows ] @property diff --git a/client/src/telethon/events/filters.py b/client/src/telethon/events/filters.py index 2ef8ad38..d76a90a7 100644 --- a/client/src/telethon/events/filters.py +++ b/client/src/telethon/events/filters.py @@ -7,6 +7,7 @@ When the return value is :data:`True`, the associated :mod:`~telethon.events` ha The :doc:`/concepts/updates` concept to learn to combine filters or define your own. """ + from .._impl.client.events.filters import ( All, Any, @@ -14,7 +15,7 @@ from .._impl.client.events.filters import ( ChatType, Command, Data, - Filter, + FilterType, Forward, Incoming, Media, @@ -31,7 +32,7 @@ __all__ = [ "Chats", "ChatType", "Command", - "Filter", + "FilterType", "Forward", "Incoming", "Media", diff --git a/client/src/telethon/types/__init__.py b/client/src/telethon/types/__init__.py index 01c3c013..0a47300d 100644 --- a/client/src/telethon/types/__init__.py +++ b/client/src/telethon/types/__init__.py @@ -13,7 +13,9 @@ from .._impl.client.types import ( Draft, File, Group, + InlineKeyboard, InlineResult, + Keyboard, LoginToken, Message, Participant, @@ -37,7 +39,9 @@ __all__ = [ "Draft", "File", "Group", + "InlineKeyboard", "InlineResult", + "Keyboard", "LoginToken", "Message", "Participant",