From fa844fce591645dc61f4c350a694dc7da6426fe8 Mon Sep 17 00:00:00 2001 From: Kostiantyn Kriuchkov <36363097+Latand@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:22:56 +0200 Subject: [PATCH] Add icon and style args to keyboard builders (#1769) --- CHANGES/1768.bugfix.rst | 1 + aiogram/utils/keyboard.py | 8 +++ tests/test_utils/test_keyboard.py | 91 +++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 CHANGES/1768.bugfix.rst diff --git a/CHANGES/1768.bugfix.rst b/CHANGES/1768.bugfix.rst new file mode 100644 index 00000000..4b8c94bf --- /dev/null +++ b/CHANGES/1768.bugfix.rst @@ -0,0 +1 @@ +Added ``icon_custom_emoji_id`` and ``style`` parameters to ``InlineKeyboardBuilder.button`` and ``ReplyKeyboardBuilder.button`` signatures. diff --git a/aiogram/utils/keyboard.py b/aiogram/utils/keyboard.py index 8824edfd..2dba452c 100644 --- a/aiogram/utils/keyboard.py +++ b/aiogram/utils/keyboard.py @@ -303,6 +303,8 @@ class InlineKeyboardBuilder(KeyboardBuilder[InlineKeyboardButton]): self, *, text: str, + icon_custom_emoji_id: str | None = None, + style: str | None = None, url: str | None = None, callback_data: str | CallbackData | None = None, web_app: WebAppInfo | None = None, @@ -319,6 +321,8 @@ class InlineKeyboardBuilder(KeyboardBuilder[InlineKeyboardButton]): InlineKeyboardBuilder, self._button( text=text, + icon_custom_emoji_id=icon_custom_emoji_id, + style=style, url=url, callback_data=callback_data, web_app=web_app, @@ -375,6 +379,8 @@ class ReplyKeyboardBuilder(KeyboardBuilder[KeyboardButton]): self, *, text: str, + icon_custom_emoji_id: str | None = None, + style: str | None = None, request_users: KeyboardButtonRequestUsers | None = None, request_chat: KeyboardButtonRequestChat | None = None, request_contact: bool | None = None, @@ -387,6 +393,8 @@ class ReplyKeyboardBuilder(KeyboardBuilder[KeyboardButton]): ReplyKeyboardBuilder, self._button( text=text, + icon_custom_emoji_id=icon_custom_emoji_id, + style=style, request_users=request_users, request_chat=request_chat, request_contact=request_contact, diff --git a/tests/test_utils/test_keyboard.py b/tests/test_utils/test_keyboard.py index e80fed8e..b374e7ac 100644 --- a/tests/test_utils/test_keyboard.py +++ b/tests/test_utils/test_keyboard.py @@ -214,11 +214,63 @@ class TestKeyboardBuilder: "builder_type,kwargs,expected", [ [ReplyKeyboardBuilder, {"text": "test"}, KeyboardButton(text="test")], + [ + ReplyKeyboardBuilder, + {"text": "test", "icon_custom_emoji_id": "emoji-id"}, + KeyboardButton(text="test", icon_custom_emoji_id="emoji-id"), + ], + [ + ReplyKeyboardBuilder, + {"text": "test", "style": "success"}, + KeyboardButton(text="test", style="success"), + ], + [ + ReplyKeyboardBuilder, + {"text": "test", "icon_custom_emoji_id": "emoji-id", "style": "success"}, + KeyboardButton( + text="test", + icon_custom_emoji_id="emoji-id", + style="success", + ), + ], [ InlineKeyboardBuilder, {"text": "test", "callback_data": "callback"}, InlineKeyboardButton(text="test", callback_data="callback"), ], + [ + InlineKeyboardBuilder, + { + "text": "test", + "icon_custom_emoji_id": "emoji-id", + "callback_data": "callback", + }, + InlineKeyboardButton( + text="test", + icon_custom_emoji_id="emoji-id", + callback_data="callback", + ), + ], + [ + InlineKeyboardBuilder, + {"text": "test", "style": "primary", "callback_data": "callback"}, + InlineKeyboardButton(text="test", style="primary", callback_data="callback"), + ], + [ + InlineKeyboardBuilder, + { + "text": "test", + "icon_custom_emoji_id": "emoji-id", + "style": "primary", + "callback_data": "callback", + }, + InlineKeyboardButton( + text="test", + icon_custom_emoji_id="emoji-id", + style="primary", + callback_data="callback", + ), + ], [ InlineKeyboardBuilder, {"text": "test", "callback_data": MyCallback(value="test")}, @@ -242,6 +294,45 @@ class TestKeyboardBuilder: def test_as_markup(self, builder, expected): assert isinstance(builder.as_markup(), expected) + @pytest.mark.parametrize( + "builder,button_kwargs,icon_custom_emoji_id,style", + [ + [ + ReplyKeyboardBuilder(), + {"text": "test", "icon_custom_emoji_id": "emoji-id", "style": "success"}, + "emoji-id", + "success", + ], + [ + InlineKeyboardBuilder(), + { + "text": "test", + "icon_custom_emoji_id": "emoji-id", + "style": "primary", + "callback_data": "callback", + }, + "emoji-id", + "primary", + ], + ], + ) + def test_as_markup_preserves_icon_and_style( + self, + builder, + button_kwargs, + icon_custom_emoji_id, + style, + ): + builder.button(**button_kwargs) + markup = builder.as_markup() + if isinstance(markup, ReplyKeyboardMarkup): + button = markup.keyboard[0][0] + else: + button = markup.inline_keyboard[0][0] + + assert button.icon_custom_emoji_id == icon_custom_emoji_id + assert button.style == style + @pytest.mark.parametrize( "markup,builder_type", [