diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index 331b8e80..6653cf89 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -8,7 +8,7 @@ import warnings from .base import BaseBot, api from .. import types from ..types import base -from ..utils.deprecated import deprecated +from ..utils.deprecated import deprecated, removed_argument from ..utils.exceptions import ValidationError from ..utils.mixins import DataMixin, ContextInstanceMixin from ..utils.payload import generate_payload, prepare_arg, prepare_attachment, prepare_file @@ -1814,6 +1814,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): return await self.request(api.Methods.SET_CHAT_ADMINISTRATOR_CUSTOM_TITLE, payload) + @removed_argument("until_date", "2.19") async def ban_chat_sender_chat( self, chat_id: typing.Union[base.Integer, base.String], diff --git a/aiogram/utils/deprecated.py b/aiogram/utils/deprecated.py index 6d0d7ee3..186fe6cc 100644 --- a/aiogram/utils/deprecated.py +++ b/aiogram/utils/deprecated.py @@ -131,6 +131,57 @@ def renamed_argument(old_name: str, new_name: str, until_version: str, stackleve return decorator +def removed_argument(name: str, until_version: str, stacklevel: int = 3): + """ + A meta-decorator to mark an argument as removed. + + .. code-block:: python3 + + @removed_argument("until_date", "3.0") # stacklevel=3 by default + def some_function(user_id, chat_id=None): + print(f"user_id={user_id}, chat_id={chat_id}") + + :param name: + :param until_version: the version in which the argument is scheduled to be removed + :param stacklevel: leave it to default if it's the first decorator used. + Increment with any new decorator used. + :return: decorator + """ + + def decorator(func): + is_coroutine = asyncio.iscoroutinefunction(func) + + def _handling(kwargs): + """ + Returns updated version of kwargs. + """ + routine_type = 'coroutine' if is_coroutine else 'function' + if name in kwargs: + warn_deprecated( + f"In {routine_type} {func.__name__!r} argument {name!r} " + f"is planned to be removed in aiogram {until_version}", + stacklevel=stacklevel, + ) + kwargs = kwargs.copy() + del kwargs[name] + return kwargs + + if is_coroutine: + @functools.wraps(func) + async def wrapped(*args, **kwargs): + kwargs = _handling(kwargs) + return await func(*args, **kwargs) + else: + @functools.wraps(func) + def wrapped(*args, **kwargs): + kwargs = _handling(kwargs) + return func(*args, **kwargs) + + return wrapped + + return decorator + + _VT = TypeVar("_VT") _OwnerCls = TypeVar("_OwnerCls")