Adding ReplyKeyboardMarkup and ReplyInlineMarkup custom types

This commit is contained in:
Jahongir Qurbonov 2024-08-19 17:54:51 +05:00
parent ee3248c3a4
commit 21d2ded546
6 changed files with 112 additions and 59 deletions

View File

@ -45,7 +45,7 @@ from ..types import (
RecentAction,
User,
)
from ..types import buttons as btns
from ..types.buttons.reply_markup import ReplyMarkupType
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
@ -571,7 +572,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,
buttons: Optional[ReplyMarkupType] = None,
) -> Message:
"""
Edit a message.
@ -1393,7 +1394,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,
buttons: Optional[ReplyMarkupType] = None,
) -> Message:
"""
Send an audio file.
@ -1466,7 +1467,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]]],
buttons: Optional[ReplyMarkupType],
) -> Message:
"""
Send any type of file with any amount of attributes.
@ -1633,7 +1634,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,
buttons: Optional[ReplyMarkupType] = None,
) -> Message:
"""
Send a message.
@ -1687,7 +1688,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,
buttons: Optional[ReplyMarkupType] = None,
) -> Message:
"""
Send a photo file.
@ -1755,7 +1756,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]]],
buttons: Optional[ReplyMarkupType],
) -> Message:
"""
Send a video file.

View File

@ -17,14 +17,12 @@ from ..types import (
OutFileLike,
OutWrapper,
Peer,
)
from ..types import buttons as btns
from ..types import (
expand_stripped_size,
generate_random_id,
parse_message,
try_get_url_path,
)
from ..types.buttons.reply_markup import ReplyMarkupType
if TYPE_CHECKING:
from .client import Client
@ -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,
buttons: Optional[ReplyMarkupType] = None,
) -> Message:
return await send_file(
self,
@ -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,
buttons: Optional[ReplyMarkupType] = None,
) -> Message:
return await send_file(
self,
@ -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]]],
buttons: Optional[ReplyMarkupType],
) -> Message:
return await send_file(
self,
@ -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]]],
buttons: Optional[ReplyMarkupType],
) -> Message:
message, entities = parse_message(
text=caption, markdown=caption_markdown, html=caption_html, allow_empty=True
@ -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]]],
buttons: Optional[ReplyMarkupType],
) -> 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=buttons.build() if buttons is not None else None,
entities=entities,
schedule_date=None,
send_as=None,

View File

@ -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,
Message,
Peer,
build_chat_map,
generate_random_id,
parse_message,
peer_id,
)
from ..types.buttons.reply_markup import ReplyMarkupType
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,
buttons: Optional[ReplyMarkupType] = 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=buttons.build() if buttons is not None 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,
buttons: Optional[ReplyMarkupType] = 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=buttons.build() if buttons is not None else None,
entities=entities,
schedule_date=None,
)

View File

@ -1,12 +1,13 @@
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
from .callback import Callback
from .inline_button import InlineButton
from .reply_markup import ReplyInlineMarkup, ReplyKeyboardMarkup
from .request_geo_location import RequestGeoLocation
from .request_phone import RequestPhone
from .request_poll import RequestPoll
@ -23,40 +24,6 @@ def as_concrete_row(row: abcs.KeyboardButtonRow) -> 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.
@ -113,6 +80,8 @@ __all__ = [
"Button",
"Callback",
"InlineButton",
"ReplyInlineMarkup",
"ReplyKeyboardMarkup",
"RequestGeoLocation",
"RequestPhone",
"RequestPoll",

View File

@ -0,0 +1,71 @@
from typing import Optional, TypeAlias
from ....tl import abcs, types
from .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 ReplyKeyboardMarkup:
__slots__ = (
"_btns",
"resize",
"single_use",
"selective",
"persistent",
"placeholder",
)
def __init__(
self,
btns: list[Button] | list[list[Button]],
resize: bool,
single_use: bool,
selective: bool,
persistent: bool,
placeholder: Optional[str],
) -> None:
self._btns = build_keyboard_rows(btns)
self.resize = resize
self.single_use = single_use
self.selective = selective
self.persistent = persistent
self.placeholder = placeholder
def build(self) -> abcs.ReplyMarkup:
return types.ReplyKeyboardMarkup(
resize=self.resize,
single_use=self.single_use,
selective=self.selective,
persistent=self.persistent,
rows=self._btns,
placeholder=self.placeholder,
)
class ReplyInlineMarkup:
__slots__ = ("_btns",)
def __init__(self, btns: list[Button] | list[list[Button]]) -> None:
self._btns = build_keyboard_rows(btns)
def build(self) -> abcs.ReplyMarkup:
return types.ReplyInlineMarkup(rows=self._btns)
ReplyMarkupType: TypeAlias = ReplyKeyboardMarkup | ReplyInlineMarkup

View File

@ -22,7 +22,12 @@ from .._impl.client.types import (
RecentAction,
User,
)
from .._impl.client.types.buttons import Button, InlineButton
from .._impl.client.types.buttons import (
Button,
InlineButton,
ReplyInlineMarkup,
ReplyKeyboardMarkup,
)
from .._impl.session import ChannelRef, GroupRef, PeerRef, UserRef
__all__ = [
@ -42,6 +47,8 @@ __all__ = [
"Message",
"Participant",
"PasswordToken",
"ReplyInlineMarkup",
"ReplyKeyboardMarkup",
"RecentAction",
"User",
"Button",