Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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#february-9-2026"><img src="https://img.shields.io/badge/Bot%20API-9.4-blue?logo=telegram" alt="Supported Bot API version"></a>
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#march-1-2026"><img src="https://img.shields.io/badge/Bot%20API-9.5-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
12 changes: 12 additions & 0 deletions examples/asynchronous_telebot/chat_member_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,17 @@ async def my_chat_m(message: types.ChatMemberUpdated):
@bot.message_handler(content_types=util.content_type_service)
async def delall(message: types.Message):
await bot.delete_message(message.chat.id,message.message_id)


@bot.message_handler(commands=['set_tag'])
async def set_tag(message: types.Message):
tag = util.extract_arguments(message.text)
if not tag:
await bot.reply_to(message, "Usage: /set_tag your_tag")
return
await bot.set_chat_member_tag(message.chat.id, message.from_user.id, tag=tag)
await bot.reply_to(message, f"Tag updated: {tag}")


import asyncio
asyncio.run(bot.polling(allowed_updates=util.update_types))
21 changes: 19 additions & 2 deletions examples/asynchronous_telebot/formatting_example.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from telebot.async_telebot import AsyncTeleBot
from telebot import formatting
from telebot import formatting, types

bot = AsyncTeleBot('token')

Expand Down Expand Up @@ -50,5 +50,22 @@ async def start_message(message):
parse_mode='HTML'
)

# Bot API 9.5: date_time entity example
date_text = "2026-03-01 12:00:00"
text = f"Local time: {date_text}"
await bot.send_message(
message.chat.id,
text,
entities=[
types.MessageEntity(
type='date_time',
offset=len("Local time: "),
length=len(date_text),
unix_time=1772366400,
date_time_format='short'
)
]
)

import asyncio
asyncio.run(bot.polling())
asyncio.run(bot.polling())
22 changes: 22 additions & 0 deletions examples/asynchronous_telebot/send_message_draft_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import asyncio

from telebot.async_telebot import AsyncTeleBot

bot = AsyncTeleBot("TOKEN")


@bot.message_handler(commands=['draft'])
async def send_draft(message):
if message.chat.type != 'private':
await bot.reply_to(message, "This example works in private chats.")
return

draft_id = message.from_user.id
await bot.send_message_draft(message.chat.id, draft_id, "Generating response...")
await asyncio.sleep(1)
await bot.send_message_draft(message.chat.id, draft_id, "Still working...")
await asyncio.sleep(1)
await bot.send_message(message.chat.id, "Done.")


asyncio.run(bot.polling())
12 changes: 12 additions & 0 deletions examples/chat_member_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@ def my_chat_m(message: types.ChatMemberUpdated):
@bot.message_handler(content_types=util.content_type_service)
def delall(message: types.Message):
bot.delete_message(message.chat.id,message.message_id)


@bot.message_handler(commands=['set_tag'])
def set_tag(message: types.Message):
tag = util.extract_arguments(message.text)
if not tag:
bot.reply_to(message, "Usage: /set_tag your_tag")
return
bot.set_chat_member_tag(message.chat.id, message.from_user.id, tag=tag)
bot.reply_to(message, f"Tag updated: {tag}")


bot.infinity_polling(allowed_updates=util.update_types)
21 changes: 19 additions & 2 deletions examples/formatting_example.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from telebot import TeleBot
from telebot import formatting
from telebot import formatting, types

bot = TeleBot('TOKEN')

Expand Down Expand Up @@ -50,4 +50,21 @@ def start_message(message):
parse_mode='HTML'
)

bot.infinity_polling()
# Bot API 9.5: date_time entity example
date_text = "2026-03-01 12:00:00"
text = f"Local time: {date_text}"
bot.send_message(
message.chat.id,
text,
entities=[
types.MessageEntity(
type='date_time',
offset=len("Local time: "),
length=len(date_text),
unix_time=1772366400,
date_time_format='short'
)
]
)

bot.infinity_polling()
22 changes: 22 additions & 0 deletions examples/send_message_draft_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import time

import telebot

bot = telebot.TeleBot("TOKEN")


@bot.message_handler(commands=['draft'])
def send_draft(message):
if message.chat.type != 'private':
bot.reply_to(message, "This example works in private chats.")
return

draft_id = message.from_user.id
bot.send_message_draft(message.chat.id, draft_id, "Generating response...")
time.sleep(1)
bot.send_message_draft(message.chat.id, draft_id, "Still working...")
time.sleep(1)
bot.send_message(message.chat.id, "Done.")


bot.infinity_polling()
33 changes: 31 additions & 2 deletions telebot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4237,7 +4237,7 @@ def send_message_draft(
entities: Optional[List[types.MessageEntity]]=None):
"""
Use this method to stream a partial message to a user while the message is being generated;
supported only for bots with forum topic mode enabled. Returns True on success.
available for all bots. Returns True on success.

Telegram documentation: https://core.telegram.org/bots/api#sendmessagedraft

Expand Down Expand Up @@ -4487,7 +4487,8 @@ def promote_chat_member(
can_post_stories: Optional[bool]=None,
can_edit_stories: Optional[bool]=None,
can_delete_stories: Optional[bool]=None,
can_manage_direct_messages: Optional[bool]=None) -> bool:
can_manage_direct_messages: Optional[bool]=None,
can_manage_tags: Optional[bool]=None) -> bool:
"""
Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator
in the chat for this to work and must have the appropriate admin rights.
Expand Down Expand Up @@ -4561,6 +4562,9 @@ def promote_chat_member(
within the channel and decline suggested posts; for channels only
:type can_manage_direct_messages: :obj:`bool`

:param can_manage_tags: Pass True if the administrator can manage tags in the chat
:type can_manage_tags: :obj:`bool`

:return: True on success.
:rtype: :obj:`bool`
"""
Expand All @@ -4578,6 +4582,7 @@ def promote_chat_member(
can_manage_video_chats=can_manage_video_chats, can_manage_topics=can_manage_topics,
can_post_stories=can_post_stories, can_edit_stories=can_edit_stories,
can_delete_stories=can_delete_stories, can_manage_direct_messages=can_manage_direct_messages,
can_manage_tags=can_manage_tags,
)


Expand Down Expand Up @@ -4606,6 +4611,30 @@ def set_chat_administrator_custom_title(
return apihelper.set_chat_administrator_custom_title(self.token, chat_id, user_id, custom_title)


def set_chat_member_tag(
self, chat_id: Union[int, str], user_id: int, tag: Optional[str]=None) -> bool:
"""
Use this method to set a new tag for a member in a chat.
Returns True on success.

Telegram documentation: https://core.telegram.org/bots/api#setchatmembertag

:param chat_id: Unique identifier for the target chat or username of the target supergroup
(in the format @supergroupusername)
:type chat_id: :obj:`int` or :obj:`str`

:param user_id: Unique identifier of the target user
:type user_id: :obj:`int`

:param tag: New tag for the member; pass an empty string to remove the tag
:type tag: :obj:`str`

:return: True on success.
:rtype: :obj:`bool`
"""
return apihelper.set_chat_member_tag(self.token, chat_id, user_id, tag)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Better pass optional parameters using parameter names; tag=tag



def ban_chat_sender_chat(self, chat_id: Union[int, str], sender_chat_id: Union[int, str]) -> bool:
"""
Use this method to ban a channel chat in a supergroup or a channel.
Expand Down
12 changes: 11 additions & 1 deletion telebot/apihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,7 @@ def promote_chat_member(
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None,
can_manage_topics=None, can_post_stories=None, can_edit_stories=None,
can_delete_stories=None, can_manage_direct_messages=None):
can_delete_stories=None, can_manage_direct_messages=None, can_manage_tags=None):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info is not None:
Expand Down Expand Up @@ -1322,6 +1322,8 @@ def promote_chat_member(
payload['can_delete_stories'] = can_delete_stories
if can_manage_direct_messages is not None:
payload['can_manage_direct_messages'] = can_manage_direct_messages
if can_manage_tags is not None:
payload['can_manage_tags'] = can_manage_tags
return _make_request(token, method_url, params=payload, method='post')


Expand All @@ -1333,6 +1335,14 @@ def set_chat_administrator_custom_title(token, chat_id, user_id, custom_title):
return _make_request(token, method_url, params=payload, method='post')


def set_chat_member_tag(token, chat_id, user_id, tag=None):
method_url = 'setChatMemberTag'
payload = {'chat_id': chat_id, 'user_id': user_id}
if tag is not None:
payload['tag'] = tag
return _make_request(token, method_url, params=payload, method='post')


def ban_chat_sender_chat(token, chat_id, sender_chat_id):
method_url = 'banChatSenderChat'
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
Expand Down
35 changes: 32 additions & 3 deletions telebot/async_telebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5757,7 +5757,7 @@ async def send_message_draft(
entities: Optional[List[types.MessageEntity]]=None):
"""
Use this method to stream a partial message to a user while the message is being generated;
supported only for bots with forum topic mode enabled. Returns True on success.
available for all bots. Returns True on success.

Telegram documentation: https://core.telegram.org/bots/api#sendmessagedraft

Expand Down Expand Up @@ -5996,7 +5996,8 @@ async def promote_chat_member(
can_post_stories: Optional[bool]=None,
can_edit_stories: Optional[bool]=None,
can_delete_stories: Optional[bool]=None,
can_manage_direct_messages: Optional[bool]=None) -> bool:
can_manage_direct_messages: Optional[bool]=None,
can_manage_tags: Optional[bool]=None) -> bool:
"""
Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator
in the chat for this to work and must have the appropriate admin rights.
Expand Down Expand Up @@ -6070,6 +6071,9 @@ async def promote_chat_member(
within the channel and decline suggested posts; for channels only
:type can_manage_direct_messages: :obj:`bool`

:param can_manage_tags: Pass True if the administrator can manage tags in the chat
:type can_manage_tags: :obj:`bool`

:return: True on success.
:rtype: :obj:`bool`
"""
Expand All @@ -6084,7 +6088,8 @@ async def promote_chat_member(
can_edit_messages, can_delete_messages, can_invite_users,
can_restrict_members, can_pin_messages, can_promote_members,
is_anonymous, can_manage_chat, can_manage_video_chats, can_manage_topics,
can_post_stories, can_edit_stories, can_delete_stories, can_manage_direct_messages=can_manage_direct_messages
can_post_stories, can_edit_stories, can_delete_stories,
can_manage_direct_messages=can_manage_direct_messages, can_manage_tags=can_manage_tags
)

async def set_chat_administrator_custom_title(
Expand Down Expand Up @@ -6112,6 +6117,30 @@ async def set_chat_administrator_custom_title(
return await asyncio_helper.set_chat_administrator_custom_title(self.token, chat_id, user_id, custom_title)


async def set_chat_member_tag(
self, chat_id: Union[int, str], user_id: int, tag: Optional[str]=None) -> bool:
"""
Use this method to set a new tag for a member in a chat.
Returns True on success.

Telegram documentation: https://core.telegram.org/bots/api#setchatmembertag

:param chat_id: Unique identifier for the target chat or username of the target supergroup
(in the format @supergroupusername)
:type chat_id: :obj:`int` or :obj:`str`

:param user_id: Unique identifier of the target user
:type user_id: :obj:`int`

:param tag: New tag for the member; pass an empty string to remove the tag
:type tag: :obj:`str`

:return: True on success.
:rtype: :obj:`bool`
"""
return await asyncio_helper.set_chat_member_tag(self.token, chat_id, user_id, tag)


async def ban_chat_sender_chat(self, chat_id: Union[int, str], sender_chat_id: Union[int, str]) -> bool:
"""
Use this method to ban a channel chat in a supergroup or a channel.
Expand Down
12 changes: 11 additions & 1 deletion telebot/asyncio_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1281,7 +1281,7 @@ async def promote_chat_member(
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None, can_manage_topics=None,
can_post_stories=None, can_edit_stories=None, can_delete_stories=None,
can_manage_direct_messages=None):
can_manage_direct_messages=None, can_manage_tags=None):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info is not None:
Expand Down Expand Up @@ -1316,6 +1316,8 @@ async def promote_chat_member(
payload['can_delete_stories'] = can_delete_stories
if can_manage_direct_messages is not None:
payload['can_manage_direct_messages'] = can_manage_direct_messages
if can_manage_tags is not None:
payload['can_manage_tags'] = can_manage_tags
return await _process_request(token, method_url, params=payload, method='post')


Expand All @@ -1327,6 +1329,14 @@ async def set_chat_administrator_custom_title(token, chat_id, user_id, custom_ti
return await _process_request(token, method_url, params=payload, method='post')


async def set_chat_member_tag(token, chat_id, user_id, tag=None):
method_url = 'setChatMemberTag'
payload = {'chat_id': chat_id, 'user_id': user_id}
if tag is not None:
payload['tag'] = tag
return await _process_request(token, method_url, params=payload, method='post')


async def ban_chat_sender_chat(token, chat_id, sender_chat_id):
method_url = 'banChatSenderChat'
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
Expand Down
Loading