8000 Refactor init of Persistence by Bibo-Joshi · Pull Request #2604 · python-telegram-bot/python-telegram-bot · GitHub
[go: up one dir, main page]

Skip to content

Refactor init of Persistence #2604

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

8000
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/source/telegram.ext.persistenceinput.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
:github_url: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/telegram/ext/basepersistence.py

telegram.ext.PersistenceInput
=============================

.. autoclass:: telegram.ext.PersistenceInput
:show-inheritance:
1 change: 1 addition & 0 deletions docs/source/telegram.ext.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Persistence
.. toctree::

telegram.ext.basepersistence
telegram.ext.persistenceinput
telegram.ext.picklepersistence
telegram.ext.dictpersistence

Expand Down
4 changes: 1 addition & 3 deletions examples/arbitrarycallbackdatabot.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,7 @@ def handle_invalid_button(update: Update, context: CallbackContext) -> None:
def main() -> None:
"""Run the bot."""
# We use persistence to demonstrate how buttons can still work after the bot was restarted
persistence = PicklePersistence(
filename='arbitrarycallbackdatabot.pickle', store_callback_data=True
)
persistence = PicklePersistence(filename='arbitrarycallbackdatabot.pickle')
# Create the Updater and pass it your bot's token.
updater = Updater("TOKEN", persistence=persistence, arbitrary_callback_data=True)

Expand Down
3 changes: 2 additions & 1 deletion telegram/ext/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"""Extensions over the Telegram Bot API to facilitate bot making"""

from .extbot import ExtBot
from .basepersistence import BasePersistence
from .basepersistence import BasePersistence, PersistenceInput
from .picklepersistence import PicklePersistence
from .dictpersistence import DictPersistence
from .handler import Handler
Expand Down Expand Up @@ -88,6 +88,7 @@
'MessageFilter',
'MessageHandler',
'MessageQueue',
'PersistenceInput',
'PicklePersistence',
'PollAnswerHandler',
'PollHandler',
Expand Down
84 changes: 44 additions & 40 deletions telegram/ext/basepersistence.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from sys import version_info as py_ver
from abc import ABC, abstractmethod
from copy import copy
from typing import Dict, Optional, Tuple, cast, ClassVar, Generic, DefaultDict
from typing import Dict, Optional, Tuple, cast, ClassVar, Generic, DefaultDict, NamedTuple

from telegram.utils.deprecate import set_new_attribute_deprecated

Expand All @@ -31,6 +31,33 @@
from telegram.ext.utils.types import UD, CD, BD, ConversationDict, CDCData


class PersistenceInput(NamedTuple):
"""Convenience wrapper to group boolean input for :class:`BasePersistence`.

Args:
bot_data (:obj:`bool`, optional): Whether the setting should be applied for ``bot_data``.
Defaults to :obj:`True`.
chat_data (:obj:`bool`, optional): Whether the setting should be applied for ``chat_data``.
Defaults to :obj:`True`.
user_data (:obj:`bool`, optional): Whether the setting should be applied for ``user_data``.
Defaults to :obj:`True`.
callback_data (:obj:`bool`, optional): Whether the setting should be 8000 applied for
``callback_data``. Defaults to :obj:`True`.

Attributes:
bot_data (:obj:`bool`): Whether the setting should be applied for ``bot_data``.
chat_data (:obj:`bool`): Whether the setting should be applied for ``chat_data``.
user_data (:obj:`bool`): Whether the setting should be applied for ``user_data``.
callback_data (:obj:`bool`): Whether the setting should be applied for ``callback_data``.

"""

bot_data: bool = True
chat_data: bool = True
user_data: bool = True
callback_data: bool = True


class BasePersistence(Generic[UD, CD, BD], ABC):
"""Interface class for adding persistence to your bot.
Subclass this object for different implementations of a persistent bot.
Expand All @@ -53,7 +80,7 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
* :meth:`flush`

If you don't actually need one of those methods, a simple ``pass`` is enough. For example, if
``store_bot_data=False``, you don't need :meth:`get_bot_data`, :meth:`update_bot_data` or
you don't store ``bot_data``, you don't need :meth:`get_bot_data`, :meth:`update_bot_data` or
:meth:`refresh_bot_data`.

Warning:
Expand All @@ -68,46 +95,28 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
of the :meth:`update/get_*` methods, i.e. you don't need to worry about it while
implementing a custom persistence subclass.

Args:
store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this
persistence class. Default is :obj:`True`.
store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this
persistence class. Default is :obj:`True` .
store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this
persistence class. Default is :obj:`True`.
store_callback_data (:obj:`bool`, optional): Whether callback_data should be saved by this
persistence class. Default is :obj:`True`.
.. versionchanged:: 14.0
The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`.

.. versionadded:: 13.6
Args:
store_data (:class:`PersistenceInput`, optional): Specifies which kinds of data will be
saved by this persistence instance. By default, all available kinds of data will be
saved.

Attributes:
store_user_data (:obj:`bool`): Optional, Whether user_data should be saved by this
persistence class.
store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this
persistence class.
store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this
persistence class.
store_callback_data (:obj:`bool`): Optional. Whether callback_data should be saved by this
persistence class.

.. versionadded:: 13.6
store_data (:class:`PersistenceInput`): Specifies which kinds of data will be saved by this
persistence instance.
"""

# Apparently Py 3.7 and below have '__dict__' in ABC
if py_ver < (3, 7):
__slots__ = (
'store_user_data',
'store_chat_data',
'store_bot_data',
'store_callback_data',
'store_data',
'bot',
)
else:
__slots__ = (
'store_user_data', # type: ignore[assignment]
'store_chat_data',
'store_bot_data',
'store_callback_data',
'store_data', # type: ignore[assignment]
'bot',
'__dict__',
)
Expand Down Expand Up @@ -173,15 +182,10 @@ def update_callback_data_replace_bot(data: CDCData) -> None:

def __init__(
self,
store_user_data: bool = True,
store_chat_data: bool = True,
store_bot_data: bool = True,
store_callback_data: bool = True,
store_data: PersistenceInput = None,
):
self.store_user_data = store_user_data
self.store_chat_data = store_chat_data
self.store_bot_data = store_bot_data
self.store_callback_data = store_callback_data
self.store_data = store_data or PersistenceInput()

self.bot: Bot = None # type: ignore[assignment]

def __setattr__(self, key: str, value: object) -> None:
Expand All @@ -200,8 +204,8 @@ def set_bot(self, bot: Bot) -> None:
Args:
bot (:class:`telegram.Bot`): The bot.
"""
if self.store_callback_data and not isinstance(bot, telegram.ext.extbot.ExtBot):
raise TypeError('store_callback_data can only be used with telegram.ext.ExtBot.')
if self.store_data.callback_data and not isinstance(bot, telegram.ext.extbot.ExtBot):
raise TypeError('callback_data can only be stored when using telegram.ext.ExtBot.')

self.bot = bot

Expand Down
12 changes: 9 additions & 3 deletions telegram/ext/callbackcontext.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,17 @@ def refresh_data(self) -> None:
.. versionadded:: 13.6
"""
if self.dispatcher.persistence:
if self.dispatcher.persistence.store_bot_data:
if self.dispatcher.persistence.store_data.bot_data:
self.dispatcher.persistence.refresh_bot_data(self.bot_data)
if self.dispatcher.persistence.store_chat_data and self._chat_id_and_data is not None:
if (
self.dispatcher.persistence.store_data.chat_data
and self._chat_id_and_data is not None
):
self.dispatcher.persistence.refresh_chat_data(*self._chat_id_and_data)
if self.dispatcher.persistence.store_user_data and self._user_id_and_data is not None:
if (
self.dispatcher.persistence.store_data.user_data
and self._user_id_and_data is not None
):
self.dispatcher.persistence.refresh_user_data(*self._user_id_and_data)

def drop_callback_data(self, callback_query: CallbackQuery) -> None:
Expand Down
42 changes: 11 additions & 31 deletions telegram/ext/dictpersistence.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
decode_user_chat_data_from_json,
encode_conversations_to_json,
)
from telegram.ext import BasePersistence
from telegram.ext import BasePersistence, PersistenceInput
from telegram.ext.utils.types import ConversationDict, CDCData

try:
Expand All @@ -53,17 +53,13 @@ class DictPersistence(BasePersistence):
:meth:`telegram.ext.BasePersistence.replace_bot` and
:meth:`telegram.ext.BasePersistence.insert_bot`.

Args:
store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this
persistence class. Default is :obj:`True`.
store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this
persistence class. Default is :obj:`True`.
store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this
persistence class. Default is :obj:`True`.
store_callback_data (:obj:`bool`, optional): Whether callback_data should be saved by this
persistence class. Default is :obj:`False`.
.. versionchanged:: 14.0
The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`.

.. versionadded:: 13.6
Args:
store_data (:class:`PersistenceInput`, optional): Specifies which kinds of data will be
saved by this persistence instance. By default, all available kinds of data will be
saved.
user_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct
user_data on creating this persistence. Default is ``""``.
chat_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct
Expand All @@ -78,16 +74,8 @@ class DictPersistence(BasePersistence):
conversation on creating this persistence. Default is ``""``.

Attributes:
store_user_data (:obj:`bool`): Whether user_data should be saved by this
persistence class.
store_chat_data (:obj:`bool`): Whether chat_data should be saved by this
persistence class.
store_bot_data (:obj:`bool`): Whether bot_data should be saved by this
persistence class.
store_callback_data (:obj:`bool`): Whether callback_data be saved by this
persistence class.

.. versionadded:: 13.6
store_data (:class:`PersistenceInput`): Specifies which kinds of data will be saved by this
persistence instance.
"""

__slots__ = (
Expand All @@ -105,22 +93,14 @@ class DictPersistence(BasePersistence):

def __init__(
self,
store_user_data: bool = True,
store_chat_data: bool = True,
store_bot_data: bool = True,
store_data: PersistenceInput = None,
user_data_json: str = '',
chat_data_json: str = '',
bot_data_json: str = '',
conversations_json: str = '',
store_callback_data: bool = False,
callback_data_json: str = '',
):
super().__init__(
store_user_data=store_user_data,
store_chat_data=store_chat_data,
store_bot_data=store_bot_data,
store_callback_data=store_callback_data,
)
super().__init__(store_data=store_data)
self._user_data = None
self._chat_data = None
self._bot_data = None
Expand Down
16 changes: 8 additions & 8 deletions telegram/ext/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,21 +261,21 @@ def __init__(
raise TypeError("persistence must be based on telegram.ext.BasePersistence")
self.persistence = persistence
self.persistence.set_bot(self.bot)
if self.persistence.store_user_data:
if self.persistence.store_data.user_data:
self.user_data = self.persistence.get_user_data()
if not isinstance(self.user_data, defaultdict):
raise ValueError("user_data must be of type defaultdict")
if self.persistence.store_chat_data:
if self.persistence.store_data.chat_data:
self.chat_data = self.persistence.get_chat_data()
if not isinstance(self.chat_data, defaultdict):
raise ValueError("chat_data must be of type defaultdict")
if self.persistence.store_bot_data:
if self.persistence.store_data.bot_data:
self.bot_data = self.persistence.get_bot_data()
if not isinstance(self.bot_data, self.context_types.bot_data):
raise ValueError(
f"bot_data must be of type {self.context_types.bot_data.__name__}"
)
if self.persistence.store_callback_data:
if self.persistence.store_data.callback_data:
self.bot = cast(telegram.ext.extbot.ExtBot, self.bot)
persistent_data = self.persistence.get_callback_data()
if persistent_data is not None:
Expand Down Expand Up @@ -679,7 +679,7 @@ def __update_persistence(self, update: object = None) -> None:
else:
user_ids = []

if self.persistence.store_callback_data:
if self.persistence.store_data.callback_data:
self.bot = cast(telegram.ext.extbot.ExtBot, self.bot)
try:
self.persistence.update_callback_data(
Expand All @@ -695,7 +695,7 @@ def __update_persistence(self, update: object = None) -> None:
'the error with an error_handler'
)
self.logger.exception(message)
if self.persistence.store_bot_data:
if self.persistence.store_data.bot_data:
try:
self.persistence.update_bot_data(self.bot_data)
except Exception as exc:
Expand All @@ -708,7 +708,7 @@ def __update_persistence(self, update: object = None) -> None:
'the error with an error_handler'
)
self.logger.exception(message)
if self.persistence.store_chat_data:
if self.persistence.store_data.chat_data:
for chat_id in chat_ids:
try:
self.persistence.update_chat_data(chat_id, self.chat_data[chat_id])
Expand All @@ -722,7 +722,7 @@ def __update_persistence(self, update: object = None) -> None:
'the error with an error_handler'
)
self.logger.exception(message)
if self.persistence.store_user_data:
if self.persistence.store_data.user_data:
for user_id in user_ids:
try:
self.persistence.update_user_data(user_id, self.user_data[user_id])
Expand Down
Loading
0