Skip to content
Merged

Test #54

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/docs/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ def get_title_list(s: str) -> list:
Bot keyboards
ReplyKeyboardMarkup
KeyboardButton
KeyboardButtonStyle
ReplyKeyboardRemove
InlineKeyboardMarkup
InlineKeyboardButton
Expand Down
2 changes: 1 addition & 1 deletion pyrogram/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

__version__ = "v0.2.224.2"
__version__ = "v0.2.224.3"
__license__ = "MIT License"

from concurrent.futures.thread import ThreadPoolExecutor
Expand Down
2 changes: 2 additions & 0 deletions pyrogram/types/bots_and_keyboards/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from .inline_keyboard_button_buy import InlineKeyboardButtonBuy
from .inline_keyboard_markup import InlineKeyboardMarkup
from .keyboard_button import KeyboardButton
from .keyboard_button_style import KeyboardButtonStyle
from .login_url import LoginUrl
from .menu_button import MenuButton
from .menu_button_commands import MenuButtonCommands
Expand Down Expand Up @@ -69,6 +70,7 @@
"InlineKeyboardButtonBuy",
"InlineKeyboardMarkup",
"KeyboardButton",
"KeyboardButtonStyle",
"LoginUrl",
"MenuButton",
"MenuButtonCommands",
Expand Down
45 changes: 39 additions & 6 deletions pyrogram/types/bots_and_keyboards/inline_keyboard_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class InlineKeyboardButton(Object):

copy_text (``str``, *optional*):
A button that copies the text to the clipboard.

style (:obj:`~pyrogram.types.KeyboardButtonStyle`, *optional*):
Button style.
"""

def __init__(
Expand All @@ -71,6 +74,7 @@ def __init__(
callback_game: types.CallbackGame | None = None,
requires_password: bool | None = None,
copy_text: str | None = None,
style: types.KeyboardButtonStyle | None = None,
) -> None:
super().__init__()

Expand All @@ -85,9 +89,12 @@ def __init__(
self.callback_game = callback_game
self.requires_password = requires_password
self.copy_text = copy_text
self.style = style

@staticmethod
def read(b: raw.base.KeyboardButton):
style = types.KeyboardButtonStyle.read(getattr(b, "style", None))

if isinstance(b, raw.types.KeyboardButtonCallback):
# Try decode data to keep it as string, but if fails, fallback to bytes so we don't lose any information,
# instead of decoding by ignoring/replacing errors.
Expand All @@ -100,48 +107,63 @@ def read(b: raw.base.KeyboardButton):
text=b.text,
callback_data=data,
requires_password=getattr(b, "requires_password", None),
style=style,
)

if isinstance(b, raw.types.KeyboardButtonUrl):
return InlineKeyboardButton(text=b.text, url=b.url)
return InlineKeyboardButton(text=b.text, url=b.url, style=style)

if isinstance(b, raw.types.KeyboardButtonUrlAuth):
return InlineKeyboardButton(
text=b.text,
login_url=types.LoginUrl.read(b),
style=style,
)

if isinstance(b, raw.types.KeyboardButtonUserProfile):
return InlineKeyboardButton(text=b.text, user_id=b.user_id)
return InlineKeyboardButton(text=b.text, user_id=b.user_id, style=style)

if isinstance(b, raw.types.KeyboardButtonSwitchInline):
if b.same_peer:
return InlineKeyboardButton(
text=b.text,
switch_inline_query_current_chat=b.query,
style=style,
)
return InlineKeyboardButton(text=b.text, switch_inline_query=b.query)
return InlineKeyboardButton(
text=b.text,
switch_inline_query=b.query,
style=style,
)

if isinstance(b, raw.types.KeyboardButtonGame):
return InlineKeyboardButton(
text=b.text,
callback_game=types.CallbackGame(),
style=style,
)

if isinstance(b, raw.types.KeyboardButtonWebView):
return InlineKeyboardButton(
text=b.text,
web_app=types.WebAppInfo(url=b.url),
style=style,
)

if isinstance(b, raw.types.KeyboardButtonCopy):
return types.InlineKeyboardButton(text=b.text, copy_text=b.copy_text)
return types.InlineKeyboardButton(
text=b.text,
copy_text=b.copy_text,
style=style,
)

if isinstance(b, raw.types.KeyboardButtonBuy):
return types.InlineKeyboardButtonBuy.read(b)
return None

async def write(self, client: pyrogram.Client):
style = self.style.write() if self.style else None

if self.callback_data is not None:
# Telegram only wants bytes, but we are allowed to pass strings too, for convenience.
data = (
Expand All @@ -154,47 +176,58 @@ async def write(self, client: pyrogram.Client):
text=self.text,
data=data,
requires_password=self.requires_password,
style=style,
)

if self.url is not None:
return raw.types.KeyboardButtonUrl(text=self.text, url=self.url)
return raw.types.KeyboardButtonUrl(
text=self.text,
url=self.url,
style=style,
)

if self.login_url is not None:
return self.login_url.write(
text=self.text,
bot=await client.resolve_peer(self.login_url.bot_username or "self"),
style=style,
)

if self.user_id is not None:
return raw.types.InputKeyboardButtonUserProfile(
text=self.text,
user_id=await client.resolve_peer(self.user_id),
style=style,
)

if self.switch_inline_query is not None:
return raw.types.KeyboardButtonSwitchInline(
text=self.text,
query=self.switch_inline_query,
style=style,
)

if self.switch_inline_query_current_chat is not None:
return raw.types.KeyboardButtonSwitchInline(
text=self.text,
query=self.switch_inline_query_current_chat,
same_peer=True,
style=style,
)

if self.callback_game is not None:
return raw.types.KeyboardButtonGame(text=self.text)
return raw.types.KeyboardButtonGame(text=self.text, style=style)

if self.web_app is not None:
return raw.types.KeyboardButtonWebView(
text=self.text,
url=self.web_app.url,
style=style,
)
if self.copy_text is not None:
return raw.types.KeyboardButtonCopy(
text=self.text,
copy_text=self.copy_text,
style=style,
)
return None
22 changes: 18 additions & 4 deletions pyrogram/types/bots_and_keyboards/inline_keyboard_button_buy.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import pyrogram
from pyrogram import raw
from pyrogram import raw, types
from pyrogram.types.object import Object


Expand All @@ -13,16 +13,30 @@ class InlineKeyboardButtonBuy(Object):
text (``str``):
Text of the button. If none of the optional fields are used, it will be sent as a message when
the button is pressed.

style (:obj:`~pyrogram.types.KeyboardButtonStyle`, *optional*):
Button style.
"""

def __init__(self, text: str) -> None:
def __init__(
self,
text: str,
style: types.KeyboardButtonStyle | None = None,
) -> None:
super().__init__()

self.text = str(text)
self.style = style

@staticmethod
def read(b):
return InlineKeyboardButtonBuy(text=b.text)
return InlineKeyboardButtonBuy(
text=b.text,
style=types.KeyboardButtonStyle.read(getattr(b, "style", None)),
)

async def write(self, _: pyrogram.Client):
return raw.types.KeyboardButtonBuy(text=self.text)
return raw.types.KeyboardButtonBuy(
text=self.text,
style=self.style.write() if self.style else None,
)
34 changes: 27 additions & 7 deletions pyrogram/types/bots_and_keyboards/keyboard_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class KeyboardButton(Object):
button is pressed. The Web App will be able to send a “web_app_data” service message. Available in private
chats only.

style (:obj:`~pyrogram.types.KeyboardButtonStyle`, *optional*):
Button style.
"""

def __init__(
Expand All @@ -46,6 +48,7 @@ def __init__(
| types.RequestPeerTypeChannel = None,
request_user: types.RequestPeerTypeUser = None,
web_app: types.WebAppInfo = None,
style: types.KeyboardButtonStyle = None,
) -> None:
super().__init__()

Expand All @@ -55,20 +58,27 @@ def __init__(
self.request_chat = request_chat
self.request_user = request_user
self.web_app = web_app
self.style = style

@staticmethod
def read(b):
style = types.KeyboardButtonStyle.read(getattr(b, "style", None))

if isinstance(b, raw.types.KeyboardButton):
return b.text
return KeyboardButton(text=b.text, style=style) if style else b.text

if isinstance(b, raw.types.KeyboardButtonRequestPhone):
return KeyboardButton(text=b.text, request_contact=True)
return KeyboardButton(text=b.text, request_contact=True, style=style)

if isinstance(b, raw.types.KeyboardButtonRequestGeoLocation):
return KeyboardButton(text=b.text, request_location=True)
return KeyboardButton(text=b.text, request_location=True, style=style)

if isinstance(b, raw.types.KeyboardButtonSimpleWebView):
return KeyboardButton(text=b.text, web_app=types.WebAppInfo(url=b.url))
return KeyboardButton(
text=b.text,
web_app=types.WebAppInfo(url=b.url),
style=style,
)

if isinstance(b, raw.types.KeyboardButtonRequestPeer):
if isinstance(b.peer_type, raw.types.RequestPeerTypeBroadcast):
Expand All @@ -79,6 +89,7 @@ def read(b):
is_username=b.peer_type.has_username,
max=b.max_quantity,
),
style=style,
)
if isinstance(b.peer_type, raw.types.RequestPeerTypeChat):
return KeyboardButton(
Expand All @@ -90,6 +101,7 @@ def read(b):
is_forum=b.peer_type.forum,
max=b.max_quantity,
),
style=style,
)

if isinstance(b.peer_type, raw.types.RequestPeerTypeUser):
Expand All @@ -100,17 +112,24 @@ def read(b):
is_premium=b.peer_type.premium,
max=b.max_quantity,
),
style=style,
)
return None
return None

def write(self):
style = self.style.write() if self.style else None

if self.request_contact:
return raw.types.KeyboardButtonRequestPhone(text=self.text)
return raw.types.KeyboardButtonRequestPhone(text=self.text, style=style)
if self.request_location:
return raw.types.KeyboardButtonRequestGeoLocation(text=self.text)
return raw.types.KeyboardButtonRequestGeoLocation(
text=self.text,
style=style,
)
if self.request_chat:
if isinstance(self.request_chat, types.RequestPeerTypeChannel):
# Note: InputKeyboardButtonRequestPeer doesn't have style in schema
return raw.types.InputKeyboardButtonRequestPeer(
text=self.text,
button_id=self.request_chat.button_id,
Expand Down Expand Up @@ -154,5 +173,6 @@ def write(self):
return raw.types.KeyboardButtonSimpleWebView(
text=self.text,
url=self.web_app.url,
style=style,
)
return raw.types.KeyboardButton(text=self.text)
return raw.types.KeyboardButton(text=self.text, style=style)
57 changes: 57 additions & 0 deletions pyrogram/types/bots_and_keyboards/keyboard_button_style.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from __future__ import annotations

from pyrogram import raw
from pyrogram.types.object import Object


class KeyboardButtonStyle(Object):
"""Button style.

Parameters:
bg_primary (``bool``, *optional*):
Whether the button should be primary.

bg_danger (``bool``, *optional*):
Whether the button should be danger.

bg_success (``bool``, *optional*):
Whether the button should be success.

icon (``int``, *optional*):
Custom icon for the button.
"""

def __init__(
self,
*,
bg_primary: bool | None = None,
bg_danger: bool | None = None,
bg_success: bool | None = None,
icon: int | None = None,
) -> None:
super().__init__()

self.bg_primary = bg_primary
self.bg_danger = bg_danger
self.bg_success = bg_success
self.icon = icon

@staticmethod
def read(b: raw.types.KeyboardButtonStyle) -> KeyboardButtonStyle | None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The type hint for the b parameter is raw.types.KeyboardButtonStyle, but the implementation correctly handles None as a possible value, as seen in the if not b: check. To make the type hint accurate and improve type safety, it should be updated to raw.types.KeyboardButtonStyle | None.

Suggested change
def read(b: raw.types.KeyboardButtonStyle) -> KeyboardButtonStyle | None:
def read(b: raw.types.KeyboardButtonStyle | None) -> KeyboardButtonStyle | None:

if not b:
return None

return KeyboardButtonStyle(
bg_primary=b.bg_primary,
bg_danger=b.bg_danger,
bg_success=b.bg_success,
icon=b.icon,
)

def write(self) -> raw.types.KeyboardButtonStyle:
return raw.types.KeyboardButtonStyle(
bg_primary=self.bg_primary,
bg_danger=self.bg_danger,
bg_success=self.bg_success,
icon=self.icon,
)
Loading
Loading