Skip to content

Commit 2d95aee

Browse files
committed
Another rework. no tests & stuff yet.
1 parent 524d776 commit 2d95aee

14 files changed

+333
-222
lines changed

telegram/bot.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
InlineKeyboardMarkup,
8585
)
8686
from telegram.constants import MAX_INLINE_QUERY_RESULTS
87-
from telegram.error import InvalidToken, TelegramError, InvalidCallbackData
87+
from telegram.error import InvalidToken, TelegramError
8888
from telegram.utils.helpers import (
8989
DEFAULT_NONE,
9090
DefaultValue,
@@ -171,7 +171,7 @@ class Bot(TelegramObject):
171171
Warning:
172172
Not limiting :attr:`maxsize` may cause memory issues for long running bots. If you
173173
don't limit the size, you should be sure that every inline button is actually
174-
pressed or that you manually clear the cache using e.g. :meth:`clear`.
174+
pressed or that you manually clear the cache.
175175
176176
"""
177177

@@ -290,7 +290,7 @@ def _message(
290290
if reply_markup is not None:
291291
if isinstance(reply_markup, ReplyMarkup):
292292
if self.arbitrary_callback_data and isinstance(reply_markup, InlineKeyboardMarkup):
293-
reply_markup = reply_markup.replace_callback_data(bot=self)
293+
reply_markup = self.callback_data.put_keyboard(reply_markup)
294294
# We need to_json() instead of to_dict() here, because reply_markups may be
295295
# attached to media messages, which aren't json dumped by utils.request
296296
data['reply_markup'] = reply_markup.to_json()
@@ -2138,7 +2138,7 @@ def _set_defaults(res):
21382138
if hasattr(result, 'reply_markup') and isinstance(
21392139
result.reply_markup, InlineKeyboardMarkup # type: ignore[attr-defined]
21402140
):
2141-
markup = result.reply_markup.replace_callback_data(bot=self) # type: ignore
2141+
markup = self.callback_data.put_keyboard(result.reply_markup) # type: ignore
21422142
result.reply_markup = markup # type: ignore[attr-defined]
21432143

21442144
results_dicts = [res.to_dict() for res in effective_results]
@@ -2739,8 +2739,6 @@ def get_updates(
27392739
2. In order to avoid getting duplicate updates, recalculate offset after each
27402740
server response.
27412741
3. To take full advantage of this library take a look at :class:`telegram.ext.Updater`
2742-
4. Updates causing :class:`telegram.error.InvalidCallbackData` will be logged and not
2743-
returned.
27442742
27452743
Returns:
27462744
List[:class:`telegram.Update`]
@@ -2778,14 +2776,7 @@ def get_updates(
27782776
else:
27792777
self.logger.debug('No new updates found.')
27802778

2781-
updates = []
2782-
for u in result:
2783-
try:
2784-
updates.append(cast(Update, Update.de_json(u, self)))
2785-
except InvalidCallbackData as exc:
2786-
exc.update_id = int(u['update_id'])
2787-
self.logger.warning('%s Skipping CallbackQuery with invalid data: %s', exc, u)
2788-
return updates
2779+
return [cast(Update, Update.de_json(u, self)) for u in result]
27892780

27902781
@log
27912782
def set_webhook(
@@ -4586,7 +4577,7 @@ def stop_poll(
45864577
if reply_markup:
45874578
if isinstance(reply_markup, ReplyMarkup):
45884579
if self.arbitrary_callback_data and isinstance(reply_markup, InlineKeyboardMarkup):
4589-
reply_markup = reply_markup.replace_callback_data(bot=self)
4580+
reply_markup = self.callback_data.put_keyboard(reply_markup)
45904581
# We need to_json() instead of to_dict() here, because reply_markups may be
45914582
# attached to media messages, which aren't json dumped by utils.request
45924583
data['reply_markup'] = reply_markup.to_json()
@@ -4835,7 +4826,7 @@ def copy_message(
48354826
if reply_markup:
48364827
if isinstance(reply_markup, ReplyMarkup):
48374828
if self.arbitrary_callback_data and isinstance(reply_markup, InlineKeyboardMarkup):
4838-
reply_markup = reply_markup.replace_callback_data(bot=self)
4829+
reply_markup = self.callback_data.put_keyboard(reply_markup)
48394830
# We need to_json() instead of to_dict() here, because reply_markups may be
48404831
# attached to media messages, which aren't json dumped by utils.request
48414832
data['reply_markup'] = reply_markup.to_json()

telegram/callbackquery.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ class CallbackQuery(TelegramObject):
5353
until you call :attr:`answer`. It is, therefore, necessary to react
5454
by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user
5555
is needed (e.g., without specifying any of the optional parameters).
56+
* If you're using :attr:`Bot.arbitrary_callback_data`, :attr:`data` maybe be an instance of
57+
:class:`telegram.error.InvalidCallbackData`. This will be the case, if the data
58+
associated with the button triggering the :class:`telegram.CallbackQuery` was already
59+
deleted or if :attr:`data` was manipulated by a malicious client.
5660
5761
Args:
5862
id (:obj:`str`): Unique identifier for this query.
@@ -106,11 +110,22 @@ def __init__(
106110
self.data = data
107111
self.inline_message_id = inline_message_id
108112
self.game_short_name = game_short_name
109-
110113
self.bot = bot
111114

115+
self._callback_data = _kwargs.pop('callback_data', None)
116+
112117
self._id_attrs = (self.id,)
113118

119+
def drop_callback_data(self) -> None:
120+
"""
121+
Deletes the callback data stored in cache for all buttons associated with
122+
:attr:`reply_markup`. Will have no effect if :attr:`reply_markup` is :obj:`None`. Will
123+
automatically be called by all methods that change the reply markup of the message
124+
associated with this callback query.
125+
"""
126+
if self._callback_data:
127+
self.bot.callback_data.drop_keyboard(self._callback_data)
128+
114129
@classmethod
115130
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['CallbackQuery']:
116131
data = cls.parse_data(data)
@@ -119,13 +134,20 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['CallbackQuer
119134
return None
120135

121136
data['from_user'] = User.de_json(data.get('from'), bot)
122-
data['message'] = Message.de_json(data.get('message'), bot)
123137

124-
if bot.arbitrary_callback_data and 'data' in data:
138+
if bot.arbitrary_callback_data and data.get('data'):
139+
# Pass along the callback_data to message for the drop_callback_data shortcuts
140+
if data.get('message'):
141+
data['message']['callback_data'] = data['data']
142+
143+
# Pass the data to init for the drop_callback_data shortcuts
144+
data['callback_data'] = data['data']
125145
try:
126-
data['data'] = bot.callback_data.pop(data['data'])
127-
except IndexError as exc:
128-
raise InvalidCallbackData() from exc
146+
data['data'] = bot.callback_data.get_button_data(data['data'])
147+
except IndexError:
148+
data['data'] = InvalidCallbackData()
149+
150+
data['message'] = Message.de_json(data.get('message'), bot)
129151

130152
return cls(bot=bot, **data)
131153

@@ -186,6 +208,7 @@ def edit_message_text(
186208
edited Message is returned, otherwise :obj:`True` is returned.
187209
188210
"""
211+
self.drop_callback_data()
189212
if self.inline_message_id:
190213
return self.bot.edit_message_text(
191214
inline_message_id=self.inline_message_id,
@@ -236,6 +259,7 @@ def edit_message_caption(
236259
edited Message is returned, otherwise :obj:`True` is returned.
237260
238261
"""
262+
self.drop_callback_data()
239263
if self.inline_message_id:
240264
return self.bot.edit_message_caption(
241265
caption=caption,
@@ -288,6 +312,7 @@ def edit_message_reply_markup(
288312
edited Message is returned, otherwise :obj:`True` is returned.
289313
290314
"""
315+
self.drop_callback_data()
291316
if self.inline_message_id:
292317
return self.bot.edit_message_reply_markup(
293318
reply_markup=reply_markup,
@@ -327,6 +352,7 @@ def edit_message_media(
327352
edited Message is returned, otherwise :obj:`True` is returned.
328353
329354
"""
355+
self.drop_callback_data()
330356
if self.inline_message_id:
331357
return self.bot.edit_message_media(
332358
inline_message_id=self.inline_message_id,
@@ -375,6 +401,7 @@ def edit_message_live_location(
375401
edited Message is returned, otherwise :obj:`True` is returned.
376402
377403
"""
404+
self.drop_callback_data()
378405
if self.inline_message_id:
379406
return self.bot.edit_message_live_location(
380407
inline_message_id=self.inline_message_id,
@@ -427,6 +454,7 @@ def stop_message_live_location(
427454
edited Message is returned, otherwise :obj:`True` is returned.
428455
429456
"""
457+
self.drop_callback_data()
430458
if self.inline_message_id:
431459
return self.bot.stop_message_live_location(
432460
inline_message_id=self.inline_message_id,
@@ -542,6 +570,7 @@ def delete_message(
542570
:obj:`bool`: On success, :obj:`True` is returned.
543571
544572
"""
573+
self.drop_callback_data()
545574
return self.message.delete(
546575
timeout=timeout,
547576
api_kwargs=api_kwargs,

telegram/ext/basepersistence.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def get_callback_data_insert_bot() -> Optional[CDCData]:
105105
cdc_data = get_callback_data()
106106
if cdc_data is None:
107107
return None
108-
return cdc_data[0], instance.insert_bot(cdc_data[1]), cdc_data[2]
108+
return instance.insert_bot(cdc_data[0]), cdc_data[1]
109109

110110
def update_user_data_replace_bot(user_id: int, data: Dict) -> None:
111111
return update_user_data(user_id, instance.replace_bot(data))
@@ -117,8 +117,8 @@ def update_bot_data_replace_bot(data: Dict) -> None:
117117
return update_bot_data(instance.replace_bot(data))
118118

119119
def update_callback_data_replace_bot(data: CDCData) -> None:
120-
maxsize, obj_data, queue = data
121-
return update_callback_data((maxsize, instance.replace_bot(obj_data), queue))
120+
obj_data, queue = data
121+
return update_callback_data((instance.replace_bot(obj_data), queue))
122122

123123
instance.get_user_data = get_user_data_insert_bot
124124
instance.get_chat_data = get_chat_data_insert_bot

telegram/ext/dictpersistence.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from copy import deepcopy
2121

2222
from typing import Any, DefaultDict, Dict, Optional, Tuple
23-
from collections import defaultdict, deque
23+
from collections import defaultdict
2424

2525
from telegram.utils.helpers import (
2626
decode_conversations_from_json,
@@ -135,10 +135,7 @@ def __init__(
135135
raise TypeError("bot_data_json must be serialized dict")
136136
if callback_data_json:
137137
try:
138-
data = json.loads(callback_data_json)
139-
self._callback_data = (
140-
(data[0], data[1], deque(data[2])) if data is not None else None
141-
)
138+
self._callback_data = json.loads(callback_data_json)
142139
self._callback_data_json = callback_data_json
143140
except (ValueError, AttributeError) as exc:
144141
raise TypeError(
@@ -202,11 +199,7 @@ def callback_data_json(self) -> str:
202199
""":obj:`str`: The meta data on the stored callback data as a JSON-string."""
203200
if self._callback_data_json:
204201
return self._callback_data_json
205-
if self.callback_data is None:
206-
return json.dumps(self.callback_data)
207-
return json.dumps(
208-
(self.callback_data[0], self.callback_data[1], list(self.callback_data[2]))
209-
)
202+
return json.dumps(self.callback_data)
210203

211204
@property
212205
def conversations(self) -> Optional[Dict[str, Dict[Tuple, Any]]]:
@@ -350,5 +343,5 @@ def update_callback_data(self, data: CDCData) -> None:
350343
"""
351344
if self._callback_data == data:
352345
return
353-
self._callback_data = (data[0], data[1].copy(), data[2].copy())
346+
self._callback_data = (data[0].copy(), data[1].copy())
354347
self._callback_data_json = None

telegram/ext/dispatcher.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,12 @@ def __init__(
188188
if self.persistence.store_callback_data:
189189
callback_data = self.persistence.get_callback_data()
190190
if callback_data is not None:
191-
if not isinstance(callback_data, tuple) and len(callback_data) != 3:
192-
print(callback_data)
193-
raise ValueError('callback_data must be a 3-tuple')
194-
self.bot.callback_data = CallbackDataCache(*callback_data)
191+
if not isinstance(callback_data, tuple) and len(callback_data) != 2:
192+
raise ValueError('callback_data must be a 2-tuple')
193+
button_data, lru_list = callback_data
194+
self.bot.callback_data = CallbackDataCache(
195+
self.bot.callback_data.maxsize, button_data=button_data, lru_list=lru_list
196+
)
195197
else:
196198
self.persistence = None
197199

telegram/ext/picklepersistence.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ def update_callback_data(self, data: CDCData) -> None:
338338
"""
339339
if self.callback_data == data:
340340
return
341-
self.callback_data = (data[0], data[1].copy(), data[2].copy())
341+
self.callback_data = (data[0].copy(), data[1].copy())
342342
if not self.on_flush:
343343
if not self.single_file:
344344
filename = "{}_callback_data".format(self.filename)

telegram/inline/inlinekeyboardbutton.py

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
# along with this program. If not, see [http://www.gnu.org/licenses/].
1919
"""This module contains an object that represents a Telegram InlineKeyboardButton."""
2020

21-
from typing import TYPE_CHECKING, Any
21+
from typing import TYPE_CHECKING, Any, Optional
2222

2323
from telegram import TelegramObject
24+
from telegram.error import InvalidCallbackData
25+
from telegram.utils.types import JSONDict
2426

2527
if TYPE_CHECKING:
2628
from telegram import CallbackGame, LoginUrl, Bot
@@ -35,8 +37,13 @@ class InlineKeyboardButton(TelegramObject):
3537
and :attr:`pay` are equal.
3638
3739
Note:
38-
You must use exactly one of the optional fields. Mind that :attr:`callback_game` is not
39-
working as expected. Putting a game short name in it might, but is not guaranteed to work.
40+
* You must use exactly one of the optional fields. Mind that :attr:`callback_game` is not
41+
working as expected. Putting a game short name in it might, but is not guaranteed to
42+
work.
43+
* If you're using :attr:`Bot.arbitrary_callback_data`, in keyboards returned in a response
44+
from telegram, :attr:`callback_data` maybe be an instance of
45+
:class:`telegram.error.InvalidCallbackData`. This will be the case, if the data
46+
associated with the button was already deleted.
4047
4148
Args:
4249
text (:obj:`str`): Label text on the button.
@@ -119,20 +126,20 @@ def __init__(
119126
self.pay,
120127
)
121128

122-
def replace_callback_data(self, bot: 'Bot') -> 'InlineKeyboardButton':
123-
"""
124-
If this button has :attr:`callback_data`, will store that data in the bots callback data
125-
cache and return a new button where the :attr:`callback_data` is replaced by the
126-
corresponding unique identifier/a signed version of it. Otherwise just returns the button.
127-
128-
Args:
129-
bot (:class:`telegram.Bot`): The bot this button will be sent with.
130-
131-
Returns:
132-
:class:`telegram.InlineKeyboardButton`:
133-
"""
134-
if not self.callback_data:
135-
return self
136-
return InlineKeyboardButton(
137-
self.text, callback_data=bot.callback_data.put(self.callback_data)
138-
)
129+
@classmethod
130+
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['InlineKeyboardButton']:
131+
data = cls.parse_data(data)
132+
133+
if not data:
134+
return None
135+
136+
if data.get('callback_data', None):
137+
# No need to for update=True, that's already done in CallbackQuery.de_json
138+
try:
139+
data['callback_data'] = bot.callback_data.get_button_data(
140+
data['callback_data'], update=False
141+
)
142+
except IndexError:
143+
data['callback_data'] = InvalidCallbackData()
144+
145+
return cls(**data)

telegram/inline/inlinekeyboardmarkup.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -128,24 +128,6 @@ def from_column(
128128
button_grid = [[button] for button in button_column]
129129
return cls(button_grid, **kwargs)
130130

131-
def replace_callback_data(self, bot: 'Bot') -> 'InlineKeyboardMarkup':
132-
"""
133-
Builds a new keyboard by calling
134-
:meth:`telegram.InlineKeyboardButton.replace_callback_data` for all buttons.
135-
136-
Args:
137-
bot (:class:`telegram.Bot`): The bot this keyboard will be sent with.
138-
139-
Returns:
140-
:class:`telegram.InlineKeyboardMarkup`:
141-
"""
142-
return InlineKeyboardMarkup(
143-
[
144-
[btn.replace_callback_data(bot=bot) for btn in column]
145-
for column in self.inline_keyboard
146-
]
147-
)
148-
149131
def __eq__(self, other: object) -> bool:
150132
if isinstance(other, self.__class__):
151133
if len(self.inline_keyboard) != len(other.inline_keyboard):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy