Skip to content
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 @@ -69,7 +69,7 @@

## Getting started

This API is tested with Python 3.9-3.13 and Pypy 3.
This API is tested with Python 3.10-3.14 and PyPy 3.
There are two ways to install the library:

* Installation using pip (a Python package manager):
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
copyright = f'2022-{datetime.now().year}, {author}'

# The full version, including alpha/beta/rc tags
release = '4.32.0'
release = '4.33.0'


# -- General configuration ---------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ build-backend = "hatchling.build"

[project]
name = "pyTelegramBotAPI"
version = "4.32.0"
version = "4.33.0"
description = "Python Telegram bot API."
authors = [{name = "eternnoir", email = "eternnoir@gmail.com"}]
license = {text = "GPL2"}
readme = "README.md"
requires-python = ">=3.9"
requires-python = ">=3.10"
keywords = ["telegram", "bot", "api", "tools"]
classifiers = [
"Development Status :: 5 - Production/Stable",
Expand Down
4 changes: 3 additions & 1 deletion telebot/apihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1903,7 +1903,9 @@ def send_invoice(
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
:param reply_parameters: A JSON-serialized object for an inline keyboard. If empty, one 'Pay total price' button will be shown. If not empty, the first button must be a Pay button.
:param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
:param allow_paid_broadcast:
:param allow_paid_broadcast: Pass True to allow up to 1000 messages per second, ignoring broadcasting limits for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
:param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat
:param suggested_post_parameters: A JSON-serialized object containing the parameters of the suggested post to send; for direct messages chats only. If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
:return:
"""
method_url = r'sendInvoice'
Expand Down
22 changes: 15 additions & 7 deletions telebot/async_telebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ def __init__(self, token: str, parse_mode: Optional[str]=None, offset: Optional[
self.middlewares = []

self._user = None # set during polling
self._polling = None
self.webhook_listener = None

if validate_token:
util.validate_token(self.token)
Expand All @@ -203,7 +205,8 @@ def __init__(self, token: str, parse_mode: Optional[str]=None, offset: Optional[
def user(self):
return self._user

async def close_session(self):
@staticmethod
async def close_session():
"""
Closes existing session of aiohttp.
Use this function if you stop polling/webhooks.
Expand Down Expand Up @@ -554,7 +557,7 @@ async def _run_middlewares_and_handlers(self, message, handlers, middlewares, up
elif isinstance(middleware_result, SkipHandler):
skip_handlers = True

if handlers and not(skip_handlers):
if handlers and (not skip_handlers):
try:
for handler in handlers:
params = []
Expand Down Expand Up @@ -4531,7 +4534,7 @@ async def send_document(
protect_content = self.protect_content if (protect_content is None) else protect_content


if data and not(document):
if data and (not document):
# function typo miss compatibility
logger.warning('The parameter "data" is deprecated. Use "document" instead.')
document = data
Expand Down Expand Up @@ -4664,7 +4667,7 @@ async def send_sticker(
protect_content = self.protect_content if (protect_content is None) else protect_content


if data and not(sticker):
if data and (not sticker):
# function typo miss compatibility
logger.warning('The parameter "data" is deprecated. Use "sticker" instead.')
sticker = data
Expand Down Expand Up @@ -4856,12 +4859,12 @@ async def send_video(
if reply_parameters and (reply_parameters.allow_sending_without_reply is None):
reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply

if data and not(video):
if data and (not video):
# function typo miss compatibility
logger.warning('The parameter "data" is deprecated. Use "video" instead.')
video = data

if thumb and not(thumbnail):
if thumb and (not thumbnail):
logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.')
thumbnail = thumb

Expand Down Expand Up @@ -5824,7 +5827,9 @@ async def send_contact(
await asyncio_helper.send_contact(
self.token, chat_id, phone_number, first_name, last_name, vcard,
disable_notification, reply_markup, timeout,
protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast))
protect_content, message_thread_id, reply_parameters, business_connection_id,
message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast,
direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters))

async def send_message_draft(
self, chat_id: int,
Expand Down Expand Up @@ -8214,6 +8219,9 @@ async def set_sticker_set_thumbnail(self, name: str, user_id: int, thumbnail: Un
HTTP URL. If omitted, then the thumbnail is dropped and the first sticker is used as the thumbnail.
:type thumbnail: :obj:`filelike object`

:param format: Format of the thumbnail, must be one of “static” for a .WEBP or .PNG image, “animated” for a .TGS animation, or “video” for a WEBM video
:type format: :obj:`str`

:return: On success, True is returned.
:rtype: :obj:`bool`
"""
Expand Down
10 changes: 7 additions & 3 deletions telebot/asyncio_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ async def _process_request(token, url, method='get', params=None, files=None, **
logger.error(f'Unknown error: {e.__class__.__name__}')
if not got_result:
raise RequestTimeout("Request timeout. Request: method={0} url={1} params={2} files={3} request_timeout={4}".format(method, url, params, files, request_timeout, current_try))
return None

def _prepare_file(obj):
"""
Expand All @@ -119,6 +120,7 @@ def _prepare_file(obj):
name = getattr(obj, 'name', None)
if name and isinstance(name, str) and name[0] != '<' and name[-1] != '>':
return os.path.basename(name)
return None

def _prepare_data(params=None, files=None):
"""
Expand Down Expand Up @@ -1251,6 +1253,7 @@ async def get_method_by_type(data_type):
return r'sendDocument'
if data_type == 'sticker':
return r'sendSticker'
return None


async def ban_chat_member(token, chat_id, user_id, until_date=None, revoke_messages=None):
Expand Down Expand Up @@ -1914,7 +1917,9 @@ async def send_invoice(
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
:param reply_parameters: A JSON-serialized object for an inline keyboard. If empty, one 'Pay total price' button will be shown. If not empty, the first button must be a Pay button.
:param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
:param allow_paid_broadcast:
:param allow_paid_broadcast: Pass True to allow up to 1000 messages per second, ignoring broadcasting limits for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
:param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat
:param suggested_post_parameters: A JSON-serialized object containing the parameters of the suggested post to send; for direct messages chats only. If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
:return:
"""
method_url = r'sendInvoice'
Expand Down Expand Up @@ -2740,6 +2745,7 @@ async def convert_input_media(media):
async def convert_input_media_array(array):
media = []
files = {}
key = ""
for input_media in array:
if isinstance(input_media, types.InputMedia) or isinstance(input_media, types.InputPaidMedia):
media_dict = input_media.to_dict()
Expand Down Expand Up @@ -2831,5 +2837,3 @@ class RequestTimeout(Exception):
This class represents a request timeout.
"""
pass


7 changes: 4 additions & 3 deletions telebot/handler_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def dump_handlers(handlers, filename, file_mode="wb"):
os.makedirs(dirs, exist_ok=True)

with open(filename + ".tmp", file_mode) as file:
if (apihelper.CUSTOM_SERIALIZER is None):
if apihelper.CUSTOM_SERIALIZER is None:
pickle.dump(handlers, file)
else:
apihelper.CUSTOM_SERIALIZER.dump(handlers, file)
Expand All @@ -117,7 +117,7 @@ def dump_handlers(handlers, filename, file_mode="wb"):
def return_load_handlers(filename, del_file_after_loading=True):
if os.path.isfile(filename) and os.path.getsize(filename) > 0:
with open(filename, "rb") as file:
if (apihelper.CUSTOM_SERIALIZER is None):
if apihelper.CUSTOM_SERIALIZER is None:
handlers = pickle.load(file)
else:
handlers = apihelper.CUSTOM_SERIALIZER.load(file)
Expand All @@ -126,6 +126,7 @@ def return_load_handlers(filename, del_file_after_loading=True):
os.remove(filename)

return handlers
return None


class RedisHandlerBackend(HandlerBackend):
Expand Down Expand Up @@ -255,4 +256,4 @@ def start2(message):

"""
def __init__(self) -> None:
pass
pass
22 changes: 10 additions & 12 deletions telebot/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5796,7 +5796,6 @@ def __init__(self):
self.input_message_content: Optional[InputMessageContent] = None
self.parse_mode: Optional[str] = None
self.caption_entities: Optional[List[MessageEntity]] = None
# noinspection PyTypeChecker
self.payload_dic: Dict[str] = {}
self.show_caption_above_media: Optional[bool] = None

Expand Down Expand Up @@ -7653,17 +7652,16 @@ def correct_option_id(self) -> Optional[int]:
return self.correct_option_ids[0]
return None

def add(self, option):
def add(self, option, persistent_id = None):
"""
Add an option to the poll.

:param option: Option to add
:type option: :class:`telebot.types.PollOption` or :obj:`str`
Deprecated
"""
logger.warning("Poll.add is deprecated and will be removed in future versions.")

if type(option) is PollOption:
self.options.append(option)
else:
self.options.append(PollOption(option))
self.options.append(PollOption(option, persistent_id))


class PollAnswer(JsonSerializable, JsonDeserializable, Dictionaryable):
Expand Down Expand Up @@ -10177,8 +10175,7 @@ class BusinessConnection(JsonDeserializable):
:param date: Date the connection was established in Unix time
:type date: :obj:`int`

:param can_reply: Deprecated, use :attr:`rights` instead. True, if the bot can reply to messages from the business account
:type can_reply: :obj:`bool`
:param can_reply: Deprecated, use :attr:`rights` instead.

:param rights: Optional. Rights of the business bot
:type rights: :class:`BusinessBotRights`
Expand All @@ -10198,7 +10195,7 @@ def de_json(cls, json_string):
obj['rights'] = BusinessBotRights.de_json(obj.get('rights'))
return cls(**obj)

def __init__(self, id, user, user_chat_id, date, can_reply, is_enabled,
def __init__(self, id, user, user_chat_id, date, is_enabled,
rights=None, **kwargs):
self.id: str = id
self.user: User = user
Expand Down Expand Up @@ -13219,6 +13216,7 @@ def to_dict(self):
data['others_can_add_tasks'] = self.others_can_add_tasks
if self.others_can_mark_tasks_as_done is not None:
data['others_can_mark_tasks_as_done'] = self.others_can_mark_tasks_as_done
return data


class ChecklistTasksDone(JsonDeserializable):
Expand Down Expand Up @@ -13905,8 +13903,9 @@ def de_json(cls, json_string):
obj['bot'] = User.de_json(obj['bot'])

return cls(**obj)



# noinspection PyShadowingBuiltins
class PreparedKeyboardButton(JsonDeserializable):
"""
Describes a keyboard button to be used by a user of a Mini App.
Expand Down Expand Up @@ -14017,4 +14016,3 @@ def de_json(cls, json_string):
if 'option_text_entities' in obj:
obj['option_text_entities'] = [MessageEntity.de_json(entity) for entity in obj['option_text_entities']]
return cls(**obj)

2 changes: 1 addition & 1 deletion telebot/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Versions should comply with PEP440.
# This line is parsed in setup.py:
__version__ = '4.32.0'
__version__ = '4.33.0'
Loading