Skip to content
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

bot API 7.10 #2395

Merged
merged 7 commits into from
Sep 18, 2024
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.</p>
<p align="center">Both synchronous and asynchronous.</p>

## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#august-14-2024"><img src="https://img.shields.io/badge/Bot%20API-7.9-blue?logo=telegram" alt="Supported Bot API version"></a>
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#september-6-2024"><img src="https://img.shields.io/badge/Bot%20API-7.10-blue?logo=telegram" alt="Supported Bot API version"></a>

<h2><a href='https://pytba.readthedocs.io/en/latest/index.html'>Official documentation</a></h2>
<h2><a href='https://pytba.readthedocs.io/ru/latest/index.html'>Official ru documentation</a></h2>
Expand Down
73 changes: 68 additions & 5 deletions telebot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ def __init__(
self.business_message_handlers = []
self.edited_business_message_handlers = []
self.deleted_business_messages_handlers = []
self.purchased_paid_media_handlers = []

self.custom_filters = {}
self.state_handlers = []
Expand Down Expand Up @@ -724,6 +725,7 @@ def process_new_updates(self, updates: List[types.Update]):
new_business_messages = None
new_edited_business_messages = None
new_deleted_business_messages = None
new_purchased_paid_media = None

for update in updates:
if apihelper.ENABLE_MIDDLEWARE and not self.use_class_middlewares:
Expand Down Expand Up @@ -805,8 +807,10 @@ def process_new_updates(self, updates: List[types.Update]):
if update.deleted_business_messages:
if new_deleted_business_messages is None: new_deleted_business_messages = []
new_deleted_business_messages.append(update.deleted_business_messages)


if update.purchased_paid_media:
if new_purchased_paid_media is None: new_purchased_paid_media = []
new_purchased_paid_media.append(update.purchased_paid_media)

if new_messages:
self.process_new_messages(new_messages)
if new_edited_messages:
Expand Down Expand Up @@ -851,6 +855,8 @@ def process_new_updates(self, updates: List[types.Update]):
self.process_new_edited_business_message(new_edited_business_messages)
if new_deleted_business_messages:
self.process_new_deleted_business_messages(new_deleted_business_messages)
if new_purchased_paid_media:
self.process_new_purchased_paid_media(new_purchased_paid_media)

def process_new_messages(self, new_messages):
"""
Expand Down Expand Up @@ -987,8 +993,11 @@ def process_new_deleted_business_messages(self, new_deleted_business_messages):
"""
self._notify_command_handlers(self.deleted_business_messages_handlers, new_deleted_business_messages, 'deleted_business_messages')



def process_new_purchased_paid_media(self, new_purchased_paid_media):
"""
:meta private:
"""
self._notify_command_handlers(self.purchased_paid_media_handlers, new_purchased_paid_media, 'purchased_paid_media')

def process_middlewares(self, update):
"""
Expand Down Expand Up @@ -3137,6 +3146,7 @@ def send_paid_media(
show_caption_above_media: Optional[bool]=None, disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None, reply_parameters: Optional[types.ReplyParameters]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None, business_connection_id: Optional[str]=None,
payload: Optional[str]=None
) -> types.Message:
"""
Use this method to send paid media to channel chats. On success, the sent Message is returned.
Expand Down Expand Up @@ -3179,6 +3189,9 @@ def send_paid_media(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`

:param payload: Bot-defined paid media payload, 0-128 bytes. This will not be displayed to the user, use it for your internal processes.
:type payload: :obj:`str`

:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
Expand All @@ -3187,7 +3200,8 @@ def send_paid_media(
self.token, chat_id, star_count, media, caption=caption, parse_mode=parse_mode,
caption_entities=caption_entities, show_caption_above_media=show_caption_above_media,
disable_notification=disable_notification, protect_content=protect_content,
reply_parameters=reply_parameters, reply_markup=reply_markup, business_connection_id=business_connection_id)
reply_parameters=reply_parameters, reply_markup=reply_markup, business_connection_id=business_connection_id,
payload=payload)
)


Expand Down Expand Up @@ -8035,6 +8049,55 @@ def register_pre_checkout_query_handler(self, callback: Callable, func: Callable
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
self.add_pre_checkout_query_handler(handler_dict)

def purchased_paid_media_handler(self, func=None, **kwargs):
"""
Handles new incoming purchased paid media.

:param func: Function executed as a filter
:type func: :obj:`function`

:param kwargs: Optional keyword arguments(custom filters)

:return: None
"""
def decorator(handler):
handler_dict = self._build_handler_dict(handler, func=func, **kwargs)
self.add_purchased_paid_media_handler(handler_dict)
return handler

return decorator

def add_purchased_paid_media_handler(self, handler_dict):
"""
Adds a purchased paid media handler
Note that you should use register_purchased_paid_media_handler to add purchased_paid_media_handler to the bot.

:meta private:

:param handler_dict:
:return:
"""
self.purchased_paid_media_handlers.append(handler_dict)

def register_purchased_paid_media_handler(self, callback: Callable, func: Callable, pass_bot: Optional[bool]=False, **kwargs):
"""
Registers purchased paid media handler.

:param callback: function to be called
:type callback: :obj:`function`

:param func: Function executed as a filter
:type func: :obj:`function`

:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool`

:param kwargs: Optional keyword arguments(custom filters)

:return: None
"""
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
self.add_purchased_paid_media_handler(handler_dict)

def poll_handler(self, func, **kwargs):
"""
Expand Down
26 changes: 14 additions & 12 deletions telebot/apihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,30 +530,32 @@ def send_paid_media(
token, chat_id, star_count, media,
caption=None, parse_mode=None, caption_entities=None, show_caption_above_media=None,
disable_notification=None, protect_content=None, reply_parameters=None, reply_markup=None,
business_connection_id=None):
business_connection_id=None, payload=None):
method_url = r'sendPaidMedia'
media_json, files = convert_input_media_array(media)
payload = {'chat_id': chat_id, 'star_count': star_count, 'media': media_json}
_payload = {'chat_id': chat_id, 'star_count': star_count, 'media': media_json}
if caption:
payload['caption'] = caption
_payload['caption'] = caption
if parse_mode:
payload['parse_mode'] = parse_mode
_payload['parse_mode'] = parse_mode
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
_payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if show_caption_above_media is not None:
payload['show_caption_above_media'] = show_caption_above_media
_payload['show_caption_above_media'] = show_caption_above_media
if disable_notification is not None:
payload['disable_notification'] = disable_notification
_payload['disable_notification'] = disable_notification
if protect_content is not None:
payload['protect_content'] = protect_content
_payload['protect_content'] = protect_content
if reply_parameters is not None:
payload['reply_parameters'] = reply_parameters.to_json()
_payload['reply_parameters'] = reply_parameters.to_json()
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
_payload['reply_markup'] = _convert_markup(reply_markup)
if business_connection_id:
payload['business_connection_id'] = business_connection_id
_payload['business_connection_id'] = business_connection_id
if payload:
_payload['payload'] = payload
return _make_request(
token, method_url, params=payload,
token, method_url, params=_payload,
method='post' if files else 'get',
files=files if files else None)

Expand Down
72 changes: 70 additions & 2 deletions telebot/async_telebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ def __init__(self, token: str, parse_mode: Optional[str]=None, offset: Optional[
self.business_message_handlers = []
self.edited_business_message_handlers = []
self.deleted_business_messages_handlers = []
self.purchased_paid_media_handlers = []

self.custom_filters = {}
self.state_handlers = []
Expand Down Expand Up @@ -636,6 +637,7 @@ async def process_new_updates(self, updates: List[types.Update]):
new_business_messages = None
new_edited_business_messages = None
new_deleted_business_messages = None
new_purchased_paid_media = None


for update in updates:
Expand Down Expand Up @@ -706,6 +708,9 @@ async def process_new_updates(self, updates: List[types.Update]):
if update.deleted_business_messages:
if new_deleted_business_messages is None: new_deleted_business_messages = []
new_deleted_business_messages.append(update.deleted_business_messages)
if update.purchased_paid_media:
if new_purchased_paid_media is None: new_purchased_paid_media = []
new_purchased_paid_media.append(update.purchased_paid_media)


if new_messages:
Expand Down Expand Up @@ -750,6 +755,8 @@ async def process_new_updates(self, updates: List[types.Update]):
await self.process_new_edited_business_message(new_edited_business_messages)
if new_deleted_business_messages:
await self.process_new_deleted_business_messages(new_deleted_business_messages)
if new_purchased_paid_media:
await self.process_new_purchased_paid_media(new_purchased_paid_media)

async def process_new_messages(self, new_messages):
"""
Expand Down Expand Up @@ -884,6 +891,12 @@ async def process_new_deleted_business_messages(self, new_deleted_business_messa
"""
await self._process_updates(self.deleted_business_messages_handlers, new_deleted_business_messages, 'deleted_business_messages')

async def process_new_purchased_paid_media(self, new_purchased_paid_media):
"""
:meta private:
"""
await self._process_updates(self.purchased_paid_media_handlers, new_purchased_paid_media, 'purchased_paid_media')

async def _get_middlewares(self, update_type):
"""
:meta private:
Expand Down Expand Up @@ -1867,6 +1880,56 @@ def register_pre_checkout_query_handler(self, callback: Callable[[Any], Awaitabl
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
self.add_pre_checkout_query_handler(handler_dict)

def purchased_paid_media_handler(self, func=None, **kwargs):
"""
Handles new incoming purchased paid media.

:param func: Function executed as a filter
:type func: :obj:`function`

:param kwargs: Optional keyword arguments(custom filters)

:return: None
"""
def decorator(handler):
handler_dict = self._build_handler_dict(handler, func=func, **kwargs)
self.add_purchased_paid_media_handler(handler_dict)
return handler

return decorator

def add_purchased_paid_media_handler(self, handler_dict):
"""
Adds a purchased paid media handler
Note that you should use register_purchased_paid_media_handler to add purchased_paid_media_handler to the bot.

:meta private:

:param handler_dict:
:return:
"""
self.purchased_paid_media_handlers.append(handler_dict)

def register_purchased_paid_media_handler(self, callback: Callable, func: Callable, pass_bot: Optional[bool]=False, **kwargs):
"""
Registers purchased paid media handler.

:param callback: function to be called
:type callback: :obj:`function`

:param func: Function executed as a filter
:type func: :obj:`function`

:param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files)
:type pass_bot: :obj:`bool`

:param kwargs: Optional keyword arguments(custom filters)

:return: None
"""
handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs)
self.add_purchased_paid_media_handler(handler_dict)

def poll_handler(self, func, **kwargs):
"""
Handles new state of a poll. Bots receive only updates about stopped polls and polls, which are sent by the bot
Expand Down Expand Up @@ -4564,7 +4627,8 @@ async def send_paid_media(
caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None,
show_caption_above_media: Optional[bool]=None, disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None, reply_parameters: Optional[types.ReplyParameters]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None, business_connection_id: Optional[str]=None) -> types.Message:
reply_markup: Optional[REPLY_MARKUP_TYPES]=None, business_connection_id: Optional[str]=None,
payload: Optional[str]=None) -> types.Message:
"""
Use this method to send paid media to channel chats. On success, the sent Message is returned.

Expand Down Expand Up @@ -4606,6 +4670,9 @@ async def send_paid_media(
:param business_connection_id: Identifier of a business connection, in which the message will be sent
:type business_connection_id: :obj:`str`

:param payload: Bot-defined paid media payload, 0-128 bytes. This will not be displayed to the user, use it for your internal processes.
:type payload: :obj:`str`

:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
Expand All @@ -4614,7 +4681,8 @@ async def send_paid_media(
self.token, chat_id, star_count, media, caption=caption, parse_mode=parse_mode,
caption_entities=caption_entities, show_caption_above_media=show_caption_above_media,
disable_notification=disable_notification, protect_content=protect_content,
reply_parameters=reply_parameters, reply_markup=reply_markup, business_connection_id=business_connection_id))
reply_parameters=reply_parameters, reply_markup=reply_markup, business_connection_id=business_connection_id,
payload=payload))

async def send_media_group(
self, chat_id: Union[int, str],
Expand Down
28 changes: 16 additions & 12 deletions telebot/asyncio_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,30 +520,34 @@ async def send_paid_media(
token, chat_id, star_count, media,
caption=None, parse_mode=None, caption_entities=None, show_caption_above_media=None,
disable_notification=None, protect_content=None, reply_parameters=None, reply_markup=None,
business_connection_id=None):
business_connection_id=None, payload=None):
method_url = r'sendPaidMedia'
media_json, files = convert_input_media_array(media)
payload = {'chat_id': chat_id, 'star_count': star_count, 'media': media_json}
_payload = {'chat_id': chat_id, 'star_count': star_count, 'media': media_json}
# USE _payload for request payload
if caption:
payload['caption'] = caption
_payload['caption'] = caption
if parse_mode:
payload['parse_mode'] = parse_mode
_payload['parse_mode'] = parse_mode
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
_payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if show_caption_above_media is not None:
payload['show_caption_above_media'] = show_caption_above_media
_payload['show_caption_above_media'] = show_caption_above_media
if disable_notification is not None:
payload['disable_notification'] = disable_notification
_payload['disable_notification'] = disable_notification
if protect_content is not None:
payload['protect_content'] = protect_content
_payload['protect_content'] = protect_content
if reply_parameters is not None:
payload['reply_parameters'] = reply_parameters.to_json()
_payload['reply_parameters'] = reply_parameters.to_json()
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
_payload['reply_markup'] = _convert_markup(reply_markup)
if business_connection_id:
payload['business_connection_id'] = business_connection_id
_payload['business_connection_id'] = business_connection_id
if payload:
_payload['payload'] = payload

return await _process_request(
token, method_url, params=payload,
token, method_url, params=_payload,
method='post' if files else 'get',
files=files if files else None)

Expand Down
Loading
Loading