mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-11-21 22:56:38 +01:00
Read-Only CallbackDataCache
(#3266)
This commit is contained in:
parent
870a20e834
commit
fb87418473
15 changed files with 158 additions and 87 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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."
|
||||
)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 <telegram.ext.CallbackDataCache.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:
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in a new issue