Add Version to PTBDeprecationWarning (#4262)

This commit is contained in:
Harshil 2024-05-20 10:12:34 -04:00 committed by GitHub
parent 7d952d8707
commit 512a0b7417
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 150 additions and 70 deletions

View file

@ -524,7 +524,10 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
@classmethod
def _warn(
cls, message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0
cls,
message: Union[str, PTBUserWarning],
category: Type[Warning] = PTBUserWarning,
stacklevel: int = 0,
) -> None:
"""Convenience method to issue a warning. This method is here mostly to make it easier
for ExtBot to add 1 level to all warning calls.
@ -837,7 +840,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
f"Please use 'Bot.{endpoint}' instead of "
f"'Bot.do_api_request(\"{endpoint}\", ...)'"
),
PTBDeprecationWarning,
stacklevel=2,
)
@ -4209,10 +4211,12 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
except NotImplementedError:
arg_read_timeout = 2
self._warn(
f"The class {self._request[0].__class__.__name__} does not override "
"the property `read_timeout`. Overriding this property will be mandatory in "
"future versions. Using 2 seconds as fallback.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.7",
f"The class {self._request[0].__class__.__name__} does not override "
"the property `read_timeout`. Overriding this property will be mandatory "
"in future versions. Using 2 seconds as fallback.",
),
stacklevel=2,
)

View file

@ -910,10 +910,12 @@ class Chat(TelegramObject):
for arg in _deprecated_attrs:
if (val := object.__getattribute__(self, arg)) is not None and val != ():
warn(
f"The argument `{arg}` is deprecated and will only be available via "
"`ChatFullInfo` in the future.",
PTBDeprecationWarning(
"NEXT.VERSION",
f"The argument `{arg}` is deprecated and will only be available via "
"`ChatFullInfo` in the future.",
),
stacklevel=2,
category=PTBDeprecationWarning,
)
self._id_attrs = (self.id,)
@ -923,10 +925,12 @@ class Chat(TelegramObject):
def __getattribute__(self, name: str) -> Any:
if name in _deprecated_attrs and self.__class__ is Chat:
warn(
f"The attribute `{name}` is deprecated and will only be accessible via "
"`ChatFullInfo` in the future.",
PTBDeprecationWarning(
"NEXT.VERSION",
f"The attribute `{name}` is deprecated and will only be accessible via "
"`ChatFullInfo` in the future.",
),
stacklevel=2,
category=PTBDeprecationWarning,
)
return super().__getattribute__(name)

View file

@ -1579,9 +1579,11 @@ class Message(MaybeInaccessibleMessage):
if quote is not None:
warn(
"The `quote` parameter is deprecated in favor of the `do_quote` parameter. Please "
"update your code to use `do_quote` instead.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.8",
"The `quote` parameter is deprecated in favor of the `do_quote` parameter. "
"Please update your code to use `do_quote` instead.",
),
stacklevel=2,
)

View file

@ -210,9 +210,11 @@ class PassportElementErrorFiles(PassportElementError):
This attribute will return a tuple instead of a list in future major versions.
"""
warn(
"The attribute `file_hashes` will return a tuple instead of a list in future major"
" versions.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.6",
"The attribute `file_hashes` will return a tuple instead of a list in future major"
" versions.",
),
stacklevel=2,
)
return self._file_hashes
@ -427,10 +429,12 @@ class PassportElementErrorTranslationFiles(PassportElementError):
This attribute will return a tuple instead of a list in future major versions.
"""
warn(
"The attribute `file_hashes` will return a tuple instead of a list in future major"
" versions. See the stability policy:"
" https://docs.python-telegram-bot.org/en/stable/stability_policy.html",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.6",
"The attribute `file_hashes` will return a tuple instead of a list in future major"
" versions. See the stability policy:"
" https://docs.python-telegram-bot.org/en/stable/stability_policy.html",
),
stacklevel=2,
)
return self._file_hashes

View file

@ -107,9 +107,11 @@ class PassportFile(TelegramObject):
This attribute will return a datetime instead of a integer in future major versions.
"""
warn(
"The attribute `file_date` will return a datetime instead of an integer in future"
" major versions.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.6",
"The attribute `file_date` will return a datetime instead of an integer in future"
" major versions.",
),
stacklevel=2,
)
return self._file_date

View file

@ -26,19 +26,28 @@ Warning:
the changelog.
"""
import warnings
from typing import Type
from typing import Type, Union
from telegram.warnings import PTBUserWarning
def warn(message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0) -> None:
def warn(
message: Union[str, PTBUserWarning],
category: Type[Warning] = PTBUserWarning,
stacklevel: int = 0,
) -> None:
"""
Helper function used as a shortcut for warning with default values.
.. versionadded:: 20.0
Args:
message (:obj:`str`): Specify the warnings message to pass to ``warnings.warn()``.
message (:obj:`str` | :obj:`PTBUserWarning`): Specify the warnings message to pass to
``warnings.warn()``.
.. versionchanged:: NEXT.VERSION
Now also accepts a :obj:`PTBUserWarning` instance.
category (:obj:`Type[Warning]`, optional): Specify the Warning class to pass to
``warnings.warn()``. Defaults to :class:`telegram.warnings.PTBUserWarning`.
stacklevel (:obj:`int`, optional): Specify the stacklevel to pass to ``warnings.warn()``.

View file

@ -23,10 +23,10 @@ inside warnings.py.
.. versionadded:: 20.2
"""
from typing import Any, Callable, Type
from typing import Any, Callable, Type, Union
from telegram._utils.warnings import warn
from telegram.warnings import PTBDeprecationWarning
from telegram.warnings import PTBDeprecationWarning, PTBUserWarning
def build_deprecation_warning_message(
@ -54,8 +54,9 @@ def warn_about_deprecated_arg_return_new_arg(
deprecated_arg_name: str,
new_arg_name: str,
bot_api_version: str,
ptb_version: str,
stacklevel: int = 2,
warn_callback: Callable[[str, Type[Warning], int], None] = warn,
warn_callback: Callable[[Union[str, PTBUserWarning], Type[Warning], int], None] = warn,
) -> Any:
"""A helper function for the transition in API when argument is renamed.
@ -80,10 +81,12 @@ def warn_about_deprecated_arg_return_new_arg(
if deprecated_arg:
warn_callback(
f"Bot API {bot_api_version} renamed the argument '{deprecated_arg_name}' to "
f"'{new_arg_name}'.",
PTBDeprecationWarning,
stacklevel + 1,
PTBDeprecationWarning(
ptb_version,
f"Bot API {bot_api_version} renamed the argument '{deprecated_arg_name}' to "
f"'{new_arg_name}'.",
),
stacklevel=stacklevel + 1, # type: ignore[call-arg]
)
return deprecated_arg
@ -94,6 +97,7 @@ def warn_about_deprecated_attr_in_property(
deprecated_attr_name: str,
new_attr_name: str,
bot_api_version: str,
ptb_version: str,
stacklevel: int = 2,
) -> None:
"""A helper function for the transition in API when attribute is renamed. Call from properties.
@ -101,8 +105,10 @@ def warn_about_deprecated_attr_in_property(
The properties replace deprecated attributes in classes and issue these deprecation warnings.
"""
warn(
f"Bot API {bot_api_version} renamed the attribute '{deprecated_attr_name}' to "
f"'{new_attr_name}'.",
PTBDeprecationWarning,
PTBDeprecationWarning(
ptb_version,
f"Bot API {bot_api_version} renamed the attribute '{deprecated_attr_name}' to "
f"'{new_attr_name}'.",
),
stacklevel=stacklevel + 1,
)

View file

@ -857,9 +857,11 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
if (read_timeout, write_timeout, connect_timeout, pool_timeout) != ((DEFAULT_NONE,) * 4):
warn(
"Setting timeouts via `Application.run_polling` is deprecated. "
"Please use `ApplicationBuilder.get_updates_*_timeout` instead.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.6",
"Setting timeouts via `Application.run_polling` is deprecated. "
"Please use `ApplicationBuilder.get_updates_*_timeout` instead.",
),
stacklevel=2,
)
@ -1183,9 +1185,11 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica
# Generator-based coroutines are not supported in Python 3.12+
if sys.version_info < (3, 12) and isinstance(coroutine, Generator):
warn(
"Generator-based coroutines are deprecated in create_task and will not work"
" in Python 3.12+",
category=PTBDeprecationWarning,
PTBDeprecationWarning(
"20.4",
"Generator-based coroutines are deprecated in create_task and will not"
" work in Python 3.12+",
),
)
return await asyncio.create_task(coroutine)
# If user uses generator in python 3.12+, Exception will happen and we cannot do

View file

@ -528,9 +528,11 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
:class:`ApplicationBuilder`: The same builder with the updated argument.
"""
warn(
"`ApplicationBuilder.proxy_url` is deprecated since version "
"20.7. Use `ApplicationBuilder.proxy` instead.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.7",
"`ApplicationBuilder.proxy_url` is deprecated. Use `ApplicationBuilder.proxy` "
"instead.",
),
stacklevel=2,
)
return self.proxy(proxy_url)
@ -760,9 +762,11 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
:class:`ApplicationBuilder`: The same builder with the updated argument.
"""
warn(
"`ApplicationBuilder.get_updates_proxy_url` is deprecated since version "
"20.7. Use `ApplicationBuilder.get_updates_proxy` instead.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.7",
"`ApplicationBuilder.get_updates_proxy_url` is deprecated. Use "
"`ApplicationBuilder.get_updates_proxy` instead.",
),
stacklevel=2,
)
return self.get_updates_proxy(get_updates_proxy_url)

View file

@ -156,9 +156,11 @@ class Defaults:
raise ValueError("`quote` and `do_quote` are mutually exclusive")
if disable_web_page_preview is not None:
warn(
"`Defaults.disable_web_page_preview` is deprecated. Use "
"`Defaults.link_preview_options` instead.",
category=PTBDeprecationWarning,
PTBDeprecationWarning(
"20.8",
"`Defaults.disable_web_page_preview` is deprecated. Use "
"`Defaults.link_preview_options` instead.",
),
stacklevel=2,
)
self._link_preview_options: Optional[LinkPreviewOptions] = LinkPreviewOptions(
@ -169,8 +171,9 @@ class Defaults:
if quote is not None:
warn(
"`Defaults.quote` is deprecated. Use `Defaults.do_quote` instead.",
category=PTBDeprecationWarning,
PTBDeprecationWarning(
"20.8", "`Defaults.quote` is deprecated. Use `Defaults.do_quote` instead."
),
stacklevel=2,
)
self._do_quote: Optional[bool] = quote

View file

@ -263,7 +263,10 @@ class ExtBot(Bot, Generic[RLARGS]):
@classmethod
def _warn(
cls, message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0
cls,
message: Union[str, PTBUserWarning],
category: Type[Warning] = PTBUserWarning,
stacklevel: int = 0,
) -> None:
"""We override this method to add one more level to the stacklevel, so that the warning
points to the user's code, not to the PTB code.

View file

@ -318,10 +318,12 @@ class BaseRequest(
and isinstance(write_timeout, DefaultValue)
):
warn(
f"The `write_timeout` parameter passed to {self.__class__.__name__}.do_request "
"will default to `BaseRequest.DEFAULT_NONE` instead of 20 in future versions "
"for *all* methods of the `Bot` class, including methods sending media.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.7",
f"The `write_timeout` parameter passed to {self.__class__.__name__}.do_request"
" will default to `BaseRequest.DEFAULT_NONE` instead of 20 in future versions "
"for *all* methods of the `Bot` class, including methods sending media.",
),
stacklevel=3,
)
write_timeout = 20

View file

@ -146,9 +146,9 @@ class HTTPXRequest(BaseRequest):
if proxy_url is not None:
proxy = proxy_url
warn(
"The parameter `proxy_url` is deprecated since version 20.7. Use `proxy` "
"instead.",
PTBDeprecationWarning,
PTBDeprecationWarning(
"20.7", "The parameter `proxy_url` is deprecated. Use `proxy` instead."
),
stacklevel=2,
)

View file

@ -54,6 +54,34 @@ class PTBDeprecationWarning(PTBUserWarning, DeprecationWarning):
.. versionchanged:: 20.0
Renamed TelegramDeprecationWarning to PTBDeprecationWarning.
Args:
version (:obj:`str`): The version in which the feature was deprecated.
.. versionadded:: NEXT.VERSION
message (:obj:`str`): The message to display.
.. versionadded:: NEXT.VERSION
Attributes:
version (:obj:`str`): The version in which the feature was deprecated.
.. versionadded:: NEXT.VERSION
message (:obj:`str`): The message to display.
.. versionadded:: NEXT.VERSION
"""
__slots__ = ()
__slots__ = ("message", "version")
def __init__(self, version: str, message: str) -> None:
self.version: str = version
self.message: str = message
def __str__(self) -> str:
"""Returns a string representation of the warning, using :attr:`message` and
:attr:`version`.
.. versionadded:: NEXT.VERSION
"""
return f"Deprecated since version {self.version}: {self.message}"

View file

@ -2105,6 +2105,7 @@ class TestBotWithoutRequest:
monkeypatch.setattr(bot.request, "post", make_assertion)
assert await bot.do_api_request("camel_case")
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
async def test_do_api_request_media_write_timeout(self, bot, chat_id, monkeypatch):
test_flag = None
@ -2143,6 +2144,7 @@ class TestBotWithoutRequest:
DEFAULT_NONE,
)
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
async def test_do_api_request_default_timezone(self, tz_bot, monkeypatch):
until = dtm.datetime(2020, 1, 11, 16, 13)
until_timestamp = to_timestamp(until, tzinfo=tz_bot.defaults.tzinfo)
@ -4090,7 +4092,7 @@ class TestBotWithRequest:
@pytest.mark.parametrize("bot_class", [Bot, ExtBot])
async def test_do_api_request_warning_known_method(self, bot, bot_class):
with pytest.warns(PTBDeprecationWarning, match="Please use 'Bot.get_me'") as record:
with pytest.warns(PTBUserWarning, match="Please use 'Bot.get_me'") as record:
await bot_class(bot.token).do_api_request("get_me")
assert record[0].filename == __file__, "Wrong stack level!"
@ -4099,6 +4101,7 @@ class TestBotWithRequest:
with pytest.raises(EndPointNotFound, match="'unknownEndpoint' not found"):
await bot.do_api_request("unknown_endpoint")
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
async def test_do_api_request_invalid_token(self, bot):
# we do not initialize the bot here on purpose b/c that's the case were we actually
# do not know for sure if the token is invalid or the method was not found
@ -4113,6 +4116,7 @@ class TestBotWithRequest:
):
await Bot(bot.token).do_api_request("unknown_endpoint")
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
@pytest.mark.parametrize("return_type", [Message, None])
async def test_do_api_request_basic_and_files(self, bot, chat_id, return_type):
result = await bot.do_api_request(
@ -4137,6 +4141,7 @@ class TestBotWithRequest:
assert out.read() == data_file("telegram.png").open("rb").read()
assert result.document.file_name == "telegram.png"
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
@pytest.mark.parametrize("return_type", [Message, None])
async def test_do_api_request_list_return_type(self, bot, chat_id, return_type):
result = await bot.do_api_request(
@ -4175,6 +4180,7 @@ class TestBotWithRequest:
assert out.read() == data_file(file_name).open("rb").read()
assert message.document.file_name == file_name
@pytest.mark.filterwarnings("ignore::telegram.warnings.PTBUserWarning")
@pytest.mark.parametrize("return_type", [Message, None])
async def test_do_api_request_bool_return_type(self, bot, chat_id, return_type):
assert await bot.do_api_request("delete_my_commands", return_type=return_type) is True

View file

@ -33,7 +33,7 @@ class TestWarnings:
[
(PTBUserWarning("test message")),
(PTBRuntimeWarning("test message")),
(PTBDeprecationWarning()),
(PTBDeprecationWarning("20.6", "test message")),
],
)
def test_slots_behavior(self, inst):
@ -80,9 +80,8 @@ class TestWarnings:
assert str(recwarn[1].message) == "test message 2"
assert Path(recwarn[1].filename) == expected_file, "incorrect stacklevel!"
warn("test message 3", stacklevel=1, category=PTBDeprecationWarning)
expected_file = Path(__file__)
warn(PTBDeprecationWarning("20.6", "test message 3"), stacklevel=1)
assert len(recwarn) == 3
assert recwarn[2].category is PTBDeprecationWarning
assert str(recwarn[2].message) == "test message 3"
assert Path(recwarn[2].filename) == expected_file, "incorrect stacklevel!"
assert str(recwarn[2].message) == "Deprecated since version 20.6: test message 3"
assert Path(recwarn[2].filename) == Path(__file__), "incorrect stacklevel!"