8000 API 9.1 General by harshil21 · Pull Request #4851 · python-telegram-bot/python-telegram-bot · GitHub
[go: up one dir, main page]

Skip to content

API 9.1 General #4851

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 5, 2025
Merged
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
5 changes: 5 additions & 0 deletions changes/unreleased/4851.jGu7ZujzXWWGJATTXGxn4u.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
other = "API 9.1 General"
[[pull_requests]]
uid = "4851"
author_uid = "harshil21"
closes_threads = []
2 changes: 2 additions & 0 deletions docs/source/inclusions/bot_methods.rst
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@
- Used to generate an HTTP link for an invoice
* - :meth:`~telegram.Bot.edit_user_star_subscription`
- Used for editing a user's star subscription
* - :meth:`~telegram.Bot.get_my_star_balance`
- Used for obtaining the bot's Telegram Stars balance
* - :meth:`~telegram.Bot.get_star_transactions`
- Used for obtaining the bot's Telegram Stars transactions
* - :meth:`~telegram.Bot.refund_star_payment`
Expand Down
1 change: 1 addition & 0 deletions docs/source/telegram.at-tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Available Types
telegram.chatshared
telegram.contact
telegram.dice
telegram.directmessagepricechanged
telegram.document
telegram.externalreplyinfo
telegram.file
Expand Down
6 changes: 6 additions & 0 deletions docs/source/telegram.directmessagepricechanged.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DirectMessagePriceChanged
=========================

.. autoclass:: telegram.DirectMessagePriceChanged
:members:
:show-inheritance:
2 changes: 2 additions & 0 deletions src/telegram/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"Credentials",
"DataCredentials",
"Dice",
"DirectMessagePriceChanged",
"Document",
"EncryptedCredentials",
"EncryptedPassportElement",
Expand Down Expand Up @@ -386,6 +387,7 @@
from ._choseninlineresult import ChosenInlineResult
from ._copytextbutton import CopyTextButton
from ._dice import Dice
from ._directmessagepricechanged import DirectMessagePriceChanged
from ._files._inputstorycontent import (
InputStoryContent,
InputStoryContentPhoto,
Expand Down
32 changes: 32 additions & 0 deletions src/telegram/_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11072,6 +11072,36 @@ async def remove_user_verification(
api_kwargs=api_kwargs,
)

async def get_my_star_balance(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> StarAmount:
"""A method to get the current Telegram Stars balance of the bot. Requires no parameters.

.. versionadded:: NEXT.VERSION

Returns:
:class:`telegram.StarAmount`

Raises:
:class:`telegram.error.TelegramError`
"""
return StarAmount.de_json(
await self._post(
"getMyStarBalance",
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
)

def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
"""See :meth:`telegram.TelegramObject.to_dict`."""
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
Expand Down Expand Up @@ -11386,3 +11416,5 @@ def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
"""Alias for :meth:`remove_chat_verification`"""
removeUserVerification = remove_user_verification
"""Alias for :meth:`remove_user_verification`"""
getMyStarBalance = get_my_star_balance
"""Alias for :meth:`get_my_star_balance`"""
73 changes: 73 additions & 0 deletions src/telegram/_directmessagepricechanged.py
1E0A
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2025
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Direct Message Price."""


from typing import Optional

from telegram._telegramobject import TelegramObject
from telegram._utils.types import JSONDict


class DirectMessagePriceChanged(TelegramObject):
"""
Describes a service message about a change in the price of direct messages sent to a channel
chat.

.. versionadded:: NEXT.VERSION

Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`are_direct_messages_enabled`, and
:attr:`direct_message_star_count` are equal.

Args:
are_direct_messages_enabled (:obj:`bool`):
:obj:`True`, if direct messages are enabled for the channel chat; :obj:`False`
otherwise.
direct_message_star_count (:obj:`int`, optional):
The new number of Telegram Stars that must be paid by users for each direct message
sent to the channel. Does not apply to users who have been exempted by administrators.
Defaults to ``0``.

Attributes:
are_direct_messages_enabled (:obj:`bool`):
:obj:`True`, if direct messages are enabled for the channel chat; :obj:`False`
otherwise.
direct_message_star_count (:obj:`int`):
Optional. The new number of Telegram Stars that must be paid by users for each direct
message sent to the channel. Does not apply to users who have been exempted by
administrators. Defaults to ``0``.
"""

__slots__ = ("are_direct_messages_enabled", "direct_message_star_count")

def __init__(
self,
are_direct_messages_enabled: bool,
direct_message_star_count: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.are_direct_messages_enabled: bool = are_direct_messages_enabled
self.direct_message_star_count: Optional[int] = direct_message_star_count

self._id_attrs = (self.are_direct_messages_enabled, self.direct_message_star_count)

self._freeze()
19 changes: 19 additions & 0 deletions src/telegram/_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from telegram._chatbackground import ChatBackground
from telegram._chatboost import ChatBoostAdded
from telegram._dice import Dice
from telegram._directmessagepricechanged import DirectMessagePriceChanged
from telegram._files.animation import Animation
from telegram._files.audio import Audio
from telegram._files.contact import Contact
Expand Down Expand Up @@ -609,6 +610,11 @@ class Message(MaybeInaccessibleMessage):
message about a refunded payment, information about the payment.

.. versionadded:: 21.4
direct_message_price_changed (:class:`telegram.DirectMessagePriceChanged`, optional):
Service message: the price for paid messages in the corresponding direct messages chat
of a channel has changed.

.. versionadded:: NEXT.VERSION

Attributes:
message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances
Expand Down Expand Up @@ -954,6 +960,11 @@ class Message(MaybeInaccessibleMessage):
message about a refunded payment, information about the payment.

.. versionadded:: 21.4
direct_message_price_changed (:class:`telegram.DirectMessagePriceChanged`):
Optional. Service message: the price for paid messages in the corresponding direct
messages chat of a channel has changed.

.. versionadded:: NEXT.VERSION

.. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
Expand Down Expand Up @@ -987,6 +998,7 @@ class Message(MaybeInaccessibleMessage):
"contact",
"delete_chat_photo",
"dice",
"direct_message_price_changed",
"document",
"edit_date",
"effect_id",
Expand Down Expand Up @@ -1152,6 +1164,7 @@ def __init__(
unique_gift: Optional[UniqueGiftInfo] = None,
paid_message_price_changed: Optional[PaidMessagePriceChanged] = None,
paid_star_count: Optional[int] = None,
direct_message_price_changed: Optional[DirectMessagePriceChanged] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
Expand Down Expand Up @@ -1261,6 +1274,9 @@ def __init__(
paid_message_price_changed
)
self.paid_star_count: Optional[int] = paid_star_count
self.direct_message_price_changed: Optional[DirectMessagePriceChanged] = (
direct_message_price_changed
)

self._effective_attachment = DEFAULT_NONE

Expand Down Expand Up @@ -1437,6 +1453,9 @@ def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "Message":
data["reply_to_story"] = de_json_optional(data.get("reply_to_story"), Story, bot)
data["boost_added"] = de_json_optional(data.get("boost_added"), ChatBoostAdded, bot)
data["sender_business_bot"] = de_json_optional(data.get("sender_business_bot"), User, bot)
data["direct_message_price_changed"] = de_json_optional(
data.get("direct_message_price_changed"), DirectMessagePriceChanged, bot
)

api_kwargs = {}
# This is a deprecated field that TG still returns for backwards compatibility
Expand Down
10 changes: 9 additions & 1 deletion src/telegram/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2064,6 +2064,11 @@ class MessageType(StringEnum):
""":obj:`str`: Messages with :attr:`telegram.Message.delete_chat_photo`."""
DICE = "dice"
""":obj:`str`: Messages with :attr:`telegram.Message.dice`."""
DIRECT_MESSAGE_PRICE_CHANGED = "direct_message_price_changed"
""":obj:`str`: Messages with :attr:`telegram.Message.direct_message_price_changed`.

.. versionadded:: NEXT.VERSION
"""
DOCUMENT = "document"
""":obj:`str`: Messages with :attr:`telegram.Message.document`."""
EFFECT_ID = "effect_id"
Expand Down Expand Up @@ -3153,10 +3158,13 @@ class PollLimit(IntEnum):
to the :paramref:`~telegram.Bot.send_poll.options` parameter of
:meth:`telegram.Bot.send_poll`.
"""
MAX_OPTION_NUMBER = 10
MAX_OPTION_NUMBER = 12
""":obj:`int`: Maximum number of strings passed in a :obj:`list`
to the :paramref:`~telegram.Bot.send_poll.options` parameter of
:meth:`telegram.Bot.send_poll`.

.. versionchanged:: NEXT.VERSION
This value was changed from ``10`` to ``12`` in accordance to Bot API 9.1.
"""
MAX_EXPLANATION_LENGTH = 200
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as the
Expand Down
19 changes: 19 additions & 0 deletions src/telegram/ext/_extbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5057,6 +5057,24 @@ async def remove_user_verification(
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)

async def get_my_star_balance(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
rate_limit_args: Optional[RLARGS] = None,
) -> StarAmount:
return await super().get_my_star_balance(
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)

# updated camelCase aliases
getMe = get_me
sendMessage = send_message
Expand Down Expand Up @@ -5210,3 +5228,4 @@ async def remove_user_verification(
verifyUser = verify_user
removeChatVerification = remove_chat_verification
removeUserVerification = remove_user_verification
getMyStarBalance = get_my_star_balance
15 changes: 15 additions & 0 deletions src/telegram/ext/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1947,6 +1947,7 @@ def filter(self, update: Update) -> bool:
or StatusUpdate.VIDEO_CHAT_STARTED.check_update(update)
or StatusUpdate.WEB_APP_DATA.check_update(update)
or StatusUpdate.WRITE_ACCESS_ALLOWED.check_update(update)
or StatusUpdate.DIRECT_MESSAGE_PRICE_CHANGED.check_update(update)
)

ALL = _All(name="filters.StatusUpdate.ALL")
Expand Down Expand Up @@ -1997,6 +1998,20 @@ def filter(self, message: Message) -> bool:
CONNECTED_WEBSITE = _ConnectedWebsite(name="filters.StatusUpdate.CONNECTED_WEBSITE")
"""Messages that contain :attr:`telegram.Message.connected_website`."""

class _DirectMessagePriceChanged(MessageFilter):
__slots__ = ()

def filter(self, message: Message) -> bool:
return bool(message.direct_message_price_changed)

DIRECT_MESSAGE_PRICE_CHANGED = _DirectMessagePriceChanged(
name="filters.StatusUpdate.DIRECT_MESSAGE_PRICE_CHANGED"
)
"""Messages that contain :attr:`telegram.Message.direct_message_price_changed`.

.. versionadded:: NEXT.VERSION
"""

class _DeleteChatPhoto(MessageFilter):
__slots__ = ()

Expand Down
7 changes: 6 additions & 1 deletion tests/ext/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,12 @@ def test_filters_status_update(self, update):
assert filters.StatusUpdate.PAID_MESSAGE_PRICE_CHANGED.check_update(update)
update.message.paid_message_price_changed = None

def test_filters_forwarded(self, update, message_origin_user):
update.message.direct_message_price_changed = "direct_message_price_changed"
assert filters.StatusUpdate.ALL.check_update(update)
assert filters.StatusUpdate.DIRECT_MESSAGE_PRICE_CHANGED.check_update(update)
update.message.direct_message_price_changed = None

def test_filters_forwarded(self, update):
assert filters.FORWARDED.check_update(update)
update.message.forward_origin = MessageOriginHiddenUser(dtm.datetime.utcnow(), 1)
assert filters.FORWARDED.check_update(update)
Expand Down
17 changes: 17 additions & 0 deletions tests/test_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
User,
WebAppInfo,
)
from telegram._payment.stars.staramount import StarAmount
from telegram._utils.datetime import UTC, from_timestamp, localize, to_timestamp
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.strings import to_camel_case
Expand Down Expand Up @@ -2574,6 +2575,17 @@ async def make_assertion(url, request_data: RequestData, *args, **kwargs):

await offline_bot.remove_chat_verification(1234)

async def test_get_my_star_balance(self, offline_bot, monkeypatch):
sa = StarAmount(1000).to_json()

async def do_request(url, request_data: RequestData, *args, **kwargs):
assert not request_data.parameters
return 200, f'{{"ok": true, "result": {sa}}}'.encode()

monkeypatch.setattr(offline_bot.request, "do_request", do_request)
obj = await offline_bot.get_my_star_balance()
assert isinstance(obj, StarAmount)


class TestBotWithRequest:
"""
Expand Down Expand Up @@ -4540,3 +4552,8 @@ async def test_create_edit_chat_subscription_link(
assert edited_link.name == "sub_name_2"
assert sub_link.subscription_period == 2592000
assert sub_link.subscription_price == 13

async def test_get_my_star_balance(self, bot):
balance = await bot.get_my_star_balance()
assert isinstance(balance, StarAmount)
assert balance.amount == 0
Loading
Loading
0