Added full support of the Bot API 9.4 (#1761)

* Bump API schema to version 9.4, add new object types, methods, and properties.

* Add tests for `ChatOwnerChanged` and `ChatOwnerLeft` message types

* Add tests for `GetUserProfileAudios`, `RemoveMyProfilePhoto`, and `SetMyProfilePhoto` methods

* Bump version

* Update Makefile variables and refactor `test_get_user_profile_audios.py`

* Document new features and updates from Bot API 9.4 in changelog

* Add `ButtonStyle` enum to represent button styles in the Telegram API

* Fix review issues from PR #1761

- Remove stray '-' artifact from GameHighScore docstring and butcher schema
- Fix Makefile reformat target scope inconsistency (ruff check --fix)
- Fix ButtonStyle enum source URL (#chat -> #inlinekeyboardbutton)
- Add User.get_profile_audios() shortcut method (parallel to get_profile_photos)
- Test ChatOwnerLeft with new_owner=None (edge case)
- Add VideoQuality type and Video.qualities nesting tests
- Add User.get_profile_audios() test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Revert "Fix review issues from PR #1761"

This reverts commit 2184e98988.

* Update source links for `ButtonStyle` documentation to reflect accurate API references

* Fix review issues from PR #1761 (#1762)

* Fix review issues from PR #1761

- Remove stray '-' artifact from GameHighScore docstring
- Fix Makefile reformat target scope inconsistency (ruff check --fix)
- Add User.get_profile_audios() shortcut method (parallel to get_profile_photos)
- Test ChatOwnerLeft with new_owner=None (edge case)
- Add VideoQuality type and Video.qualities nesting tests
- Add User.get_profile_audios() test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address review comments: use fixture and variables in tests, add changelog

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address review follow-ups for PR #1762

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Reformat code

* Shut up, ruff

---------

Co-authored-by: latand <latand666@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Kostiantyn Kriuchkov <36363097+Latand@users.noreply.github.com>
This commit is contained in:
Alex Root Junior 2026-02-10 23:43:52 +02:00 committed by GitHub
parent da7bfdca0c
commit 49d0784e33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 1457 additions and 61 deletions

View file

@ -1,2 +1,2 @@
__version__ = "3.24.0"
__api_version__ = "9.3"
__version__ = "3.25.0"
__api_version__ = "9.4"

View file

@ -92,6 +92,7 @@ from ..methods import (
GetUpdates,
GetUserChatBoosts,
GetUserGifts,
GetUserProfileAudios,
GetUserProfilePhotos,
GetWebhookInfo,
GiftPremiumSubscription,
@ -105,6 +106,7 @@ from ..methods import (
RefundStarPayment,
RemoveBusinessAccountProfilePhoto,
RemoveChatVerification,
RemoveMyProfilePhoto,
RemoveUserVerification,
ReopenForumTopic,
ReopenGeneralForumTopic,
@ -154,6 +156,7 @@ from ..methods import (
SetMyDefaultAdministratorRights,
SetMyDescription,
SetMyName,
SetMyProfilePhoto,
SetMyShortDescription,
SetPassportDataErrors,
SetStickerEmojiList,
@ -241,6 +244,7 @@ from ..types import (
Update,
User,
UserChatBoosts,
UserProfileAudios,
UserProfilePhotos,
WebhookInfo,
)
@ -911,7 +915,7 @@ class Bot:
request_timeout: int | None = None,
) -> ForumTopic:
"""
Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights. Returns information about the created topic as a :class:`aiogram.types.forum_topic.ForumTopic` object.
Use this method to create a topic in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator right. Returns information about the created topic as a :class:`aiogram.types.forum_topic.ForumTopic` object.
Source: https://core.telegram.org/bots/api#createforumtopic
@ -5842,3 +5846,65 @@ class Bot:
entities=entities,
)
return await self(call, request_timeout=request_timeout)
async def get_user_profile_audios(
self,
user_id: int,
offset: int | None = None,
limit: int | None = None,
request_timeout: int | None = None,
) -> UserProfileAudios:
"""
Use this method to get a list of profile audios for a user. Returns a :class:`aiogram.types.user_profile_audios.UserProfileAudios` object.
Source: https://core.telegram.org/bots/api#getuserprofileaudios
:param user_id: Unique identifier of the target user
:param offset: Sequential number of the first audio to be returned. By default, all audios are returned.
:param limit: Limits the number of audios to be retrieved. Values between 1-100 are accepted. Defaults to 100.
:param request_timeout: Request timeout
:return: Returns a :class:`aiogram.types.user_profile_audios.UserProfileAudios` object.
"""
call = GetUserProfileAudios(
user_id=user_id,
offset=offset,
limit=limit,
)
return await self(call, request_timeout=request_timeout)
async def remove_my_profile_photo(
self,
request_timeout: int | None = None,
) -> bool:
"""
Removes the profile photo of the bot. Requires no parameters. Returns :code:`True` on success.
Source: https://core.telegram.org/bots/api#removemyprofilephoto
:param request_timeout: Request timeout
:return: Returns :code:`True` on success.
"""
call = RemoveMyProfilePhoto()
return await self(call, request_timeout=request_timeout)
async def set_my_profile_photo(
self,
photo: InputProfilePhotoUnion,
request_timeout: int | None = None,
) -> bool:
"""
Changes the profile photo of the bot. Returns :code:`True` on success.
Source: https://core.telegram.org/bots/api#setmyprofilephoto
:param photo: The new profile photo to set
:param request_timeout: Request timeout
:return: Returns :code:`True` on success.
"""
call = SetMyProfilePhoto(
photo=photo,
)
return await self(call, request_timeout=request_timeout)

View file

@ -1,4 +1,5 @@
from .bot_command_scope_type import BotCommandScopeType
from .button_style import ButtonStyle
from .chat_action import ChatAction
from .chat_boost_source_type import ChatBoostSourceType
from .chat_member_status import ChatMemberStatus
@ -36,6 +37,7 @@ from .update_type import UpdateType
__all__ = (
"BotCommandScopeType",
"ButtonStyle",
"ChatAction",
"ChatBoostSourceType",
"ChatMemberStatus",

View file

@ -0,0 +1,15 @@
from enum import Enum
class ButtonStyle(str, Enum):
"""
This object represents a button style (inline- or reply-keyboard).
Sources:
* https://core.telegram.org/bots/api#inlinekeyboardbutton
* https://core.telegram.org/bots/api#keyboardbutton
"""
DANGER = "danger"
SUCCESS = "success"
PRIMARY = "primary"

View file

@ -28,6 +28,8 @@ class ContentType(str, Enum):
LOCATION = "location"
NEW_CHAT_MEMBERS = "new_chat_members"
LEFT_CHAT_MEMBER = "left_chat_member"
CHAT_OWNER_LEFT = "chat_owner_left"
CHAT_OWNER_CHANGED = "chat_owner_changed"
NEW_CHAT_TITLE = "new_chat_title"
NEW_CHAT_PHOTO = "new_chat_photo"
DELETE_CHAT_PHOTO = "delete_chat_photo"

View file

@ -74,6 +74,7 @@ from .get_sticker_set import GetStickerSet
from .get_updates import GetUpdates
from .get_user_chat_boosts import GetUserChatBoosts
from .get_user_gifts import GetUserGifts
from .get_user_profile_audios import GetUserProfileAudios
from .get_user_profile_photos import GetUserProfilePhotos
from .get_webhook_info import GetWebhookInfo
from .gift_premium_subscription import GiftPremiumSubscription
@ -87,6 +88,7 @@ from .read_business_message import ReadBusinessMessage
from .refund_star_payment import RefundStarPayment
from .remove_business_account_profile_photo import RemoveBusinessAccountProfilePhoto
from .remove_chat_verification import RemoveChatVerification
from .remove_my_profile_photo import RemoveMyProfilePhoto
from .remove_user_verification import RemoveUserVerification
from .reopen_forum_topic import ReopenForumTopic
from .reopen_general_forum_topic import ReopenGeneralForumTopic
@ -136,6 +138,7 @@ from .set_my_commands import SetMyCommands
from .set_my_default_administrator_rights import SetMyDefaultAdministratorRights
from .set_my_description import SetMyDescription
from .set_my_name import SetMyName
from .set_my_profile_photo import SetMyProfilePhoto
from .set_my_short_description import SetMyShortDescription
from .set_passport_data_errors import SetPassportDataErrors
from .set_sticker_emoji_list import SetStickerEmojiList
@ -238,6 +241,7 @@ __all__ = (
"GetUpdates",
"GetUserChatBoosts",
"GetUserGifts",
"GetUserProfileAudios",
"GetUserProfilePhotos",
"GetWebhookInfo",
"GiftPremiumSubscription",
@ -251,6 +255,7 @@ __all__ = (
"RefundStarPayment",
"RemoveBusinessAccountProfilePhoto",
"RemoveChatVerification",
"RemoveMyProfilePhoto",
"RemoveUserVerification",
"ReopenForumTopic",
"ReopenGeneralForumTopic",
@ -302,6 +307,7 @@ __all__ = (
"SetMyDefaultAdministratorRights",
"SetMyDescription",
"SetMyName",
"SetMyProfilePhoto",
"SetMyShortDescription",
"SetPassportDataErrors",
"SetStickerEmojiList",

View file

@ -8,7 +8,7 @@ from .base import TelegramMethod
class CreateForumTopic(TelegramMethod[ForumTopic]):
"""
Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator rights. Returns information about the created topic as a :class:`aiogram.types.forum_topic.ForumTopic` object.
Use this method to create a topic in a forum supergroup chat or a private chat with a user. In the case of a supergroup chat the bot must be an administrator in the chat for this to work and must have the *can_manage_topics* administrator right. Returns information about the created topic as a :class:`aiogram.types.forum_topic.ForumTopic` object.
Source: https://core.telegram.org/bots/api#createforumtopic
"""

View file

@ -0,0 +1,42 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from ..types import UserProfileAudios
from .base import TelegramMethod
class GetUserProfileAudios(TelegramMethod[UserProfileAudios]):
"""
Use this method to get a list of profile audios for a user. Returns a :class:`aiogram.types.user_profile_audios.UserProfileAudios` object.
Source: https://core.telegram.org/bots/api#getuserprofileaudios
"""
__returning__ = UserProfileAudios
__api_method__ = "getUserProfileAudios"
user_id: int
"""Unique identifier of the target user"""
offset: int | None = None
"""Sequential number of the first audio to be returned. By default, all audios are returned."""
limit: int | None = None
"""Limits the number of audios to be retrieved. Values between 1-100 are accepted. Defaults to 100."""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
# This section was auto-generated via `butcher`
def __init__(
__pydantic__self__,
*,
user_id: int,
offset: int | None = None,
limit: int | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(user_id=user_id, offset=offset, limit=limit, **__pydantic_kwargs)

View file

@ -0,0 +1,14 @@
from __future__ import annotations
from .base import TelegramMethod
class RemoveMyProfilePhoto(TelegramMethod[bool]):
"""
Removes the profile photo of the bot. Requires no parameters. Returns :code:`True` on success.
Source: https://core.telegram.org/bots/api#removemyprofilephoto
"""
__returning__ = bool
__api_method__ = "removeMyProfilePhoto"

View file

@ -0,0 +1,33 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from ..types import InputProfilePhotoUnion
from .base import TelegramMethod
class SetMyProfilePhoto(TelegramMethod[bool]):
"""
Changes the profile photo of the bot. Returns :code:`True` on success.
Source: https://core.telegram.org/bots/api#setmyprofilephoto
"""
__returning__ = bool
__api_method__ = "setMyProfilePhoto"
photo: InputProfilePhotoUnion
"""The new profile photo to set"""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
# This section was auto-generated via `butcher`
def __init__(
__pydantic__self__, *, photo: InputProfilePhotoUnion, **__pydantic_kwargs: Any
) -> None:
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(photo=photo, **__pydantic_kwargs)

View file

@ -387,6 +387,8 @@ __all__ = (
"ChatMemberRestricted",
"ChatMemberUnion",
"ChatMemberUpdated",
"ChatOwnerChanged",
"ChatOwnerLeft",
"ChatPermissions",
"ChatPhoto",
"ChatShared",
@ -627,6 +629,7 @@ __all__ = (
"Update",
"User",
"UserChatBoosts",
"UserProfileAudios",
"UserProfilePhotos",
"UserRating",
"UserShared",
@ -638,6 +641,7 @@ __all__ = (
"VideoChatScheduled",
"VideoChatStarted",
"VideoNote",
"VideoQuality",
"Voice",
"WebAppData",
"WebAppInfo",
@ -646,6 +650,10 @@ __all__ = (
)
from ..client.default import Default as _Default
from .chat_owner_changed import ChatOwnerChanged
from .chat_owner_left import ChatOwnerLeft
from .user_profile_audios import UserProfileAudios
from .video_quality import VideoQuality
# Load typing forward refs for every TelegramObject
for _entity_name in __all__:

View file

@ -9,6 +9,7 @@ from .custom import DateTime
if TYPE_CHECKING:
from .accepted_gift_types import AcceptedGiftTypes
from .audio import Audio
from .birthdate import Birthdate
from .business_intro import BusinessIntro
from .business_location import BusinessLocation
@ -125,6 +126,8 @@ class ChatFullInfo(Chat):
"""*Optional*. For supergroups, the location to which the supergroup is connected"""
rating: UserRating | None = None
"""*Optional*. For private chats, the rating of the user if any"""
first_profile_audio: Audio | None = None
"""*Optional*. For private chats, the first audio added to the profile of the user"""
unique_gift_colors: UniqueGiftColors | None = None
"""*Optional*. The color scheme based on a unique gift that must be used for the chat's name, message replies and link previews"""
paid_message_star_count: int | None = None
@ -190,6 +193,7 @@ class ChatFullInfo(Chat):
linked_chat_id: int | None = None,
location: ChatLocation | None = None,
rating: UserRating | None = None,
first_profile_audio: Audio | None = None,
unique_gift_colors: UniqueGiftColors | None = None,
paid_message_star_count: int | None = None,
can_send_gift: bool | None = None,
@ -248,6 +252,7 @@ class ChatFullInfo(Chat):
linked_chat_id=linked_chat_id,
location=location,
rating=rating,
first_profile_audio=first_profile_audio,
unique_gift_colors=unique_gift_colors,
paid_message_star_count=paid_message_star_count,
can_send_gift=can_send_gift,

View file

@ -0,0 +1,30 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
if TYPE_CHECKING:
from .user import User
class ChatOwnerChanged(TelegramObject):
"""
Describes a service message about an ownership change in the chat.
Source: https://core.telegram.org/bots/api#chatownerchanged
"""
new_owner: User
"""The new owner of the chat"""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
# This section was auto-generated via `butcher`
def __init__(__pydantic__self__, *, new_owner: User, **__pydantic_kwargs: Any) -> None:
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(new_owner=new_owner, **__pydantic_kwargs)

View file

@ -0,0 +1,32 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
if TYPE_CHECKING:
from .user import User
class ChatOwnerLeft(TelegramObject):
"""
Describes a service message about the chat owner leaving the chat.
Source: https://core.telegram.org/bots/api#chatownerleft
"""
new_owner: User | None = None
"""*Optional*. The user which will be the new owner of the chat if the previous owner does not return to the chat"""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
# This section was auto-generated via `butcher`
def __init__(
__pydantic__self__, *, new_owner: User | None = None, **__pydantic_kwargs: Any
) -> None:
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(new_owner=new_owner, **__pydantic_kwargs)

View file

@ -15,6 +15,8 @@ class GameHighScore(TelegramObject):
If you've got any questions, please check out our `https://core.telegram.org/bots/faq <https://core.telegram.org/bots/faq>`_ **Bot FAQ »**
-
Source: https://core.telegram.org/bots/api#gamehighscore
"""

View file

@ -14,13 +14,17 @@ if TYPE_CHECKING:
class InlineKeyboardButton(MutableTelegramObject):
"""
This object represents one button of an inline keyboard. Exactly one of the optional fields must be used to specify type of the button.
This object represents one button of an inline keyboard. Exactly one of the fields other than *text*, *icon_custom_emoji_id*, and *style* must be used to specify the type of the button.
Source: https://core.telegram.org/bots/api#inlinekeyboardbutton
"""
text: str
"""Label text on the button"""
icon_custom_emoji_id: str | None = None
"""*Optional*. Unique identifier of the custom emoji shown before the text of the button. Can only be used by bots that purchased additional usernames on `Fragment <https://fragment.com>`_ or in the messages directly sent by the bot to private, group and supergroup chats if the owner of the bot has a Telegram Premium subscription."""
style: str | None = None
"""*Optional*. Style of the button. Must be one of 'danger' (red), 'success' (green) or 'primary' (blue). If omitted, then an app-specific style is used."""
url: str | None = None
"""*Optional*. HTTP or tg:// URL to be opened when the button is pressed. Links :code:`tg://user?id=<user_id>` can be used to mention a user by their identifier without using a username, if this is allowed by their privacy settings."""
callback_data: str | None = None
@ -50,6 +54,8 @@ class InlineKeyboardButton(MutableTelegramObject):
__pydantic__self__,
*,
text: str,
icon_custom_emoji_id: str | None = None,
style: str | None = None,
url: str | None = None,
callback_data: str | None = None,
web_app: WebAppInfo | None = None,
@ -68,6 +74,8 @@ class InlineKeyboardButton(MutableTelegramObject):
super().__init__(
text=text,
icon_custom_emoji_id=icon_custom_emoji_id,
style=style,
url=url,
callback_data=callback_data,
web_app=web_app,

View file

@ -16,14 +16,17 @@ if TYPE_CHECKING:
class KeyboardButton(MutableTelegramObject):
"""
This object represents one button of the reply keyboard. At most one of the optional fields must be used to specify type of the button. For simple text buttons, *String* can be used instead of this object to specify the button text.
**Note:** *request_users* and *request_chat* options will only work in Telegram versions released after 3 February, 2023. Older clients will display *unsupported message*.
This object represents one button of the reply keyboard. At most one of the fields other than *text*, *icon_custom_emoji_id*, and *style* must be used to specify the type of the button. For simple text buttons, *String* can be used instead of this object to specify the button text.
Source: https://core.telegram.org/bots/api#keyboardbutton
"""
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"""
"""Text of the button. If none of the fields other than *text*, *icon_custom_emoji_id*, and *style* are used, it will be sent as a message when the button is pressed"""
icon_custom_emoji_id: str | None = None
"""*Optional*. Unique identifier of the custom emoji shown before the text of the button. Can only be used by bots that purchased additional usernames on `Fragment <https://fragment.com>`_ or in the messages directly sent by the bot to private, group and supergroup chats if the owner of the bot has a Telegram Premium subscription."""
style: str | None = None
"""*Optional*. Style of the button. Must be one of 'danger' (red), 'success' (green) or 'primary' (blue). If omitted, then an app-specific style is used."""
request_users: KeyboardButtonRequestUsers | None = None
"""*Optional*. If specified, pressing the button will open a list of suitable users. Identifiers of selected users will be sent to the bot in a 'users_shared' service message. Available in private chats only."""
request_chat: KeyboardButtonRequestChat | None = None
@ -52,6 +55,8 @@ class KeyboardButton(MutableTelegramObject):
__pydantic__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,
@ -67,6 +72,8 @@ class KeyboardButton(MutableTelegramObject):
super().__init__(
text=text,
icon_custom_emoji_id=icon_custom_emoji_id,
style=style,
request_users=request_users,
request_chat=request_chat,
request_contact=request_contact,

View file

@ -55,6 +55,8 @@ if TYPE_CHECKING:
from .chat_background import ChatBackground
from .chat_boost_added import ChatBoostAdded
from .chat_id_union import ChatIdUnion
from .chat_owner_changed import ChatOwnerChanged
from .chat_owner_left import ChatOwnerLeft
from .chat_shared import ChatShared
from .checklist import Checklist
from .checklist_tasks_added import ChecklistTasksAdded
@ -245,6 +247,10 @@ class Message(MaybeInaccessibleMessage):
"""*Optional*. New members that were added to the group or supergroup and information about them (the bot itself may be one of these members)"""
left_chat_member: User | None = None
"""*Optional*. A member was removed from the group, information about them (this member may be the bot itself)"""
chat_owner_left: ChatOwnerLeft | None = None
"""*Optional*. Service message: chat owner has left"""
chat_owner_changed: ChatOwnerChanged | None = None
"""*Optional*. Service message: chat owner has changed"""
new_chat_title: str | None = None
"""*Optional*. A chat title was changed to this value"""
new_chat_photo: list[PhotoSize] | None = None
@ -440,6 +446,8 @@ class Message(MaybeInaccessibleMessage):
location: Location | None = None,
new_chat_members: list[User] | None = None,
left_chat_member: User | None = None,
chat_owner_left: ChatOwnerLeft | None = None,
chat_owner_changed: ChatOwnerChanged | None = None,
new_chat_title: str | None = None,
new_chat_photo: list[PhotoSize] | None = None,
delete_chat_photo: bool | None = None,
@ -557,6 +565,8 @@ class Message(MaybeInaccessibleMessage):
location=location,
new_chat_members=new_chat_members,
left_chat_member=left_chat_member,
chat_owner_left=chat_owner_left,
chat_owner_changed=chat_owner_changed,
new_chat_title=new_chat_title,
new_chat_photo=new_chat_photo,
delete_chat_photo=delete_chat_photo,
@ -650,6 +660,10 @@ class Message(MaybeInaccessibleMessage):
return ContentType.NEW_CHAT_MEMBERS
if self.left_chat_member:
return ContentType.LEFT_CHAT_MEMBER
if self.chat_owner_left:
return ContentType.CHAT_OWNER_LEFT
if self.chat_owner_changed:
return ContentType.CHAT_OWNER_CHANGED
if self.invoice:
return ContentType.INVOICE
if self.successful_payment:

View file

@ -35,6 +35,8 @@ class UniqueGift(TelegramObject):
"""Backdrop of the gift"""
is_premium: bool | None = None
"""*Optional*. :code:`True`, if the original regular gift was exclusively purchaseable by Telegram Premium subscribers"""
is_burned: bool | None = None
"""*Optional*. :code:`True`, if the gift was used to craft another gift and isn't available anymore"""
is_from_blockchain: bool | None = None
"""*Optional*. :code:`True`, if the gift is assigned from the TON blockchain and can't be resold or transferred in Telegram"""
colors: UniqueGiftColors | None = None
@ -57,6 +59,7 @@ class UniqueGift(TelegramObject):
symbol: UniqueGiftSymbol,
backdrop: UniqueGiftBackdrop,
is_premium: bool | None = None,
is_burned: bool | None = None,
is_from_blockchain: bool | None = None,
colors: UniqueGiftColors | None = None,
publisher_chat: Chat | None = None,
@ -75,6 +78,7 @@ class UniqueGift(TelegramObject):
symbol=symbol,
backdrop=backdrop,
is_premium=is_premium,
is_burned=is_burned,
is_from_blockchain=is_from_blockchain,
colors=colors,
publisher_chat=publisher_chat,

View file

@ -20,7 +20,9 @@ class UniqueGiftModel(TelegramObject):
sticker: Sticker
"""The sticker that represents the unique gift"""
rarity_per_mille: int
"""The number of unique gifts that receive this model for every 1000 gifts upgraded"""
"""The number of unique gifts that receive this model for every 1000 gift upgrades. Always 0 for crafted gifts."""
rarity: str | None = None
"""*Optional*. Rarity of the model if it is a crafted model. Currently, can be 'uncommon', 'rare', 'epic', or 'legendary'."""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
@ -32,6 +34,7 @@ class UniqueGiftModel(TelegramObject):
name: str,
sticker: Sticker,
rarity_per_mille: int,
rarity: str | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
@ -39,5 +42,9 @@ class UniqueGiftModel(TelegramObject):
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(
name=name, sticker=sticker, rarity_per_mille=rarity_per_mille, **__pydantic_kwargs
name=name,
sticker=sticker,
rarity_per_mille=rarity_per_mille,
rarity=rarity,
**__pydantic_kwargs,
)

View file

@ -7,7 +7,7 @@ from ..utils.link import create_tg_link
from .base import TelegramObject
if TYPE_CHECKING:
from ..methods import GetUserProfilePhotos
from ..methods import GetUserProfileAudios, GetUserProfilePhotos
class User(TelegramObject):
@ -45,6 +45,8 @@ class User(TelegramObject):
"""*Optional*. :code:`True`, if the bot has a main Web App. Returned only in :class:`aiogram.methods.get_me.GetMe`."""
has_topics_enabled: bool | None = None
"""*Optional*. :code:`True`, if the bot has forum topic mode enabled in private chats. Returned only in :class:`aiogram.methods.get_me.GetMe`."""
allows_users_to_create_topics: bool | None = None
"""*Optional*. :code:`True`, if the bot allows users to create and delete topics in private chats. Returned only in :class:`aiogram.methods.get_me.GetMe`."""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
@ -67,6 +69,7 @@ class User(TelegramObject):
can_connect_to_business: bool | None = None,
has_main_web_app: bool | None = None,
has_topics_enabled: bool | None = None,
allows_users_to_create_topics: bool | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
@ -88,6 +91,7 @@ class User(TelegramObject):
can_connect_to_business=can_connect_to_business,
has_main_web_app=has_main_web_app,
has_topics_enabled=has_topics_enabled,
allows_users_to_create_topics=allows_users_to_create_topics,
**__pydantic_kwargs,
)
@ -142,3 +146,35 @@ class User(TelegramObject):
limit=limit,
**kwargs,
).as_(self._bot)
def get_profile_audios(
self,
offset: int | None = None,
limit: int | None = None,
**kwargs: Any,
) -> GetUserProfileAudios:
"""
Shortcut for method :class:`aiogram.methods.get_user_profile_audios.GetUserProfileAudios`
will automatically fill method attributes:
- :code:`user_id`
Use this method to get a list of profile audios for a user. Returns a :class:`aiogram.types.user_profile_audios.UserProfileAudios` object.
Source: https://core.telegram.org/bots/api#getuserprofileaudios
:param offset: Sequential number of the first audio to be returned. By default, all audios are returned.
:param limit: Limits the number of audios to be retrieved. Values between 1-100 are accepted. Defaults to 100.
:return: instance of method :class:`aiogram.methods.get_user_profile_audios.GetUserProfileAudios`
"""
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
from aiogram.methods import GetUserProfileAudios
return GetUserProfileAudios(
user_id=self.id,
offset=offset,
limit=limit,
**kwargs,
).as_(self._bot)

View file

@ -0,0 +1,34 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
if TYPE_CHECKING:
from .audio import Audio
class UserProfileAudios(TelegramObject):
"""
This object represents the audios displayed on a user's profile.
Source: https://core.telegram.org/bots/api#userprofileaudios
"""
total_count: int
"""Total number of profile audios for the target user"""
audios: list[Audio]
"""Requested profile audios"""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
# This section was auto-generated via `butcher`
def __init__(
__pydantic__self__, *, total_count: int, audios: list[Audio], **__pydantic_kwargs: Any
) -> None:
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(total_count=total_count, audios=audios, **__pydantic_kwargs)

View file

@ -7,6 +7,7 @@ from .base import TelegramObject
if TYPE_CHECKING:
from .photo_size import PhotoSize
from .video_quality import VideoQuality
class Video(TelegramObject):
@ -32,6 +33,8 @@ class Video(TelegramObject):
"""*Optional*. Available sizes of the cover of the video in the message"""
start_timestamp: datetime.datetime | None = None
"""*Optional*. Timestamp in seconds from which the video will play in the message"""
qualities: list[VideoQuality] | None = None
"""*Optional*. List of available qualities of the video"""
file_name: str | None = None
"""*Optional*. Original filename as defined by the sender"""
mime_type: str | None = None
@ -54,6 +57,7 @@ class Video(TelegramObject):
thumbnail: PhotoSize | None = None,
cover: list[PhotoSize] | None = None,
start_timestamp: datetime.datetime | None = None,
qualities: list[VideoQuality] | None = None,
file_name: str | None = None,
mime_type: str | None = None,
file_size: int | None = None,
@ -72,6 +76,7 @@ class Video(TelegramObject):
thumbnail=thumbnail,
cover=cover,
start_timestamp=start_timestamp,
qualities=qualities,
file_name=file_name,
mime_type=mime_type,
file_size=file_size,

View file

@ -0,0 +1,55 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
class VideoQuality(TelegramObject):
"""
This object represents a video file of a specific quality.
Source: https://core.telegram.org/bots/api#videoquality
"""
file_id: str
"""Identifier for this file, which can be used to download or reuse the file"""
file_unique_id: str
"""Unique identifier for this file, which is supposed to be the same over time and for different bots. Can't be used to download or reuse the file."""
width: int
"""Video width"""
height: int
"""Video height"""
codec: str
"""Codec that was used to encode the video, for example, 'h264', 'h265', or 'av01'"""
file_size: int | None = None
"""*Optional*. File size in bytes. It can be bigger than 2^31 and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a signed 64-bit integer or double-precision float type are safe for storing this value."""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
# This section was auto-generated via `butcher`
def __init__(
__pydantic__self__,
*,
file_id: str,
file_unique_id: str,
width: int,
height: int,
codec: str,
file_size: int | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
width=width,
height=height,
codec=codec,
file_size=file_size,
**__pydantic_kwargs,
)