Compare commits

...

28 Commits

Author SHA1 Message Date
_run fb7d60f09d
Merge pull request #1913 from coder2020official/botapi6.5
Fix #1912
2023-02-09 19:49:17 +04:00
coder2020official 8dc4e77287 Update asyncio_helper.py 2023-02-09 19:27:05 +04:00
Badiboy a999161384
Merge pull request #1911 from Badiboy/master
restrict_chat_member fix
2023-02-09 17:58:28 +03:00
Badiboy b4196f5891 restrict_chat_member fix 2023-02-09 17:56:10 +03:00
Badiboy e55fe962ca
Merge pull request #1906 from Badiboy/master
Bump version to 4.10.0
2023-02-05 13:14:08 +03:00
Badiboy 3d2c5c9590 Bump version to 4.10.0 2023-02-05 13:11:07 +03:00
_run 40567570e8
Merge pull request #1902 from coder2020official/botapi6.5
Bot API 6.5 update 🔥
2023-02-05 13:07:47 +04:00
coder2020official 4179e502c3 Fix description 2023-02-05 11:13:31 +04:00
coder2020official a9b878107c Fix can_send_media_messages param, added warnings 2023-02-04 22:24:26 +04:00
coder2020official 2094120ec7 Added user_chat_id to ChatJoinRequest; And, i corrected typehints 2023-02-04 20:07:01 +04:00
coder2020official d1348606e3 Added use_independent_chat_permissions to setchatpermissions 2023-02-04 20:04:07 +04:00
coder2020official d0d03d0c09 Added use_independent_chat_permissions for restrictchatmember 2023-02-04 19:59:49 +04:00
Badiboy fdd82a5e4b
Merge pull request #1894 from Muhammad-Aadil/master
Added poll_example.py in the examples
2023-02-04 18:46:39 +03:00
coder2020official 9e68f76f5d Replaced the fields can_send_media_messages in the classes ChatMemberRestricted and ChatPermissions with separate fields can_send_audios, can_send_documents, can_send_photos, can_send_videos, can_send_video_notes, and can_send_voice_notes for different media types. 2023-02-04 18:57:06 +04:00
coder2020official 4000c9fb48 Added chat_shared and chatshared 2023-02-04 16:58:48 +04:00
coder2020official ae42d0b1fe Added usershared and user_shared 2023-02-04 16:54:43 +04:00
coder2020official a3891ff363 Pep 0563 proposed change
https://peps.python.org/pep-0563/
2023-02-04 16:29:48 +04:00
coder2020official 4d7f5310fb Added the class KeyboardButtonRequestChat and the field request_chat to the class KeyboardButton. 2023-02-04 16:24:05 +04:00
_run 3e0d69f7f4
fixed checks x1 2023-02-04 16:16:34 +04:00
coder2020official 2e5fb10430 Added the class KeyboardButtonRequestUser and the field request_user to the class KeyboardButton. 2023-02-04 16:02:18 +04:00
_run c39c050abf
Update README.md 2023-02-04 15:32:55 +04:00
Muhammad Aadil ed6d6cc03f add poll answer handler to poll_example.py to show the example to send next poll or log user answers 2023-02-04 11:22:49 +05:00
Muhammad Aadil 10a80e1cfa add only quiz type poll example to the poll_example.py 2023-02-04 10:27:29 +05:00
Badiboy d99f48f975
Merge pull request #1893 from artyl/master
RuntimeError("cannot join current thread")
2023-01-31 20:52:59 +03:00
_run dae2790c61
Merge pull request #1898 from Badiboy/master
Async allowed_updates fix
2023-01-31 20:59:35 +04:00
Badiboy f5eac56afa Async allowed_updates fix 2023-01-31 11:19:11 +03:00
Muhammad Aadil ad7e4bbaf7 Added poll_example.py in the examples 2023-01-28 18:20:58 +05:00
Artem Lavrenov b9bedef73f Avoid raise RuntimeError(cannot join current thread) 2023-01-28 12:26:25 +03:00
10 changed files with 453 additions and 104 deletions

View File

@ -11,7 +11,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#december-30-2022">6.4</a>!
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#february-3-2023">6.5</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>

View File

@ -22,7 +22,7 @@ copyright = '2022, coder2020official'
author = 'coder2020official'
# The full version, including alpha/beta/rc tags
release = '4.9.0'
release = '4.10.0'
# -- General configuration ---------------------------------------------------

32
examples/poll_example.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/python
# This is an example file to create quiz polls
import telebot
API_TOKEN = "<api_token>"
bot = telebot.TeleBot(API_TOKEN)
@bot.message_handler(commands=["poll"])
def create_poll(message):
bot.send_message(message.chat.id, "English Article Test")
answer_options = ["a", "an", "the", "-"]
bot.send_poll(
chat_id=message.chat.id,
question="We are going to '' park.",
options=answer_options,
type="quiz",
correct_option_id=2,
is_anonymous=False,
)
@bot.poll_answer_handler()
def handle_poll(poll):
# This handler can be used to log User answers and to send next poll
pass
bot.infinity_polling()

View File

@ -2917,7 +2917,9 @@ class TeleBot:
can_add_web_page_previews: Optional[bool]=None,
can_change_info: Optional[bool]=None,
can_invite_users: Optional[bool]=None,
can_pin_messages: Optional[bool]=None) -> bool:
can_pin_messages: Optional[bool]=None,
permissions: Optional[types.ChatPermissions]=None,
use_independent_chat_permissions: Optional[bool]=None) -> bool:
"""
Use this method to restrict a user in a supergroup.
The bot must be an administrator in the supergroup for this to work and must have
@ -2925,6 +2927,9 @@ class TeleBot:
Telegram documentation: https://core.telegram.org/bots/api#restrictchatmember
.. warning::
Individual parameters are deprecated and will be removed, use 'permissions' instead.
:param chat_id: Unique identifier for the target group or username of the target supergroup
or channel (in the format @channelusername)
:type chat_id: :obj:`int` or :obj:`str`
@ -2965,15 +2970,36 @@ class TeleBot:
:param can_pin_messages: Pass True, if the user is allowed to pin messages. Ignored in public supergroups
:type can_pin_messages: :obj:`bool`
:param use_independent_chat_permissions: Pass True if chat permissions are set independently. Otherwise,
the can_send_other_messages and can_add_web_page_previews permissions will imply the can_send_messages,
can_send_audios, can_send_documents, can_send_photos, can_send_videos, can_send_video_notes, and
can_send_voice_notes permissions; the can_send_polls permission will imply the can_send_messages permission.
:type use_independent_chat_permissions: :obj:`bool`
:param permissions: Pass ChatPermissions object to set all permissions at once. Use this param instead of
passing all boolean parameters.
:type permissions: :class:`telebot.types.ChatPermissions`
:return: True on success
:rtype: :obj:`bool`
"""
if permissions is None:
permissions = types.ChatPermissions(
can_send_messages=can_send_messages,
can_send_media_messages=can_send_media_messages,
can_send_polls=can_send_polls,
can_send_other_messages=can_send_other_messages,
can_add_web_page_previews=can_add_web_page_previews,
can_change_info=can_change_info,
can_invite_users=can_invite_users,
can_pin_messages=can_pin_messages
)
logger.warning(
"Individual parameters are deprecated and will be removed, use 'permissions' instead."
)
return apihelper.restrict_chat_member(
self.token, chat_id, user_id, until_date,
can_send_messages, can_send_media_messages,
can_send_polls, can_send_other_messages,
can_add_web_page_previews, can_change_info,
can_invite_users, can_pin_messages)
self.token, chat_id, user_id, permissions, until_date, use_independent_chat_permissions)
def promote_chat_member(
self, chat_id: Union[int, str], user_id: int,
@ -3131,7 +3157,8 @@ class TeleBot:
return apihelper.unban_chat_sender_chat(self.token, chat_id, sender_chat_id)
def set_chat_permissions(
self, chat_id: Union[int, str], permissions: types.ChatPermissions) -> bool:
self, chat_id: Union[int, str], permissions: types.ChatPermissions,
use_independent_chat_permissions: Optional[bool]=None) -> bool:
"""
Use this method to set default chat permissions for all members.
The bot must be an administrator in the group or a supergroup for this to work
@ -3146,10 +3173,16 @@ class TeleBot:
:param permissions: New default chat permissions
:type permissions: :class:`telebot.types..ChatPermissions`
:param use_independent_chat_permissions: Pass True if chat permissions are set independently. Otherwise,
the can_send_other_messages and can_add_web_page_previews permissions will imply the can_send_messages,
can_send_audios, can_send_documents, can_send_photos, can_send_videos, can_send_video_notes, and
can_send_voice_notes permissions; the can_send_polls permission will imply the can_send_messages permission.
:type use_independent_chat_permissions: :obj:`bool`
:return: True on success
:rtype: :obj:`bool`
"""
return apihelper.set_chat_permissions(self.token, chat_id, permissions)
return apihelper.set_chat_permissions(self.token, chat_id, permissions, use_independent_chat_permissions)
def create_chat_invite_link(
self, chat_id: Union[int, str],

View File

@ -968,36 +968,19 @@ def unban_chat_member(token, chat_id, user_id, only_if_banned):
def restrict_chat_member(
token, chat_id, user_id, until_date=None,
can_send_messages=None, can_send_media_messages=None,
can_send_polls=None, can_send_other_messages=None,
can_add_web_page_previews=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None):
token, chat_id, user_id, permissions, until_date=None,
use_independent_chat_permissions=None):
method_url = 'restrictChatMember'
permissions = {}
if can_send_messages is not None:
permissions['can_send_messages'] = can_send_messages
if can_send_media_messages is not None:
permissions['can_send_media_messages'] = can_send_media_messages
if can_send_polls is not None:
permissions['can_send_polls'] = can_send_polls
if can_send_other_messages is not None:
permissions['can_send_other_messages'] = can_send_other_messages
if can_add_web_page_previews is not None:
permissions['can_add_web_page_previews'] = can_add_web_page_previews
if can_change_info is not None:
permissions['can_change_info'] = can_change_info
if can_invite_users is not None:
permissions['can_invite_users'] = can_invite_users
if can_pin_messages is not None:
permissions['can_pin_messages'] = can_pin_messages
permissions_json = json.dumps(permissions)
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions_json}
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions.to_json()}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
if until_date is not None:
if isinstance(until_date, datetime):
payload['until_date'] = until_date.timestamp()
else:
payload['until_date'] = until_date
return _make_request(token, method_url, params=payload, method='post')
@ -1056,12 +1039,14 @@ def unban_chat_sender_chat(token, chat_id, sender_chat_id):
return _make_request(token, method_url, params=payload, method='post')
def set_chat_permissions(token, chat_id, permissions):
def set_chat_permissions(token, chat_id, permissions, use_independent_chat_permissions=None):
method_url = 'setChatPermissions'
payload = {
'chat_id': chat_id,
'permissions': permissions.to_json()
}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
return _make_request(token, method_url, params=payload, method='post')

View File

@ -3775,7 +3775,9 @@ class AsyncTeleBot:
can_add_web_page_previews: Optional[bool]=None,
can_change_info: Optional[bool]=None,
can_invite_users: Optional[bool]=None,
can_pin_messages: Optional[bool]=None) -> bool:
can_pin_messages: Optional[bool]=None,
permissions: Optional[types.ChatPermissions]=None,
use_independent_chat_permissions: Optional[bool]=None) -> bool:
"""
Use this method to restrict a user in a supergroup.
The bot must be an administrator in the supergroup for this to work and must have
@ -3783,6 +3785,9 @@ class AsyncTeleBot:
Telegram documentation: https://core.telegram.org/bots/api#restrictchatmember
.. warning::
Individual parameters are deprecated and will be removed, use 'permissions' instead
:param chat_id: Unique identifier for the target group or username of the target supergroup
or channel (in the format @channelusername)
:type chat_id: :obj:`int` or :obj:`str`
@ -3823,15 +3828,35 @@ class AsyncTeleBot:
:param can_pin_messages: Pass True, if the user is allowed to pin messages. Ignored in public supergroups
:type can_pin_messages: :obj:`bool`
:param use_independent_chat_permissions: Pass True if chat permissions are set independently. Otherwise,
the can_send_other_messages and can_add_web_page_previews permissions will imply the can_send_messages,
can_send_audios, can_send_documents, can_send_photos, can_send_videos, can_send_video_notes, and
can_send_voice_notes permissions; the can_send_polls permission will imply the can_send_messages permission.
:type use_independent_chat_permissions: :obj:`bool`
:param permissions: Pass ChatPermissions object to set all permissions at once. Use this parameter instead of
passing all boolean parameters to avoid backward compatibility problems in future.
:type permissions: :obj:`types.ChatPermissions`
:return: True on success
:rtype: :obj:`bool`
"""
if permissions is None:
permissions = types.ChatPermissions(
can_send_messages=can_send_messages,
can_send_media_messages=can_send_media_messages,
can_send_polls=can_send_polls,
can_send_other_messages=can_send_other_messages,
can_add_web_page_previews=can_add_web_page_previews,
can_change_info=can_change_info,
can_invite_users=can_invite_users,
can_pin_messages=can_pin_messages
)
logger.warning(
"Individual parameters are deprecated and will be removed, use 'permissions' instead."
)
return await asyncio_helper.restrict_chat_member(
self.token, chat_id, user_id, until_date,
can_send_messages, can_send_media_messages,
can_send_polls, can_send_other_messages,
can_add_web_page_previews, can_change_info,
can_invite_users, can_pin_messages)
self.token, chat_id, user_id, permissions, until_date, use_independent_chat_permissions)
async def promote_chat_member(
self, chat_id: Union[int, str], user_id: int,
@ -3991,7 +4016,8 @@ class AsyncTeleBot:
return await asyncio_helper.unban_chat_sender_chat(self.token, chat_id, sender_chat_id)
async def set_chat_permissions(
self, chat_id: Union[int, str], permissions: types.ChatPermissions) -> bool:
self, chat_id: Union[int, str], permissions: types.ChatPermissions,
use_independent_chat_permissions: Optional[bool]=None) -> bool:
"""
Use this method to set default chat permissions for all members.
The bot must be an administrator in the group or a supergroup for this to work
@ -4006,10 +4032,16 @@ class AsyncTeleBot:
:param permissions: New default chat permissions
:type permissions: :class:`telebot.types..ChatPermissions`
:param use_independent_chat_permissions: Pass True if chat permissions are set independently. Otherwise,
the can_send_other_messages and can_add_web_page_previews permissions will imply the can_send_messages,
can_send_audios, can_send_documents, can_send_photos, can_send_videos, can_send_video_notes, and
can_send_voice_notes permissions; the can_send_polls permission will imply the can_send_messages permission.
:type use_independent_chat_permissions: :obj:`bool`
:return: True on success
:rtype: :obj:`bool`
"""
return await asyncio_helper.set_chat_permissions(self.token, chat_id, permissions)
return await asyncio_helper.set_chat_permissions(self.token, chat_id, permissions, use_independent_chat_permissions)
async def create_chat_invite_link(
self, chat_id: Union[int, str],

View File

@ -184,7 +184,7 @@ async def download_file(token, file_path):
session = await session_manager.get_session()
async with session.get(url, proxy=proxy) as response:
if response.status != 200:
raise ApiHTTPException('Download file', result)
raise ApiHTTPException('Download file', response)
result = await response.read()
return result
@ -243,11 +243,11 @@ async def get_updates(token, offset=None, limit=None,
params['limit'] = limit
if timeout:
params['timeout'] = timeout
if allowed_updates:
params['allowed_updates'] = allowed_updates
if allowed_updates is not None: # Empty lists should pass
params['allowed_updates'] = json.dumps(allowed_updates)
return await _process_request(token, method_name, params=params, request_timeout=request_timeout)
async def _check_result(method_name, result):
async def _check_result(method_name, result: aiohttp.ClientResponse):
"""
Checks whether `result` is a valid API response.
A result is considered invalid if:
@ -263,7 +263,7 @@ async def _check_result(method_name, result):
try:
result_json = await result.json(encoding="utf-8")
except:
if result.status_code != 200:
if result.status != 200:
raise ApiHTTPException(method_name, result)
else:
raise ApiInvalidJSONException(method_name, result)
@ -960,31 +960,13 @@ async def unban_chat_member(token, chat_id, user_id, only_if_banned):
async def restrict_chat_member(
token, chat_id, user_id, until_date=None,
can_send_messages=None, can_send_media_messages=None,
can_send_polls=None, can_send_other_messages=None,
can_add_web_page_previews=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None):
token, chat_id, user_id, permissions, until_date=None,
use_independent_chat_permissions=None):
method_url = 'restrictChatMember'
permissions = {}
if can_send_messages is not None:
permissions['can_send_messages'] = can_send_messages
if can_send_media_messages is not None:
permissions['can_send_media_messages'] = can_send_media_messages
if can_send_polls is not None:
permissions['can_send_polls'] = can_send_polls
if can_send_other_messages is not None:
permissions['can_send_other_messages'] = can_send_other_messages
if can_add_web_page_previews is not None:
permissions['can_add_web_page_previews'] = can_add_web_page_previews
if can_change_info is not None:
permissions['can_change_info'] = can_change_info
if can_invite_users is not None:
permissions['can_invite_users'] = can_invite_users
if can_pin_messages is not None:
permissions['can_pin_messages'] = can_pin_messages
permissions_json = json.dumps(permissions)
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions_json}
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions.to_json()}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
if until_date is not None:
if isinstance(until_date, datetime):
payload['until_date'] = until_date.timestamp()
@ -1046,12 +1028,14 @@ async def unban_chat_sender_chat(token, chat_id, sender_chat_id):
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
return await _process_request(token, method_url, params=payload, method='post')
async def set_chat_permissions(token, chat_id, permissions):
async def set_chat_permissions(token, chat_id, permissions, use_independent_chat_permissions=None):
method_url = 'setChatPermissions'
payload = {
'chat_id': chat_id,
'permissions': permissions.to_json()
}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
return await _process_request(token, method_url, params=payload, method='post')
@ -1914,10 +1898,10 @@ class ApiHTTPException(ApiException):
This class represents an Exception thrown when a call to the
Telegram API server returns HTTP code that is not 200.
"""
def __init__(self, function_name, result):
def __init__(self, function_name, result: aiohttp.ClientResponse):
super(ApiHTTPException, self).__init__(
"The server returned HTTP {0} {1}. Response body:\n[{2}]" \
.format(result.status_code, result.reason, result),
.format(result.status, result.reason, result.request_info),
function_name,
result)

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
from io import IOBase
import logging
@ -288,9 +289,16 @@ class ChatJoinRequest(JsonDeserializable):
:param chat: Chat to which the request was sent
:type chat: :class:`telebot.types.Chat`
:param from: User that sent the join request
:param from_user: User that sent the join request
:type from_user: :class:`telebot.types.User`
:param user_chat_id: Optional. Identifier of a private chat with the user who sent the join request.
This number may have more than 32 significant bits and some programming languages may have difficulty/silent
defects in interpreting it. But it has at most 52 significant bits, so a 64-bit integer or double-precision
float type are safe for storing this identifier. The bot can use this identifier for 24 hours to send messages
until the join request is processed, assuming no other administrator contacted the user.
:type user_chat_id: :obj:`int`
:param date: Date the request was sent in Unix time
:type date: :obj:`int`
@ -312,12 +320,13 @@ class ChatJoinRequest(JsonDeserializable):
obj['invite_link'] = ChatInviteLink.de_json(obj.get('invite_link'))
return cls(**obj)
def __init__(self, chat, from_user, date, bio=None, invite_link=None, **kwargs):
self.chat = chat
self.from_user = from_user
self.date = date
self.bio = bio
self.invite_link = invite_link
def __init__(self, chat, from_user, user_chat_id, date, bio=None, invite_link=None, **kwargs):
self.chat: Chat = chat
self.from_user: User = from_user
self.date: str = date
self.bio: str = bio
self.invite_link: ChatInviteLink = invite_link
self.user_chat_id: int = user_chat_id
class WebhookInfo(JsonDeserializable):
"""
@ -902,6 +911,12 @@ class Message(JsonDeserializable):
the payment. More about payments »
:type successful_payment: :class:`telebot.types.SuccessfulPayment`
:param user_shared: Optional. Service message: a user was shared with the bot
:type user_shared: :class:`telebot.types.UserShared`
:param chat_shared: Optional. Service message: a chat was shared with the bot
:type chat_shared: :class:`telebot.types.ChatShared`
:param connected_website: Optional. The domain name of the website on which the user has logged in. More about
Telegram Login »
:type connected_website: :obj:`str`
@ -1151,6 +1166,12 @@ class Message(JsonDeserializable):
if 'write_access_allowed' in obj:
opts['write_access_allowed'] = WriteAccessAllowed.de_json(obj['write_access_allowed'])
content_type = 'write_access_allowed'
if 'user_shared' in obj:
opts['user_shared'] = UserShared.de_json(obj['user_shared'])
content_type = 'user_shared'
if 'chat_shared' in obj:
opts['chat_shared'] = ChatShared.de_json(obj['chat_shared'])
content_type = 'chat_shared'
return cls(message_id, from_user, date, chat, content_type, opts, json_string)
@classmethod
@ -1246,6 +1267,8 @@ class Message(JsonDeserializable):
self.general_forum_topic_hidden: Optional[GeneralForumTopicHidden] = None
self.general_forum_topic_unhidden: Optional[GeneralForumTopicUnhidden] = None
self.write_access_allowed: Optional[WriteAccessAllowed] = None
self.user_shared: Optional[UserShared] = None
self.chat_shared: Optional[ChatShared] = None
for key in options:
setattr(self, key, options[key])
self.json = json_string
@ -2217,6 +2240,117 @@ class KeyboardButtonPollType(Dictionaryable):
def to_dict(self):
return {'type': self.type}
class KeyboardButtonRequestUser(Dictionaryable):
"""
This object defines the criteria used to request a suitable user.
The identifier of the selected user will be shared with the bot when the corresponding button is pressed.
Telegram documentation: https://core.telegram.org/bots/api#keyboardbuttonrequestuser
:param request_id: Signed 32-bit identifier of the request, which will be received back in the UserShared object.
Must be unique within the message
:type request_id: :obj:`int`
:param user_is_bot: Optional. Pass True to request a bot, pass False to request a regular user.
If not specified, no additional restrictions are applied.
:type user_is_bot: :obj:`bool`
:param user_is_premium: Optional. Pass True to request a premium user, pass False to request a non-premium user.
If not specified, no additional restrictions are applied.
:type user_is_premium: :obj:`bool`
:return: Instance of the class
:rtype: :class:`telebot.types.KeyboardButtonRequestUser`
"""
def __init__(self, request_id: int, user_is_bot: Optional[bool]=None, user_is_premium: Optional[bool]=None) -> None:
self.request_id: int = request_id
self.user_is_bot: Optional[bool] = user_is_bot
self.user_is_premium: Optional[bool] = user_is_premium
def to_dict(self) -> dict:
data = {'request_id': self.request_id}
if self.user_is_bot is not None:
data['user_is_bot'] = self.user_is_bot
if self.user_is_premium is not None:
data['user_is_premium'] = self.user_is_premium
return data
class KeyboardButtonRequestChat(Dictionaryable):
"""
This object defines the criteria used to request a suitable chat. The identifier of the selected chat will
be shared with the bot when the corresponding button is pressed.
Telegram documentation: https://core.telegram.org/bots/api#keyboardbuttonrequestchat
:param request_id: Signed 32-bit identifier of the request, which will be received back in the ChatShared object.
Must be unique within the message
:type request_id: :obj:`int`
:param chat_is_channel: Pass True to request a channel chat, pass False to request a group or a supergroup chat.
:type chat_is_channel: :obj:`bool`
:param chat_is_forum: Optional. Pass True to request a forum supergroup, pass False to request a non-forum chat.
If not specified, no additional restrictions are applied.
:type chat_is_forum: :obj:`bool`
:param chat_has_username: Optional. Pass True to request a supergroup or a channel with a username, pass False to request a
chat without a username. If not specified, no additional restrictions are applied.
:type chat_has_username: :obj:`bool`
:param chat_is_created: Optional. Pass True to request a chat owned by the user. Otherwise, no additional restrictions are applied.
:type chat_is_created: :obj:`bool`
:param user_administrator_rights: Optional. A JSON-serialized object listing the required administrator rights of the user in the chat.
The rights must be a superset of bot_administrator_rights. If not specified, no additional restrictions are applied.
:type user_administrator_rights: :class:`telebot.types.ChatAdministratorRights`
:param bot_administrator_rights: Optional. A JSON-serialized object listing the required administrator rights of the bot in the chat.
The rights must be a subset of user_administrator_rights. If not specified, no additional restrictions are applied.
:type bot_administrator_rights: :class:`telebot.types.ChatAdministratorRights`
:param bot_is_member: Optional. Pass True to request a chat where the bot is a member. Otherwise, no additional restrictions are applied.
:type bot_is_member: :obj:`bool`
:return: Instance of the class
:rtype: :class:`telebot.types.KeyboardButtonRequestChat`
"""
def __init__(self, request_id: int, chat_is_channel: bool, chat_is_forum: Optional[bool]=None,
chat_has_username: Optional[bool]=None, chat_is_created: Optional[bool]=None,
user_administrator_rights: Optional[ChatAdministratorRights]=None,
bot_administrator_rights: Optional[ChatAdministratorRights]=None, bot_is_member: Optional[bool]=None) -> None:
self.request_id: int = request_id
self.chat_is_channel: bool = chat_is_channel
self.chat_is_forum: Optional[bool] = chat_is_forum
self.chat_has_username: Optional[bool] = chat_has_username
self.chat_is_created: Optional[bool] = chat_is_created
self.user_administrator_rights: Optional[ChatAdministratorRights] = user_administrator_rights
self.bot_administrator_rights: Optional[ChatAdministratorRights] = bot_administrator_rights
self.bot_is_member: Optional[bool] = bot_is_member
def to_dict(self) -> dict:
data = {'request_id': self.request_id, 'chat_is_channel': self.chat_is_channel}
if self.chat_is_forum is not None:
data['chat_is_forum'] = self.chat_is_forum
if self.chat_has_username is not None:
data['chat_has_username'] = self.chat_has_username
if self.chat_is_created is not None:
data['chat_is_created'] = self.chat_is_created
if self.user_administrator_rights is not None:
data['user_administrator_rights'] = self.user_administrator_rights.to_dict()
if self.bot_administrator_rights is not None:
data['bot_administrator_rights'] = self.bot_administrator_rights.to_dict()
if self.bot_is_member is not None:
data['bot_is_member'] = self.bot_is_member
return data
class KeyboardButton(Dictionaryable, JsonSerializable):
@ -2245,17 +2379,29 @@ class KeyboardButton(Dictionaryable, JsonSerializable):
will be able to send a web_app_data service message. Available in private chats only.
:type web_app: :class:`telebot.types.WebAppInfo`
:param request_user: Optional. If specified, pressing the button will open a list of suitable users. Tapping on any user
will send their identifier to the bot in a user_shared service message. Available in private chats only.
:type request_user: :class:`telebot.types.KeyboardButtonRequestUser`
:param request_chat: Optional. If specified, pressing the button will open a list of suitable chats. Tapping on a chat will
send its identifier to the bot in a chat_shared service message. Available in private chats only.
:type request_chat: :class:`telebot.types.KeyboardButtonRequestChat`
:return: Instance of the class
:rtype: :class:`telebot.types.KeyboardButton`
"""
def __init__(self, text: str, request_contact: Optional[bool]=None,
request_location: Optional[bool]=None, request_poll: Optional[KeyboardButtonPollType]=None,
web_app: WebAppInfo=None):
web_app: Optional[WebAppInfo]=None, request_user: Optional[KeyboardButtonRequestUser]=None,
request_chat: Optional[KeyboardButtonRequestChat]=None):
self.text: str = text
self.request_contact: bool = request_contact
self.request_location: bool = request_location
self.request_poll: KeyboardButtonPollType = request_poll
self.web_app: WebAppInfo = web_app
self.request_user: KeyboardButtonRequestUser = request_user
self.request_chat: KeyboardButtonRequestChat = request_chat
def to_json(self):
return json.dumps(self.to_dict())
@ -2270,6 +2416,10 @@ class KeyboardButton(Dictionaryable, JsonSerializable):
json_dict['request_poll'] = self.request_poll.to_dict()
if self.web_app is not None:
json_dict['web_app'] = self.web_app.to_dict()
if self.request_user is not None:
json_dict['request_user'] = self.request_user.to_dict()
if self.request_chat is not None:
json_dict['request_chat'] = self.request_chat.to_dict()
return json_dict
@ -2666,10 +2816,14 @@ class ChatMember(JsonDeserializable):
can_post_messages=None, can_edit_messages=None, can_delete_messages=None,
can_restrict_members=None, can_promote_members=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None, is_member=None,
can_send_messages=None, can_send_media_messages=None, can_send_polls=None,
can_send_messages=None, can_send_audios=None, can_send_documents=None,
can_send_photos=None, can_send_videos=None, can_send_video_notes=None,
can_send_voice_notes=None,
can_send_polls=None,
can_send_other_messages=None, can_add_web_page_previews=None,
can_manage_chat=None, can_manage_video_chats=None,
until_date=None, can_manage_topics=None, **kwargs):
until_date=None, can_manage_topics=None,
**kwargs):
self.user: User = user
self.status: str = status
self.custom_title: str = custom_title
@ -2685,7 +2839,7 @@ class ChatMember(JsonDeserializable):
self.can_pin_messages: bool = can_pin_messages
self.is_member: bool = is_member
self.can_send_messages: bool = can_send_messages
self.can_send_media_messages: bool = can_send_media_messages
#self.can_send_media_messages: bool = can_send_media_messages
self.can_send_polls: bool = can_send_polls
self.can_send_other_messages: bool = can_send_other_messages
self.can_add_web_page_previews: bool = can_add_web_page_previews
@ -2694,6 +2848,13 @@ class ChatMember(JsonDeserializable):
self.can_manage_voice_chats: bool = self.can_manage_video_chats # deprecated, for backward compatibility
self.until_date: int = until_date
self.can_manage_topics: bool = can_manage_topics
self.can_send_audios: bool = can_send_audios
self.can_send_documents: bool = can_send_documents
self.can_send_photos: bool = can_send_photos
self.can_send_videos: bool = can_send_videos
self.can_send_video_notes: bool = can_send_video_notes
self.can_send_voice_notes: bool = can_send_voice_notes
class ChatMemberOwner(ChatMember):
@ -2834,9 +2995,23 @@ class ChatMemberRestricted(ChatMember):
:param can_send_messages: True, if the user is allowed to send text messages, contacts, locations and venues
:type can_send_messages: :obj:`bool`
:param can_send_media_messages: True, if the user is allowed to send audios, documents, photos, videos, video
notes and voice notes
:type can_send_media_messages: :obj:`bool`
:param can_send_audios: True, if the user is allowed to send audios
:type can_send_audios: :obj:`bool`
:param can_send_documents: True, if the user is allowed to send documents
:type can_send_documents: :obj:`bool`
:param can_send_photos: True, if the user is allowed to send photos
:type can_send_photos: :obj:`bool`
:param can_send_videos: True, if the user is allowed to send videos
:type can_send_videos: :obj:`bool`
:param can_send_video_notes: True, if the user is allowed to send video notes
:type can_send_video_notes: :obj:`bool`
:param can_send_voice_notes: True, if the user is allowed to send voice notes
:type can_send_voice_notes: :obj:`bool`
:param can_send_polls: True, if the user is allowed to send polls
:type can_send_polls: :obj:`bool`
@ -2908,19 +3083,33 @@ class ChatPermissions(JsonDeserializable, JsonSerializable, Dictionaryable):
venues
:type can_send_messages: :obj:`bool`
:param can_send_media_messages: Optional. True, if the user is allowed to send audios, documents, photos, videos,
video notes and voice notes, implies can_send_messages
:type can_send_media_messages: :obj:`bool`
:param can_send_audios: Optional. True, if the user is allowed to send audios
:type can_send_audios: :obj:`bool`
:param can_send_documents: Optional. True, if the user is allowed to send documents
:type can_send_documents: :obj:`bool`
:param can_send_photos: Optional. True, if the user is allowed to send photos
:type can_send_photos: :obj:`bool`
:param can_send_videos: Optional. True, if the user is allowed to send videos
:type can_send_videos: :obj:`bool`
:param can_send_video_notes: Optional. True, if the user is allowed to send video notes
:type can_send_video_notes: :obj:`bool`
:param can_send_voice_notes: Optional. True, if the user is allowed to send voice notes
:type can_send_voice_notes: :obj:`bool`
:param can_send_polls: Optional. True, if the user is allowed to send polls, implies can_send_messages
:type can_send_polls: :obj:`bool`
:param can_send_other_messages: Optional. True, if the user is allowed to send animations, games, stickers and use
inline bots, implies can_send_media_messages
inline bots
:type can_send_other_messages: :obj:`bool`
:param can_add_web_page_previews: Optional. True, if the user is allowed to add web page previews to their
messages, implies can_send_media_messages
messages
:type can_add_web_page_previews: :obj:`bool`
:param can_change_info: Optional. True, if the user is allowed to change the chat title, photo and other settings.
@ -2937,6 +3126,10 @@ class ChatPermissions(JsonDeserializable, JsonSerializable, Dictionaryable):
value of can_pin_messages
:type can_manage_topics: :obj:`bool`
:param can_send_media_messages: deprecated. True, if the user is allowed to send audios, documents, photos, videos,
video notes and voice notes
:type can_send_media_messages: :obj:`bool`
:return: Instance of the class
:rtype: :class:`telebot.types.ChatPermissions`
"""
@ -2946,13 +3139,15 @@ class ChatPermissions(JsonDeserializable, JsonSerializable, Dictionaryable):
obj = cls.check_json(json_string, dict_copy=False)
return cls(**obj)
def __init__(self, can_send_messages=None, can_send_media_messages=None,
can_send_polls=None, can_send_other_messages=None,
can_add_web_page_previews=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None,
can_manage_topics=None, **kwargs):
def __init__(self, can_send_messages=None, can_send_media_messages=None,can_send_audios=None,
can_send_documents=None, can_send_photos=None,
can_send_videos=None, can_send_video_notes=None,
can_send_voice_notes=None, can_send_polls=None, can_send_other_messages=None,
can_add_web_page_previews=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None,
can_manage_topics=None, **kwargs):
self.can_send_messages: bool = can_send_messages
self.can_send_media_messages: bool = can_send_media_messages
#self.can_send_media_messages: bool = can_send_media_messages
self.can_send_polls: bool = can_send_polls
self.can_send_other_messages: bool = can_send_other_messages
self.can_add_web_page_previews: bool = can_add_web_page_previews
@ -2960,6 +3155,22 @@ class ChatPermissions(JsonDeserializable, JsonSerializable, Dictionaryable):
self.can_invite_users: bool = can_invite_users
self.can_pin_messages: bool = can_pin_messages
self.can_manage_topics: bool = can_manage_topics
self.can_send_audios: bool = can_send_audios
self.can_send_documents: bool = can_send_documents
self.can_send_photos: bool = can_send_photos
self.can_send_videos: bool = can_send_videos
self.can_send_video_notes: bool = can_send_video_notes
self.can_send_voice_notes: bool = can_send_voice_notes
if can_send_media_messages is not None:
logger.warning("can_send_media_messages is deprecated. Use individual parameters like can_send_audios, can_send_documents, etc.")
self.can_send_audios = can_send_media_messages
self.can_send_documents = can_send_media_messages
self.can_send_photos = can_send_media_messages
self.can_send_videos = can_send_media_messages
self.can_send_video_notes = can_send_media_messages
self.can_send_voice_notes = can_send_media_messages
def to_json(self):
return json.dumps(self.to_dict())
@ -2968,8 +3179,19 @@ class ChatPermissions(JsonDeserializable, JsonSerializable, Dictionaryable):
json_dict = dict()
if self.can_send_messages is not None:
json_dict['can_send_messages'] = self.can_send_messages
if self.can_send_media_messages is not None:
json_dict['can_send_media_messages'] = self.can_send_media_messages
if self.can_send_audios is not None:
json_dict['can_send_audios'] = self.can_send_audios
if self.can_send_documents is not None:
json_dict['can_send_documents'] = self.can_send_documents
if self.can_send_photos is not None:
json_dict['can_send_photos'] = self.can_send_photos
if self.can_send_videos is not None:
json_dict['can_send_videos'] = self.can_send_videos
if self.can_send_video_notes is not None:
json_dict['can_send_video_notes'] = self.can_send_video_notes
if self.can_send_voice_notes is not None:
json_dict['can_send_voice_notes'] = self.can_send_voice_notes
if self.can_send_polls is not None:
json_dict['can_send_polls'] = self.can_send_polls
if self.can_send_other_messages is not None:
@ -7012,5 +7234,65 @@ class WriteAccessAllowed(JsonDeserializable):
pass
class UserShared(JsonDeserializable):
"""
This object contains information about the user whose identifier was shared with the bot using a
`telebot.types.KeyboardButtonRequestUser` button.
Telegram documentation: https://core.telegram.org/bots/api#usershared
:param request_id: identifier of the request
:type request_id: :obj:`int`
:param user_id: Identifier of the shared user. This number may have more than 32 significant bits and some programming
languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a 64-bit
integer or double-precision float type are safe for storing this identifier. The bot may not have access to the user
and could be unable to use this identifier, unless the user is already known to the bot by some other means.
:type user_id: :obj:`int`
:return: Instance of the class
:rtype: :class:`telebot.types.UserShared`
"""
@classmethod
def de_json(cls, json_string):
if json_string is None: return None
obj = cls.check_json(json_string)
return cls(**obj)
def __init__(self, request_id: int, user_id: int) -> None:
self.request_id: int = request_id
self.user_id: int = user_id
class ChatShared(JsonDeserializable):
"""
This object contains information about the chat whose identifier was shared with the bot using a
`telebot.types.KeyboardButtonRequestChat` button.
Telegram documentation: https://core.telegram.org/bots/api#Chatshared
:param request_id: identifier of the request
:type request_id: :obj:`int`
:param chat_id: Identifier of the shared chat. This number may have more than 32 significant bits and some programming
languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a 64-bit
integer or double-precision float type are safe for storing this identifier. The bot may not have access to the chat
and could be unable to use this identifier, unless the chat is already known to the bot by some other means.
:type chat_id: :obj:`int`
:return: Instance of the class
:rtype: :class:`telebot.types.ChatShared`
"""
@classmethod
def de_json(cls, json_string):
if json_string is None: return None
obj = cls.check_json(json_string)
return cls(**obj)
def __init__(self, request_id: int, chat_id: int) -> None:
self.request_id: int = request_id
self.chat_id: int = chat_id

View File

@ -154,7 +154,8 @@ class ThreadPool:
for worker in self.workers:
worker.stop()
for worker in self.workers:
worker.join()
if worker != threading.current_thread():
worker.join()
class AsyncTask:

View File

@ -1,3 +1,3 @@
# Versions should comply with PEP440.
# This line is parsed in setup.py:
__version__ = '4.9.0'
__version__ = '4.10.0'