@@ -82,11 +82,19 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
82
82
:meth:`refresh_bot_data`.
83
83
84
84
Warning:
85
- Persistence will try to replace :class:`telegram.Bot` instances by :attr:`REPLACED_BOT` and
86
- insert the bot set with :meth:`set_bot` upon loading of the data. This is to ensure that
87
- changes to the bot apply to the saved objects, too. If you change the bots token, this may
88
- lead to e.g. ``Chat not found`` errors. For the limitations on replacing bots see
89
- :meth:`replace_bot` and :meth:`insert_bot`.
85
+ By default, persistence will try to replace :class:`telegram.Bot` instances in your data by
86
+ :attr:`REPLACED_BOT` and insert the bot set with :meth:`set_bot` upon loading of the data.
87
+ This is to ensure that changes to the bot apply to the saved objects, too.
88
+
89
+ For the limitations on replacing bots see :meth:`replace_bot` and :meth:`insert_bot`.
90
+
91
+ This as also relevant for all objects from the :mod:`telegram` package that have shortcuts
92
+ to bot methods (e.g. :meth:`telegram.Message.reply_text`), since they contain a reference
93
+ to a :class:`telegram.Bot` object (see :meth:`telegram.TelegramObject.get_bot`).
94
+
95
+ Because this replacing & insertion needs to go through all your data, it may add
96
+ considerable overhead. If you data does not contain any references to :class:`telegram.Bot`
97
+ instances, you can deactivate this behavior via the ``replace_bots`` parameter.
90
98
91
99
Note:
92
100
:meth:`replace_bot` and :meth:`insert_bot` are used *independently* of the implementation
@@ -100,84 +108,95 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
100
108
store_data (:class:`PersistenceInput`, optional): Specifies which kinds of data will be
101
109
saved by this persistence instance. By default, all available kinds of data will be
102
110
saved.
111
+ replace_bots (:class:`PersistenceInput`, optional): Specifies for which kinds of data
112
+ :meth:`replace_bot` and :meth:`insert_bot` will be called. By default, this is the case
113
+ for all available kinds of data.
114
+
115
+ .. versionadded:: 14.0
103
116
104
117
Attributes:
105
118
store_data (:class:`PersistenceInput`): Specifies which kinds of data will be saved by this
106
119
persistence instance.
120
+ replace_bots (:class:`PersistenceInput`, optional): Specifies for which kinds of data
121
+ :meth:`replace_bot` and :meth:`insert_bot` will be called.
122
+
123
+ .. versionadded:: 14.0
107
124
"""
108
125
109
126
__slots__ = (
110
127
'bot' ,
111
128
'store_data' ,
112
- '__dict__' , # __dict__ is included because we replace methods in the __new__
129
+ 'replace_bots' ,
130
+ # __dict__ is included because we replace methods in __inject_replace_insert_bot
131
+ '__dict__' ,
113
132
)
114
133
115
- def __new__ (
116
- cls , * args : object , ** kwargs : object # pylint: disable=unused-argument
117
- ) -> 'BasePersistence' :
134
+ def __init__ (self , store_data : PersistenceInput = None , replace_bots : PersistenceInput = None ):
135
+ self .store_data = store_data or PersistenceInput ()
136
+ self .replace_bots = replace_bots or PersistenceInput ()
137
+ self .__inject_replace_insert_bot ()
138
+
139
+ self .bot : Bot = None # type: ignore[assignment]
140
+
141
+ def __inject_replace_insert_bot (self ):
118
142
"""This overrides the get_* and update_* methods to use insert/replace_bot.
119
- That has the side effect that we always pass deepcopied data to those methods, so in
120
- Pickle/DictPersistence we don't have to worry about copying the data again.
121
143
122
- Note: This doesn't hold for second tuple-entry of callback_data. That's a Dict[str, str],
144
+ Note: Depending on `self.replace_bots`, we pass the exact objects to the update_* methods,
145
+ so in Pickle/DictPersistence we need to make sure not to modify such data in place!
146
+
147
+ Note: The second tuple-entry of callback_data is never affected. That's a Dict[str, str],
123
148
so no bots to replace anyway.
124
149
"""
125
- instance = super ().__new__ (cls )
126
- get_user_data = instance .get_user_data
127
- get_chat_data = instance .get_chat_data
128
- get_bot_data = instance .get_bot_data
129
- get_callback_data = instance .get_callback_data
130
- update_user_data = instance .update_user_data
131
- update_chat_data = instance .update_chat_data
132
- update_bot_data = instance .update_bot_data
133
- update_callback_data = instance .update_callback_data
150
+ get_user_data = self .get_user_data
151
+ get_chat_data = self .get_chat_data
152
+ get_bot_data = self .get_bot_data
153
+ get_callback_data = self .get_callback_data
154
+ update_user_data = self .update_user_data
155
+ update_chat_data = self .update_chat_data
156
+ update_bot_data = self .update_bot_data
157
+ update_callback_data = self .update_callback_data
134
158
135
159
def get_user_data_insert_bot () -> DefaultDict [int , UD ]:
136
- return instance .insert_bot (get_user_data ())
160
+ return self .insert_bot (get_user_data ())
137
161
138
162
def get_chat_data_insert_bot () -> DefaultDict [int , CD ]:
139
- return instance .insert_bot (get_chat_data ())
163
+ return self .insert_bot (get_chat_data ())
140
164
141
165
def get_bot_data_insert_bot () -> BD :
142
- return instance .insert_bot (get_bot_data ())
166
+ return self .insert_bot (get_bot_data ())
143
167
144
168
def get_callback_data_insert_bot () -> Optional [CDCData ]:
145
169
cdc_data = get_callback_data ()
146
170
if cdc_data is None :
147
171
return None
148
- return instance .insert_bot (cdc_data [0 ]), cdc_data [1 ]
172
+ return self .insert_bot (cdc_data [0 ]), cdc_data [1 ]
149
173
150
174
def update_user_data_replace_bot (user_id : int , data : UD ) -> None :
151
- return update_user_data (user_id , instance .replace_bot (data ))
175
+ return update_user_data (user_id , self .replace_bot (data ))
152
176
153
177
def update_chat_data_replace_bot (chat_id : int , data : CD ) -> None :
154
- return update_chat_data (chat_id , instance .replace_bot (data ))
178
+ return update_chat_data (chat_id , self .replace_bot (data ))
155
179
156
180
def update_bot_data_replace_bot (data : BD ) -> None :
157
- return update_bot_data (instance .replace_bot (data ))
181
+ return update_bot_data (self .replace_bot (data ))
158
182
159
183
def update_callback_data_replace_bot (data : CDCData ) -> None :
160
184
obj_data , queue = data
161
- return update_callback_data ((instance .replace_bot (obj_data ), queue ))
185
+ return update_callback_data ((self .replace_bot (obj_data ), queue ))
162
186
163
187
# Adds to __dict__
164
- setattr (instance , 'get_user_data' , get_user_data_insert_bot )
165
- setattr (instance , 'get_chat_data' , get_chat_data_insert_bot )
166
- setattr (instance , 'get_bot_data' , get_bot_data_insert_bot )
167
- setattr (instance , 'get_callback_data' , get_callback_data_insert_bot )
168
- setattr (instance , 'update_user_data' , update_user_data_replace_bot )
169
- setattr (instance , 'update_chat_data' , update_chat_data_replace_bot )
170
- setattr (instance , 'update_bot_data' , update_bot_data_replace_bot )
171
- setattr (instance , 'update_callback_data' , update_callback_data_replace_bot )
172
- return instance
173
-
174
- def __init__ (
175
- self ,
176
- store_data : PersistenceInput = None ,
177
- ):
178
- self .store_data = store_data or PersistenceInput ()
179
-
180
- self .bot : Bot = None # type: ignore[assignment]
188
+ if self .replace_bots .bot_data :
189
+ self .get_bot_data = get_bot_data_insert_bot
190
+ self .update_bot_data = update_bot_data_replace_bot
191
+ if self .replace_bots .chat_data :
192
+ self .get_chat_data = get_chat_data_insert_bot
193
+ self .update_chat_data = update_chat_data_replace_bot
194
+ if self .replace_bots .user_data :
195
+ self .get_user_data = get_user_data_insert_bot
196
+ self .update_user_data = update_user_data_replace_bot
197
+ if self .replace_bots .callback_data :
198
+ self .get_callback_data = get_callback_data_insert_bot
199
+ self .update_callback_data = update_callback_data_replace_bot
181
200
182
201
def set_bot (self , bot : Bot ) -> None :
183
202
"""Set the Bot to be used by this persistence instance.
0 commit comments