From dd25432359b61f82f088feebadbae3f42473a9f2 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Sat, 23 Apr 2022 15:03:54 +0300 Subject: [PATCH] Bot API 6.0. Deprecation fixes --- .../chat_member_example.py | 4 +- examples/chat_member_example.py | 4 +- telebot/__init__.py | 29 ++++---- telebot/apihelper.py | 31 +++------ telebot/async_telebot.py | 10 ++- telebot/asyncio_helper.py | 7 +- telebot/types.py | 67 +++++++++++++------ telebot/util.py | 13 ++-- 8 files changed, 92 insertions(+), 73 deletions(-) diff --git a/examples/asynchronous_telebot/chat_member_example.py b/examples/asynchronous_telebot/chat_member_example.py index b2f545c..160c2eb 100644 --- a/examples/asynchronous_telebot/chat_member_example.py +++ b/examples/asynchronous_telebot/chat_member_example.py @@ -23,8 +23,8 @@ async def my_chat_m(message: types.ChatMemberUpdated): #content_Type_service is: #'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created', #'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message', -#'proximity_alert_triggered', 'voice_chat_scheduled', 'voice_chat_started', 'voice_chat_ended', -#'voice_chat_participants_invited', 'message_auto_delete_timer_changed' +#'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started', 'video_chat_ended', +#'video_chat_participants_invited', 'message_auto_delete_timer_changed' # this handler deletes service messages @bot.message_handler(content_types=util.content_type_service) diff --git a/examples/chat_member_example.py b/examples/chat_member_example.py index 36dbfb2..675d956 100644 --- a/examples/chat_member_example.py +++ b/examples/chat_member_example.py @@ -23,8 +23,8 @@ def my_chat_m(message: types.ChatMemberUpdated): #content_Type_service is: #'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created', #'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message', -#'proximity_alert_triggered', 'voice_chat_scheduled', 'voice_chat_started', 'voice_chat_ended', -#'voice_chat_participants_invited', 'message_auto_delete_timer_changed' +#'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started', 'video_chat_ended', +#'video_chat_participants_invited', 'message_auto_delete_timer_changed' # this handler deletes service messages @bot.message_handler(content_types=util.content_type_service) diff --git a/telebot/__init__.py b/telebot/__init__.py index a33b265..f726bcc 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -179,6 +179,7 @@ class TeleBot: self._user = self.get_me() return self._user + @util.deprecated(warn=False, deprecation_text="Most probably this function will be removed in future major releases") def enable_save_next_step_handlers(self, delay=120, filename="./.handler-saves/step.save"): """ Enable saving next step handlers (by default saving disabled) @@ -187,8 +188,6 @@ class TeleBot: compatibility whose purpose was to enable file saving capability for handlers. And the same implementation is now available with FileHandlerBackend - Most probably this function should be deprecated in future major releases - :param delay: Delay between changes in handlers and saving :param filename: Filename of save file """ @@ -203,6 +202,7 @@ class TeleBot: self.current_states = StatePickleStorage(file_path=filename) self.current_states.create_dir() + @util.deprecated(warn=False, deprecation_text="Most probably this function will be removed in future major releases") def enable_save_reply_handlers(self, delay=120, filename="./.handler-saves/reply.save"): """ Enable saving reply handlers (by default saving disable) @@ -211,13 +211,12 @@ class TeleBot: compatibility whose purpose was to enable file saving capability for handlers. And the same implementation is now available with FileHandlerBackend - Most probably this function should be deprecated in future major releases - :param delay: Delay between changes in handlers and saving :param filename: Filename of save file """ self.reply_backend = FileHandlerBackend(self.reply_backend.handlers, filename, delay) + @util.deprecated(warn=False, deprecation_text="Most probably this function will be removed in future major releases") def disable_save_next_step_handlers(self): """ Disable saving next step handlers (by default saving disable) @@ -225,11 +224,10 @@ class TeleBot: This function is left to keep backward compatibility whose purpose was to disable file saving capability for handlers. For the same purpose, MemoryHandlerBackend is reassigned as a new next_step_backend backend instead of FileHandlerBackend. - - Most probably this function should be deprecated in future major releases """ self.next_step_backend = MemoryHandlerBackend(self.next_step_backend.handlers) + @util.deprecated(warn=False, deprecation_text="Most probably this function will be removed in future major releases") def disable_save_reply_handlers(self): """ Disable saving next step handlers (by default saving disable) @@ -237,11 +235,10 @@ class TeleBot: This function is left to keep backward compatibility whose purpose was to disable file saving capability for handlers. For the same purpose, MemoryHandlerBackend is reassigned as a new reply_backend backend instead of FileHandlerBackend. - - Most probably this function should be deprecated in future major releases """ self.reply_backend = MemoryHandlerBackend(self.reply_backend.handlers) + @util.deprecated(warn=False, deprecation_text="Most probably this function will be removed in future major releases") def load_next_step_handlers(self, filename="./.handler-saves/step.save", del_file_after_loading=True): """ Load next step handlers from save file @@ -250,13 +247,12 @@ class TeleBot: help of FileHandlerBackend and is only recommended to use if next_step_backend was assigned as FileHandlerBackend before entering this function - Most probably this function should be deprecated in future major releases - :param filename: Filename of the file where handlers was saved :param del_file_after_loading: Is passed True, after loading save file will be deleted """ self.next_step_backend.load_handlers(filename, del_file_after_loading) + @util.deprecated(warn=False, deprecation_text="Most probably this function will be removed in future major releases") def load_reply_handlers(self, filename="./.handler-saves/reply.save", del_file_after_loading=True): """ Load reply handlers from save file @@ -265,8 +261,6 @@ class TeleBot: help of FileHandlerBackend and is only recommended to use if reply_backend was assigned as FileHandlerBackend before entering this function - Most probably this function should be deprecated in future major releases - :param filename: Filename of the file where handlers was saved :param del_file_after_loading: Is passed True, after loading save file will be deleted """ @@ -620,6 +614,7 @@ class TeleBot: :return: """ if none_stop is not None: + logger.warning("polling: none_stop parameter is deprecated. Use non_stop instead.") non_stop = none_stop if skip_pending: @@ -887,11 +882,11 @@ class TeleBot: result = apihelper.get_chat_administrators(self.token, chat_id) return [types.ChatMember.de_json(r) for r in result] + @util.deprecated(deprecation_text="Use get_chat_member_count instead") def get_chat_members_count(self, chat_id: Union[int, str]) -> int: """ This function is deprecated. Use `get_chat_member_count` instead """ - logger.info('get_chat_members_count is deprecated. Use get_chat_member_count instead.') result = apihelper.get_chat_member_count(self.token, chat_id) return result @@ -1662,6 +1657,7 @@ class TeleBot: """ return apihelper.send_chat_action(self.token, chat_id, action, timeout) + @util.deprecated(deprecation_text="Use ban_chat_member instead") def kick_chat_member( self, chat_id: Union[int, str], user_id: int, until_date:Optional[Union[int, datetime]]=None, @@ -1669,7 +1665,6 @@ class TeleBot: """ This function is deprecated. Use `ban_chat_member` instead """ - logger.info('kick_chat_member is deprecated. Use ban_chat_member instead.') return apihelper.ban_chat_member(self.token, chat_id, user_id, until_date, revoke_messages) def ban_chat_member( @@ -1805,8 +1800,10 @@ class TeleBot: :return: True on success. """ - if can_manage_voice_chats and not can_manage_video_chats is None: - can_manage_video_chats = can_manage_voice_chats + if can_manage_voice_chats is not None: + logger.warning("promote_chat_member: can_manage_voice_chats parameter is deprecated. Use can_manage_video_chats instead.") + if can_manage_video_chats is None: + can_manage_video_chats = can_manage_voice_chats return apihelper.promote_chat_member( self.token, chat_id, user_id, can_change_info, can_post_messages, diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 118b496..55d6dbb 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -47,7 +47,6 @@ CUSTOM_REQUEST_SENDER = None ENABLE_MIDDLEWARE = False - def _get_req_session(reset=False): if SESSION_TIME_TO_LIVE: # If session TTL is set - check time passed @@ -94,20 +93,14 @@ def _make_request(token, method_name, method='get', params=None, files=None): if 'timeout' in params: read_timeout = params.pop('timeout') connect_timeout = read_timeout -# if 'connect-timeout' in params: -# connect_timeout = params.pop('connect-timeout') + 10 if 'long_polling_timeout' in params: - # For getUpdates: it's the only function with timeout parameter on the BOT API side + # For getUpdates. It's the only function with timeout parameter on the BOT API side long_polling_timeout = params.pop('long_polling_timeout') params['timeout'] = long_polling_timeout # Long polling hangs for a given time. Read timeout should be greater that long_polling_timeout read_timeout = max(long_polling_timeout + 5, read_timeout) - # Lets stop suppose that user is stupid and assume that he knows what he do... - # read_timeout = read_timeout + 10 - # connect_timeout = connect_timeout + 10 params = params or None # Set params to None if empty - result = None if RETRY_ON_ERROR and RETRY_ENGINE == 1: got_result = False @@ -134,6 +127,7 @@ def _make_request(token, method_name, method='get', params=None, files=None): timeout=(connect_timeout, read_timeout), proxies=proxy) elif RETRY_ON_ERROR and RETRY_ENGINE == 2: http = _get_req_session() + # noinspection PyUnresolvedReferences retry_strategy = requests.packages.urllib3.util.retry.Retry( total=MAX_RETRIES, ) @@ -1146,7 +1140,6 @@ def set_chat_menu_button(token, chat_id=None, menu_button=None): payload['chat_id'] = chat_id if menu_button: payload['menu_button'] = menu_button.to_json() - return _make_request(token, method_url, params=payload, method='post') def get_chat_menu_button(token, chat_id=None): @@ -1154,7 +1147,6 @@ def get_chat_menu_button(token, chat_id=None): payload = {} if chat_id: payload['chat_id'] = chat_id - return _make_request(token, method_url, params=payload, method='post') @@ -1163,17 +1155,16 @@ def set_my_default_administrator_rights(token, rights=None, for_channels=None): payload = {} if rights: payload['rights'] = rights.to_json() - if for_channels: + if for_channels is not None: payload['for_channels'] = for_channels - return _make_request(token, method_url, params=payload, method='post') + def get_my_default_administrator_rights(token, for_channels=None): method_url = r'getMyDefaultAdministratorRights' payload = {} if for_channels: payload['for_channels'] = for_channels - return _make_request(token, method_url, params=payload, method='post') @@ -1326,7 +1317,6 @@ def send_game( payload['allow_sending_without_reply'] = allow_sending_without_reply if protect_content is not None: payload['protect_content'] = protect_content - return _make_request(token, method_url, params=payload) @@ -1573,7 +1563,6 @@ def create_new_sticker_set( contains_masks=None, mask_position=None, webm_sticker=None): method_url = 'createNewStickerSet' payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis} - stype = None if png_sticker: stype = 'png_sticker' elif webm_sticker: @@ -1598,7 +1587,6 @@ def create_new_sticker_set( def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker): method_url = 'addStickerToSet' payload = {'user_id': user_id, 'name': name, 'emojis': emojis} - stype = None if png_sticker: stype = 'png_sticker' elif webm_sticker: @@ -1705,7 +1693,6 @@ def _convert_list_json_serializable(results): return '[' + ret + ']' - def _convert_markup(markup): if isinstance(markup, types.JsonSerializable): return markup.to_json() @@ -1778,7 +1765,8 @@ class ApiException(Exception): super(ApiException, self).__init__("A request to the Telegram API was unsuccessful. {0}".format(msg)) self.function_name = function_name self.result = result - + + class ApiHTTPException(ApiException): """ This class represents an Exception thrown when a call to the @@ -1790,7 +1778,8 @@ class ApiHTTPException(ApiException): .format(result.status_code, result.reason, result.text.encode('utf8')), function_name, result) - + + class ApiInvalidJSONException(ApiException): """ This class represents an Exception thrown when a call to the @@ -1802,7 +1791,8 @@ class ApiInvalidJSONException(ApiException): .format(result.text.encode('utf8')), function_name, result) - + + class ApiTelegramException(ApiException): """ This class represents an Exception thrown when a Telegram API returns error code. @@ -1816,4 +1806,3 @@ class ApiTelegramException(ApiException): self.result_json = result_json self.error_code = result_json['error_code'] self.description = result_json['description'] - diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index a2fdd75..6496e1b 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -149,6 +149,7 @@ class AsyncTeleBot: :return: """ if none_stop is not None: + logger.warning("polling: none_stop parameter is deprecated. Use non_stop instead.") non_stop = none_stop if skip_pending: @@ -1919,7 +1920,9 @@ class AsyncTeleBot: """ if data and not(sticker): # function typo miss compatibility + logger.warning("send_sticker: data parameter is deprecated. Use sticker instead.") sticker = data + return types.Message.de_json( await asyncio_helper.send_data( self.token, chat_id, sticker, 'sticker', @@ -1970,6 +1973,7 @@ class AsyncTeleBot: parse_mode = self.parse_mode if (parse_mode is None) else parse_mode if data and not(video): # function typo miss compatibility + logger.warning("send_sticker: data parameter is deprecated. Use video instead.") video = data return types.Message.de_json( @@ -2423,8 +2427,10 @@ class AsyncTeleBot: :return: True on success. """ - if can_manage_voice_chats and not can_manage_video_chats is None: - can_manage_video_chats = can_manage_voice_chats + if can_manage_voice_chats is not None: + logger.warning("promote_chat_member: can_manage_voice_chats parameter is deprecated. Use can_manage_video_chats instead.") + if can_manage_video_chats is None: + can_manage_video_chats = can_manage_voice_chats return await asyncio_helper.promote_chat_member( self.token, chat_id, user_id, can_change_info, can_post_messages, diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index eae41a5..40a4ca9 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -11,7 +11,6 @@ API_URL = 'https://api.telegram.org/bot{0}/{1}' from datetime import datetime -import telebot from telebot import util, logger @@ -26,8 +25,6 @@ READ_TIMEOUT = 30 LONG_POLLING_TIMEOUT = 10 # Should be positive, short polling should be used for testing purposes only (https://core.telegram.org/bots/api#getupdates) REQUEST_TIMEOUT = 10 MAX_RETRIES = 3 -logger = telebot.logger - REQUEST_LIMIT = 50 @@ -1136,7 +1133,7 @@ async def set_my_default_administrator_rights(token, rights=None, for_channels=N payload = {} if rights: payload['rights'] = rights.to_json() - if for_channels: + if for_channels is not None: payload['for_channels'] = for_channels return await _process_request(token, method_url, params=payload, method='post') @@ -1543,7 +1540,6 @@ async def create_new_sticker_set( contains_masks=None, mask_position=None, webm_sticker=None): method_url = 'createNewStickerSet' payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis} - stype = None if png_sticker: stype = 'png_sticker' elif webm_sticker: @@ -1568,7 +1564,6 @@ async def create_new_sticker_set( async def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker): method_url = 'addStickerToSet' payload = {'user_id': user_id, 'name': name, 'emojis': emojis} - stype = None if png_sticker: stype = 'png_sticker' elif webm_sticker: diff --git a/telebot/types.py b/telebot/types.py index c659fd4..ef014bf 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -473,20 +473,20 @@ class Message(JsonDeserializable): 'proximity_alert_triggered']) content_type = 'proximity_alert_triggered' if 'video_chat_scheduled' in obj: - opts['video_chat_scheduled'] = VoiceChatScheduled.de_json(obj['video_chat_scheduled']) - opts['voice_chat_scheduled'] = opts['video_chat_scheduled'] + opts['video_chat_scheduled'] = VideoChatScheduled.de_json(obj['video_chat_scheduled']) + opts['voice_chat_scheduled'] = opts['video_chat_scheduled'] # deprecated, for backward compatibility content_type = 'video_chat_scheduled' if 'video_chat_started' in obj: - opts['video_chat_started'] = VoiceChatStarted.de_json(obj['video_chat_started']) - opts['voice_chat_started'] = opts['video_chat_started'] + opts['video_chat_started'] = VideoChatStarted.de_json(obj['video_chat_started']) + opts['voice_chat_started'] = opts['video_chat_started'] # deprecated, for backward compatibility content_type = 'video_chat_started' if 'video_chat_ended' in obj: - opts['video_chat_ended'] = VoiceChatEnded.de_json(obj['video_chat_ended']) - opts['voice_chat_ended'] = opts['video_chat_ended'] + opts['video_chat_ended'] = VideoChatEnded.de_json(obj['video_chat_ended']) + opts['voice_chat_ended'] = opts['video_chat_ended'] # deprecated, for backward compatibility content_type = 'video_chat_ended' if 'video_chat_participants_invited' in obj: - opts['video_chat_participants_invited'] = VoiceChatParticipantsInvited.de_json(obj['video_chat_participants_invited']) - opts['voice_chat_participants_invited'] = opts['video_chat_participants_invited'] + opts['video_chat_participants_invited'] = VideoChatParticipantsInvited.de_json(obj['video_chat_participants_invited']) + opts['voice_chat_participants_invited'] = opts['video_chat_participants_invited'] # deprecated, for backward compatibility content_type = 'video_chat_participants_invited' if 'web_app_data' in obj: opts['web_app_data'] = WebAppData.de_json(obj['web_app_data']) @@ -1304,7 +1304,7 @@ class ChatMember(JsonDeserializable): self.can_add_web_page_previews: bool = can_add_web_page_previews self.can_manage_chat: bool = can_manage_chat self.can_manage_video_chats: bool = can_manage_video_chats - self.can_manage_voice_chats: bool = self.can_manage_video_chats + self.can_manage_voice_chats: bool = self.can_manage_video_chats # deprecated, for backward compatibility self.until_date: int = until_date @@ -1743,11 +1743,14 @@ class SentWebAppMessage(JsonDeserializable): obj = cls.check_json(json_string) return cls(**obj) - def __init__(self, inline_message_id): + def __init__(self, inline_message_id=None): self.inline_message_id = inline_message_id def to_dict(self): - return {'inline_message_id': self.inline_message_id} + json_dict = {} + if self.inline_message_id: + json_dict['inline_message_id'] = self.inline_message_id + return json_dict @@ -2897,7 +2900,7 @@ class ProximityAlertTriggered(JsonDeserializable): self.distance: int = distance -class VoiceChatStarted(JsonDeserializable): +class VideoChatStarted(JsonDeserializable): @classmethod def de_json(cls, json_string): return cls() @@ -2909,8 +2912,13 @@ class VoiceChatStarted(JsonDeserializable): """ pass +class VoiceChatStarted(VideoChatStarted): + def __init__(self): + logger.warning('VoiceChatStarted is deprecated. Use VideoChatStarted instead.') + super().__init__() -class VoiceChatScheduled(JsonDeserializable): + +class VideoChatScheduled(JsonDeserializable): @classmethod def de_json(cls, json_string): if json_string is None: return None @@ -2920,8 +2928,13 @@ class VoiceChatScheduled(JsonDeserializable): def __init__(self, start_date, **kwargs): self.start_date: int = start_date +class VoiceChatScheduled(VideoChatScheduled): + def __init__(self, *args, **kwargs): + logger.warning('VoiceChatScheduled is deprecated. Use VideoChatScheduled instead.') + super().__init__(*args, **kwargs) -class VoiceChatEnded(JsonDeserializable): + +class VideoChatEnded(JsonDeserializable): @classmethod def de_json(cls, json_string): if json_string is None: return None @@ -2931,8 +2944,14 @@ class VoiceChatEnded(JsonDeserializable): def __init__(self, duration, **kwargs): self.duration: int = duration +class VoiceChatEnded(VideoChatEnded): + def __init__(self, *args, **kwargs): + logger.warning('VoiceChatEnded is deprecated. Use VideoChatEnded instead.') + super().__init__(*args, **kwargs) -class VoiceChatParticipantsInvited(JsonDeserializable): + + +class VideoChatParticipantsInvited(JsonDeserializable): @classmethod def de_json(cls, json_string): if json_string is None: return None @@ -2944,6 +2963,11 @@ class VoiceChatParticipantsInvited(JsonDeserializable): def __init__(self, users=None, **kwargs): self.users: List[User] = users +class VoiceChatParticipantsInvited(VideoChatParticipantsInvited): + def __init__(self, *args, **kwargs): + logger.warning('VoiceChatParticipantsInvited is deprecated. Use VideoChatParticipantsInvited instead.') + super().__init__(*args, **kwargs) + class MessageAutoDeleteTimerChanged(JsonDeserializable): @classmethod @@ -3042,7 +3066,7 @@ class ChatAdministratorRights(JsonDeserializable, JsonSerializable): self.can_pin_messages: bool = can_pin_messages def to_dict(self): - data = { + json_dict = { 'is_anonymous': self.is_anonymous, 'can_manage_chat': self.can_manage_chat, 'can_delete_messages': self.can_delete_messages, @@ -3051,11 +3075,14 @@ class ChatAdministratorRights(JsonDeserializable, JsonSerializable): 'can_promote_members': self.can_promote_members, 'can_change_info': self.can_change_info, 'can_invite_users': self.can_invite_users, - 'can_post_messages': self.can_post_messages, - 'can_edit_messages': self.can_edit_messages, - 'can_pin_messages': self.can_pin_messages } - return data + if 'can_post_messages' is not None: + json_dict['can_post_messages'] = self.can_post_messages + if 'can_edit_messages' is not None: + json_dict['can_edit_messages'] = self.can_edit_messages + if 'can_pin_messages' is not None: + json_dict['can_pin_messages'] = self.can_pin_messages + return json_dict def to_json(self): return json.dumps(self.to_dict()) diff --git a/telebot/util.py b/telebot/util.py index 79ed2b1..f116d9e 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -40,8 +40,8 @@ content_type_media = [ content_type_service = [ 'new_chat_members', 'left_chat_member', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created', 'supergroup_chat_created', 'channel_chat_created', 'migrate_to_chat_id', 'migrate_from_chat_id', 'pinned_message', - 'proximity_alert_triggered', 'voice_chat_scheduled', 'voice_chat_started', 'voice_chat_ended', - 'voice_chat_participants_invited', 'message_auto_delete_timer_changed' + 'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started', 'video_chat_ended', + 'video_chat_participants_invited', 'message_auto_delete_timer_changed' ] update_types = [ @@ -449,17 +449,22 @@ def generate_random_token(): return ''.join(random.sample(string.ascii_letters, 16)) -def deprecated(warn: bool=True, alternative: Optional[Callable]=None): +def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecation_text=None): """ Use this decorator to mark functions as deprecated. When the function is used, an info (or warning if `warn` is True) is logged. :param warn: If True a warning is logged else an info :param alternative: The new function to use instead + :param deprecation_text: Custom deprecation text """ def decorator(function): def wrapper(*args, **kwargs): - info = f"`{function.__name__}` is deprecated." + (f" Use `{alternative.__name__}` instead" if alternative else "") + info = f"`{function.__name__}` is deprecated." + if alternative: + info += f" Use `{alternative.__name__}` instead" + if deprecation_text: + info += " " + deprecation_text if not warn: logger.info(info) else: