From fb8741847334cf1301ef480b494805004a40d77e Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:18:08 +0200 Subject: [PATCH] Read-Only `CallbackDataCache` (#3266) --- docs/source/telegram.ext.extbot.rst | 2 +- telegram/_callbackquery.py | 2 +- telegram/ext/_application.py | 7 +-- telegram/ext/_basepersistence.py | 12 +++-- telegram/ext/_callbackcontext.py | 2 +- telegram/ext/_callbackdatacache.py | 44 ++++++++++++---- telegram/ext/_extbot.py | 41 ++++++++++----- tests/conftest.py | 7 +++ tests/test_applicationbuilder.py | 5 +- tests/test_basepersistence.py | 12 ++++- tests/test_bot.py | 79 ++++++++++++++++------------- tests/test_callbackdatacache.py | 1 + tests/test_dictpersistence.py | 7 ++- tests/test_picklepersistence.py | 19 ++++--- tests/test_updater.py | 5 +- 15 files changed, 158 insertions(+), 87 deletions(-) diff --git a/docs/source/telegram.ext.extbot.rst b/docs/source/telegram.ext.extbot.rst index 5388df5e9..ae441ec05 100644 --- a/docs/source/telegram.ext.extbot.rst +++ b/docs/source/telegram.ext.extbot.rst @@ -3,4 +3,4 @@ telegram.ext.ExtBot .. autoclass:: telegram.ext.ExtBot :show-inheritance: - :members: insert_callback_data, defaults, rate_limiter, initialize, shutdown + :members: insert_callback_data, defaults, rate_limiter, initialize, shutdown, callback_data_cache diff --git a/telegram/_callbackquery.py b/telegram/_callbackquery.py index 111cc6f7e..874bce80e 100644 --- a/telegram/_callbackquery.py +++ b/telegram/_callbackquery.py @@ -57,7 +57,7 @@ class CallbackQuery(TelegramObject): until you call :attr:`answer`. It is, therefore, necessary to react by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user is needed (e.g., without specifying any of the optional parameters). - * If you're using :attr:`telegram.ext.ExtBot.arbitrary_callback_data`, :attr:`data` may be + * If you're using :attr:`telegram.ext.ExtBot.callback_data_cache`, :attr:`data` may be an instance of :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data associated with the button triggering the :class:`telegram.CallbackQuery` was already diff --git a/telegram/ext/_application.py b/telegram/ext/_application.py index ae2b72451..017a36d87 100644 --- a/telegram/ext/_application.py +++ b/telegram/ext/_application.py @@ -54,7 +54,6 @@ from telegram._utils.types import DVInput, ODVInput from telegram._utils.warnings import warn from telegram.error import TelegramError from telegram.ext._basepersistence import BasePersistence -from telegram.ext._callbackdatacache import CallbackDataCache from telegram.ext._contexttypes import ContextTypes from telegram.ext._extbot import ExtBot from telegram.ext._handler import BaseHandler @@ -440,10 +439,8 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AbstractAsyncContextManager) raise ValueError("callback_data must be a tuple of length 2") # Mypy doesn't know that persistence.set_bot (see above) already checks that # self.bot is an instance of ExtBot if callback_data should be stored ... - self.bot.callback_data_cache = CallbackDataCache( # type: ignore[attr-defined] - self.bot, # type: ignore[arg-type] - self.bot.callback_data_cache.maxsize, # type: ignore[attr-defined] - persistent_data=persistent_data, + self.bot.callback_data_cache.load_persistence_data( # type: ignore[attr-defined] + persistent_data ) @staticmethod diff --git a/telegram/ext/_basepersistence.py b/telegram/ext/_basepersistence.py index b70f1794f..387228da5 100644 --- a/telegram/ext/_basepersistence.py +++ b/telegram/ext/_basepersistence.py @@ -174,10 +174,16 @@ class BasePersistence(Generic[UD, CD, BD], ABC): Raises: :exc:`TypeError`: If :attr:`PersistenceInput.callback_data` is :obj:`True` and the - :paramref:`bot` is not an instance of :class:`telegram.ext.ExtBot`. + :paramref:`bot` is not an instance of :class:`telegram.ext.ExtBot` or + :attr:`~telegram.ext.ExtBot.callback_data_cache` is :obj:`None`. """ - if self.store_data.callback_data and not isinstance(bot, ExtBot): - raise TypeError("callback_data can only be stored when using telegram.ext.ExtBot.") + if self.store_data.callback_data and ( + not isinstance(bot, ExtBot) or bot.callback_data_cache is None + ): + raise TypeError( + "callback_data can only be stored when using telegram.ext.ExtBot with arbitrary " + "callback_data enabled. " + ) self.bot = bot diff --git a/telegram/ext/_callbackcontext.py b/telegram/ext/_callbackcontext.py index d2315726f..3e408a05c 100644 --- a/telegram/ext/_callbackcontext.py +++ b/telegram/ext/_callbackcontext.py @@ -235,7 +235,7 @@ class CallbackContext(Generic[BT, UD, CD, BD]): callback data. """ if isinstance(self.bot, ExtBot): - if not self.bot.arbitrary_callback_data: + if self.bot.callback_data_cache is None: raise RuntimeError( "This telegram.ext.ExtBot instance does not use arbitrary callback data." ) diff --git a/telegram/ext/_callbackdatacache.py b/telegram/ext/_callbackdatacache.py index 06c1c8af7..8f5f18821 100644 --- a/telegram/ext/_callbackdatacache.py +++ b/telegram/ext/_callbackdatacache.py @@ -113,11 +113,10 @@ class CallbackDataCache: Attributes: bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. - maxsize (:obj:`int`): maximum size of the cache. """ - __slots__ = ("bot", "maxsize", "_keyboard_data", "_callback_queries", "logger") + __slots__ = ("bot", "_maxsize", "_keyboard_data", "_callback_queries", "logger") def __init__( self, @@ -128,18 +127,43 @@ class CallbackDataCache: self.logger = logging.getLogger(__name__) self.bot = bot - self.maxsize = maxsize + self._maxsize = maxsize self._keyboard_data: MutableMapping[str, _KeyboardData] = LRUCache(maxsize=maxsize) self._callback_queries: MutableMapping[str, str] = LRUCache(maxsize=maxsize) if persistent_data: - keyboard_data, callback_queries = persistent_data - for key, value in callback_queries.items(): - self._callback_queries[key] = value - for uuid, access_time, data in keyboard_data: - self._keyboard_data[uuid] = _KeyboardData( - keyboard_uuid=uuid, access_time=access_time, button_data=data - ) + self.load_persistence_data(persistent_data) + + def load_persistence_data(self, persistent_data: CDCData) -> None: + """Loads data into the cache. + + Warning: + This method is not intended to be called by users directly. + + .. versionadded:: 20.0 + + Args: + persistent_data (Tuple[List[Tuple[:obj:`str`, :obj:`float`, \ + Dict[:obj:`str`, :class:`object`]]], Dict[:obj:`str`, :obj:`str`]], optional): \ + Data to load, as returned by \ + :meth:`telegram.ext.BasePersistence.get_callback_data`. + """ + keyboard_data, callback_queries = persistent_data + for key, value in callback_queries.items(): + self._callback_queries[key] = value + for uuid, access_time, data in keyboard_data: + self._keyboard_data[uuid] = _KeyboardData( + keyboard_uuid=uuid, access_time=access_time, button_data=data + ) + + @property + def maxsize(self) -> int: + """:obj:`int`: The maximum size of the cache. + + .. versionchanged:: 20.0 + This property is now read-only. + """ + return self._maxsize @property def persistence_data(self) -> CDCData: diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py index 37ea55025..246fefb38 100644 --- a/telegram/ext/_extbot.py +++ b/telegram/ext/_extbot.py @@ -124,6 +124,11 @@ class ExtBot(Bot, Generic[RLARGS]): .. versionadded:: 13.6 + .. versionchanged:: 20.0 + Removed the attribute ``arbitrary_callback_data``. You can instead use + :attr:`bot.callback_data_cache.maxsize ` to + access the size of the cache. + Args: defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to be used if not set explicitly in the bot methods. @@ -137,16 +142,9 @@ class ExtBot(Bot, Generic[RLARGS]): .. versionadded:: 20.0 - Attributes: - arbitrary_callback_data (:obj:`bool` | :obj:`int`): Whether this bot instance - allows to use arbitrary objects as callback data for - :class:`telegram.InlineKeyboardButton`. - callback_data_cache (:class:`telegram.ext.CallbackDataCache`): The cache for objects passed - as callback data for :class:`telegram.InlineKeyboardButton`. - """ - __slots__ = ("arbitrary_callback_data", "callback_data_cache", "_defaults", "_rate_limiter") + __slots__ = ("_callback_data_cache", "_defaults", "_rate_limiter") # using object() would be a tiny bit safer, but a string plays better with the typing setup __RL_KEY = uuid4().hex @@ -210,15 +208,30 @@ class ExtBot(Bot, Generic[RLARGS]): ) self._defaults = defaults self._rate_limiter = rate_limiter + self._callback_data_cache: Optional[CallbackDataCache] = None # set up callback_data + if arbitrary_callback_data is False: + return + if not isinstance(arbitrary_callback_data, bool): maxsize = cast(int, arbitrary_callback_data) - self.arbitrary_callback_data = True else: maxsize = 1024 - self.arbitrary_callback_data = arbitrary_callback_data - self.callback_data_cache: CallbackDataCache = CallbackDataCache(bot=self, maxsize=maxsize) + + self._callback_data_cache = CallbackDataCache(bot=self, maxsize=maxsize) + + @property + def callback_data_cache(self) -> Optional[CallbackDataCache]: + """:class:`telegram.ext.CallbackDataCache`: Optional. The cache for + objects passed as callback data for :class:`telegram.InlineKeyboardButton`. + + .. versionchanged:: 20.0 + * This property is now read-only. + * This property is now optional and can be :obj:`None` if + :paramref:`~telegram.ext.ExtBot.arbitrary_callback_data` is set to :obj:`False`. + """ + return self._callback_data_cache async def initialize(self) -> None: """See :meth:`telegram.Bot.initialize`. Also initializes the @@ -366,7 +379,7 @@ class ExtBot(Bot, Generic[RLARGS]): def _replace_keyboard(self, reply_markup: Optional[ReplyMarkup]) -> Optional[ReplyMarkup]: # If the reply_markup is an inline keyboard and we allow arbitrary callback data, let the # CallbackDataCache build a new keyboard with the data replaced. Otherwise return the input - if isinstance(reply_markup, InlineKeyboardMarkup) and self.arbitrary_callback_data: + if isinstance(reply_markup, InlineKeyboardMarkup) and self.callback_data_cache is not None: return self.callback_data_cache.process_keyboard(reply_markup) return reply_markup @@ -405,7 +418,7 @@ class ExtBot(Bot, Generic[RLARGS]): self._insert_callback_data(update.effective_message) def _insert_callback_data(self, obj: HandledTypes) -> HandledTypes: - if not self.arbitrary_callback_data: + if self.callback_data_cache is None: return obj if isinstance(obj, CallbackQuery): @@ -514,7 +527,7 @@ class ExtBot(Bot, Generic[RLARGS]): ) # Process arbitrary callback - if not self.arbitrary_callback_data: + if self.callback_data_cache is None: return effective_results, next_offset results = [] for result in effective_results: diff --git a/tests/conftest.py b/tests/conftest.py index 2515d6a58..6a001153d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -158,6 +158,13 @@ async def bot(bot_info): yield _bot +@pytest.fixture(scope="session") +async def cdc_bot(bot_info): + """Makes an ExtBot instance with the given bot_info that uses arbitrary callback_data""" + async with make_bot(bot_info, arbitrary_callback_data=True) as _bot: + yield _bot + + @pytest.fixture(scope="session") async def raw_bot(bot_info): """Makes an regular Bot instance with the given bot_info""" diff --git a/tests/test_applicationbuilder.py b/tests/test_applicationbuilder.py index c4930e39d..b2d08893b 100644 --- a/tests/test_applicationbuilder.py +++ b/tests/test_applicationbuilder.py @@ -26,6 +26,7 @@ from telegram.ext import ( AIORateLimiter, Application, ApplicationBuilder, + CallbackDataCache, ContextTypes, Defaults, ExtBot, @@ -81,7 +82,7 @@ class TestApplicationBuilder: assert "api.telegram.org" in app.bot.base_file_url assert bot.token in app.bot.base_file_url assert app.bot.private_key is None - assert app.bot.arbitrary_callback_data is False + assert app.bot.callback_data_cache is None assert app.bot.defaults is None assert app.bot.rate_limiter is None assert app.bot.local_mode is False @@ -346,6 +347,7 @@ class TestApplicationBuilder: .concurrent_updates(concurrent_updates) .post_init(post_init) .post_shutdown(post_shutdown) + .arbitrary_callback_data(True) ).build() assert app.job_queue is job_queue assert app.job_queue.application is app @@ -358,6 +360,7 @@ class TestApplicationBuilder: assert app.concurrent_updates == concurrent_updates assert app.post_init is post_init assert app.post_shutdown is post_shutdown + assert isinstance(app.bot.callback_data_cache, CallbackDataCache) updater = Updater(bot=bot, update_queue=update_queue) app = ApplicationBuilder().updater(updater).build() diff --git a/tests/test_basepersistence.py b/tests/test_basepersistence.py index 9882066a3..f5db0437d 100644 --- a/tests/test_basepersistence.py +++ b/tests/test_basepersistence.py @@ -38,6 +38,7 @@ from telegram.ext import ( BasePersistence, CallbackContext, ConversationHandler, + ExtBot, MessageHandler, PersistenceInput, filters, @@ -390,6 +391,9 @@ class TestBasePersistence: with pytest.raises(TypeError, match="when using telegram.ext.ExtBot"): papp.persistence.set_bot(Bot(papp.bot.token)) + with pytest.raises(TypeError, match="when using telegram.ext.ExtBot"): + papp.persistence.set_bot(ExtBot(papp.bot.token)) + def test_construction_with_bad_persistence(self, caplog, bot): class MyPersistence: def __init__(self): @@ -1024,7 +1028,13 @@ class TestBasePersistence: test_flag.append(str(context.error) == "PersistenceError") raise Exception("ErrorHandlingError") - app = ApplicationBuilder().token(bot.token).persistence(ErrorPersistence()).build() + app = ( + ApplicationBuilder() + .token(bot.token) + .arbitrary_callback_data(True) + .persistence(ErrorPersistence()) + .build() + ) async with app: app.add_error_handler(error) diff --git a/tests/test_bot.py b/tests/test_bot.py index ad5c6dfd2..8e94e1cb1 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -284,13 +284,15 @@ class TestBot: assert caplog.records[-1].getMessage().startswith("Exiting: get_me") @pytest.mark.parametrize( - "acd_in,maxsize,acd", - [(True, 1024, True), (False, 1024, False), (0, 0, True), (None, None, True)], + "acd_in,maxsize", + [(True, 1024), (False, 1024), (0, 0), (None, None)], ) - async def test_callback_data_maxsize(self, bot, acd_in, maxsize, acd): + async def test_callback_data_maxsize(self, bot, acd_in, maxsize): async with ExtBot(bot.token, arbitrary_callback_data=acd_in) as acd_bot: - assert acd_bot.arbitrary_callback_data == acd - assert acd_bot.callback_data_cache.maxsize == maxsize + if acd_in is not False: + assert acd_bot.callback_data_cache.maxsize == maxsize + else: + assert acd_bot.callback_data_cache is None async def test_no_token_passed(self): with pytest.raises(InvalidToken, match="You must pass the token"): @@ -1542,7 +1544,9 @@ class TestBot: if updates: assert isinstance(updates[0], Update) - async def test_get_updates_invalid_callback_data(self, bot, monkeypatch): + async def test_get_updates_invalid_callback_data(self, cdc_bot, monkeypatch): + bot = cdc_bot + async def post(*args, **kwargs): return [ Update( @@ -1563,7 +1567,6 @@ class TestBot: ).to_dict() ] - bot.arbitrary_callback_data = True try: await bot.delete_webhook() # make sure there is no webhook set if webhook tests failed monkeypatch.setattr(BaseRequest, "post", post) @@ -1575,7 +1578,8 @@ class TestBot: finally: # Reset b/c bots scope is session - bot.arbitrary_callback_data = False + bot.callback_data_cache.clear_callback_data() + bot.callback_data_cache.clear_callback_queries() @flaky(3, 1) @pytest.mark.parametrize("use_ip", [True, False]) @@ -2618,9 +2622,10 @@ class TestBot: else: assert len(message.caption_entities) == 0 - async def test_replace_callback_data_send_message(self, bot, chat_id): + async def test_replace_callback_data_send_message(self, cdc_bot, chat_id): + bot = cdc_bot + try: - bot.arbitrary_callback_data = True replace_button = InlineKeyboardButton(text="replace", callback_data="replace_test") no_replace_button = InlineKeyboardButton( text="no_replace", url="http://python-telegram-bot.org/" @@ -2642,14 +2647,14 @@ class TestBot: data = list(bot.callback_data_cache._keyboard_data[keyboard].button_data.values())[0] assert data == "replace_test" finally: - bot.arbitrary_callback_data = False bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_queries() - async def test_replace_callback_data_stop_poll_and_repl_to_message(self, bot, chat_id): + async def test_replace_callback_data_stop_poll_and_repl_to_message(self, cdc_bot, chat_id): + bot = cdc_bot + poll_message = await bot.send_poll(chat_id=chat_id, question="test", options=["1", "2"]) try: - bot.arbitrary_callback_data = True replace_button = InlineKeyboardButton(text="replace", callback_data="replace_test") no_replace_button = InlineKeyboardButton( text="no_replace", url="http://python-telegram-bot.org/" @@ -2671,16 +2676,16 @@ class TestBot: data = list(bot.callback_data_cache._keyboard_data[keyboard].button_data.values())[0] assert data == "replace_test" finally: - bot.arbitrary_callback_data = False bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_queries() - async def test_replace_callback_data_copy_message(self, bot, chat_id): + async def test_replace_callback_data_copy_message(self, cdc_bot, chat_id): """This also tests that data is inserted into the buttons of message.reply_to_message where message is the return value of a bot method""" + bot = cdc_bot + original_message = await bot.send_message(chat_id=chat_id, text="original") try: - bot.arbitrary_callback_data = True replace_button = InlineKeyboardButton(text="replace", callback_data="replace_test") no_replace_button = InlineKeyboardButton( text="no_replace", url="http://python-telegram-bot.org/" @@ -2704,12 +2709,13 @@ class TestBot: data = list(bot.callback_data_cache._keyboard_data[keyboard].button_data.values())[0] assert data == "replace_test" finally: - bot.arbitrary_callback_data = False bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_queries() # TODO: Needs improvement. We need incoming inline query to test answer. - async def test_replace_callback_data_answer_inline_query(self, monkeypatch, bot, chat_id): + async def test_replace_callback_data_answer_inline_query(self, monkeypatch, cdc_bot, chat_id): + bot = cdc_bot + # For now just test that our internals pass the correct data async def make_assertion( endpoint, @@ -2732,7 +2738,6 @@ class TestBot: return assertion_1 and assertion_2 and assertion_3 and assertion_4 try: - bot.arbitrary_callback_data = True replace_button = InlineKeyboardButton(text="replace", callback_data="replace_test") no_replace_button = InlineKeyboardButton( text="no_replace", url="http://python-telegram-bot.org/" @@ -2760,13 +2765,13 @@ class TestBot: assert await bot.answer_inline_query(chat_id, results=results) finally: - bot.arbitrary_callback_data = False bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_queries() - async def test_get_chat_arbitrary_callback_data(self, super_group_id, bot): + async def test_get_chat_arbitrary_callback_data(self, super_group_id, cdc_bot): + bot = cdc_bot + try: - bot.arbitrary_callback_data = True reply_markup = InlineKeyboardMarkup.from_button( InlineKeyboardButton(text="text", callback_data="callback_data") ) @@ -2784,7 +2789,6 @@ class TestBot: assert chat.pinned_message == message assert chat.pinned_message.reply_markup == reply_markup finally: - bot.arbitrary_callback_data = False bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_queries() await bot.unpin_all_chat_messages(super_group_id) @@ -2793,8 +2797,9 @@ class TestBot: # The same must be done in the webhook updater. This is tested over at test_updater.py, but # here we test more extensively. - async def test_arbitrary_callback_data_no_insert(self, monkeypatch, bot): - """Updates that don't need insertion shouldn.t fail obviously""" + async def test_arbitrary_callback_data_no_insert(self, monkeypatch, cdc_bot): + """Updates that don't need insertion shouldn't fail obviously""" + bot = cdc_bot async def post(*args, **kwargs): update = Update( @@ -2813,7 +2818,6 @@ class TestBot: return [update.to_dict()] try: - bot.arbitrary_callback_data = True monkeypatch.setattr(BaseRequest, "post", post) await bot.delete_webhook() # make sure there is no webhook set if webhook tests failed updates = await bot.get_updates(timeout=1) @@ -2822,15 +2826,17 @@ class TestBot: assert updates[0].update_id == 17 assert updates[0].poll.id == "42" finally: - bot.arbitrary_callback_data = False + bot.callback_data_cache.clear_callback_data() + bot.callback_data_cache.clear_callback_queries() @pytest.mark.parametrize( "message_type", ["channel_post", "edited_channel_post", "message", "edited_message"] ) async def test_arbitrary_callback_data_pinned_message_reply_to_message( - self, super_group_id, bot, monkeypatch, message_type + self, super_group_id, cdc_bot, monkeypatch, message_type ): - bot.arbitrary_callback_data = True + bot = cdc_bot + reply_markup = InlineKeyboardMarkup.from_button( InlineKeyboardButton(text="text", callback_data="callback_data") ) @@ -2880,12 +2886,13 @@ class TestBot: ) finally: - bot.arbitrary_callback_data = False bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_queries() - async def test_arbitrary_callback_data_get_chat_no_pinned_message(self, super_group_id, bot): - bot.arbitrary_callback_data = True + async def test_arbitrary_callback_data_get_chat_no_pinned_message( + self, super_group_id, cdc_bot + ): + bot = cdc_bot await bot.unpin_all_chat_messages(super_group_id) try: @@ -2895,16 +2902,17 @@ class TestBot: assert int(chat.id) == int(super_group_id) assert chat.pinned_message is None finally: - bot.arbitrary_callback_data = False + bot.callback_data_cache.clear_callback_data() + bot.callback_data_cache.clear_callback_queries() @pytest.mark.parametrize( "message_type", ["channel_post", "edited_channel_post", "message", "edited_message"] ) @pytest.mark.parametrize("self_sender", [True, False]) async def test_arbitrary_callback_data_via_bot( - self, super_group_id, bot, monkeypatch, self_sender, message_type + self, super_group_id, cdc_bot, monkeypatch, self_sender, message_type ): - bot.arbitrary_callback_data = True + bot = cdc_bot reply_markup = InlineKeyboardMarkup.from_button( InlineKeyboardButton(text="text", callback_data="callback_data") ) @@ -2938,7 +2946,6 @@ class TestBot: == reply_markup.inline_keyboard[0][0].callback_data ) finally: - bot.arbitrary_callback_data = False bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_queries() diff --git a/tests/test_callbackdatacache.py b/tests/test_callbackdatacache.py index 7deced0c4..11603adae 100644 --- a/tests/test_callbackdatacache.py +++ b/tests/test_callbackdatacache.py @@ -74,6 +74,7 @@ class TestCallbackDataCache: assert cdc.bot is bot def test_init_and_access__persistent_data(self, bot): + """This also tests CDC.load_persistent_data.""" keyboard_data = _KeyboardData("123", 456, {"button": 678}) persistent_data = ([keyboard_data.to_tuple()], {"id": "123"}) cdc = CallbackDataCache(bot, persistent_data=persistent_data) diff --git a/tests/test_dictpersistence.py b/tests/test_dictpersistence.py index 4ec324c57..b6f38df74 100644 --- a/tests/test_dictpersistence.py +++ b/tests/test_dictpersistence.py @@ -24,11 +24,10 @@ from telegram.ext import DictPersistence @pytest.fixture(autouse=True) -def reset_callback_data_cache(bot): +def reset_callback_data_cache(cdc_bot): yield - bot.callback_data_cache.clear_callback_data() - bot.callback_data_cache.clear_callback_queries() - bot.arbitrary_callback_data = False + cdc_bot.callback_data_cache.clear_callback_data() + cdc_bot.callback_data_cache.clear_callback_queries() @pytest.fixture(scope="function") diff --git a/tests/test_picklepersistence.py b/tests/test_picklepersistence.py index f267f7324..70ebea1ba 100644 --- a/tests/test_picklepersistence.py +++ b/tests/test_picklepersistence.py @@ -41,11 +41,10 @@ def change_directory(tmp_path: Path): @pytest.fixture(autouse=True) -def reset_callback_data_cache(bot): +def reset_callback_data_cache(cdc_bot): yield - bot.callback_data_cache.clear_callback_data() - bot.callback_data_cache.clear_callback_queries() - bot.arbitrary_callback_data = False + cdc_bot.callback_data_cache.clear_callback_data() + cdc_bot.callback_data_cache.clear_callback_queries() @pytest.fixture(scope="function") @@ -850,10 +849,14 @@ class TestPicklePersistence: assert conversations_test["name1"] == conversation1 async def test_custom_pickler_unpickler_simple( - self, pickle_persistence, update, good_pickle_files, bot, recwarn + self, pickle_persistence, good_pickle_files, cdc_bot, recwarn ): + bot = cdc_bot + update = Update(1) + update.set_bot(bot) + pickle_persistence.set_bot(bot) # assign the current bot to the persistence - data_with_bot = {"current_bot": update.message} + data_with_bot = {"current_bot": update} await pickle_persistence.update_chat_data( 12345, data_with_bot ) # also calls BotPickler.dumps() @@ -887,8 +890,10 @@ class TestPicklePersistence: assert (await pp.get_chat_data())[12345]["unknown_bot_in_user"]._bot is None async def test_custom_pickler_unpickler_with_custom_objects( - self, bot, pickle_persistence, good_pickle_files + self, cdc_bot, pickle_persistence, good_pickle_files ): + bot = cdc_bot + dict_s = self.DictSub("private", "normal", bot) slot_s = self.SlotsSub("new_var", "private_var") regular = self.NormalClass(12) diff --git a/tests/test_updater.py b/tests/test_updater.py index 069331fb2..ec92ba650 100644 --- a/tests/test_updater.py +++ b/tests/test_updater.py @@ -693,11 +693,11 @@ class TestUpdater: @pytest.mark.parametrize("invalid_data", [True, False], ids=("invalid data", "valid data")) async def test_webhook_arbitrary_callback_data( - self, monkeypatch, updater, invalid_data, chat_id + self, monkeypatch, cdc_bot, invalid_data, chat_id ): """Here we only test one simple setup. telegram.ext.ExtBot.insert_callback_data is tested extensively in test_bot.py in conjunction with get_updates.""" - updater.bot.arbitrary_callback_data = True + updater = Updater(bot=cdc_bot, update_queue=asyncio.Queue()) async def return_true(*args, **kwargs): return True @@ -743,7 +743,6 @@ class TestUpdater: await updater.stop() finally: - updater.bot.arbitrary_callback_data = False updater.bot.callback_data_cache.clear_callback_data() updater.bot.callback_data_cache.clear_callback_queries()