We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[BUG] v12.4 breaks PicklePersistence
<!--
Thanks for reporting issues of python-telegram-bot!

Use this template to notify us if you found a bug.

To make it easier for us to help you please enter detailed information below.

Please note, we only support the latest version of python-telegram-bot and
master branch. Please make sure to upgrade & recreate the issue on the latest
version prior to opening an issue.
-->
### Steps to reproduce
1. Have a bot using PicklePersistence with singlefile=True

2. Upgrade to v12.4

3. restart bot

### Expected behaviour
pickled file is read correctly

### Actual behaviour
key error `bot_data` is thrown

### Current workaround:
Add an empty dict `bot_data` to the file manually. Quick and dirty script:
```
import pickle

filename = 'my_pickle_persistence_file'

with (open(filename, 'rb')) as file:
    data = pickle.load(file)

data['bot_data'] = {}

with open(filename, 'wb') as f:
    pickle.dump(data, f)
```

Will be closed by #1760 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `telegram/ext/picklepersistence.py`
Content:
```
1 #!/usr/bin/env python
2 #
3 # A library that provides a Python interface to the Telegram Bot API
4 # Copyright (C) 2015-2020
5 # Leandro Toledo de Souza <devs@python-telegram-bot.org>
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU Lesser Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser Public License
18 # along with this program.  If not, see [http://www.gnu.org/licenses/].
19 """This module contains the PicklePersistence class."""
20 import pickle
21 from collections import defaultdict
22 from copy import deepcopy
23 
24 from telegram.ext import BasePersistence
25 
26 
27 class PicklePersistence(BasePersistence):
28     """Using python's builtin pickle for making you bot persistent.
29 
30     Attributes:
31         filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`
32             is false this will be used as a prefix.
33         store_user_data (:obj:`bool`): Optional. Whether user_data should be saved by this
34             persistence class.
35         store_chat_data (:obj:`bool`): Optional. Whether user_data should be saved by this
36             persistence class.
37         store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this
38             persistence class.
39         single_file (:obj:`bool`): Optional. When ``False`` will store 3 sperate files of
40             `filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is
41             ``True``.
42         on_flush (:obj:`bool`, optional): When ``True`` will only save to file when :meth:`flush`
43             is called and keep data in memory until that happens. When ``False`` will store data
44             on any transaction *and* on call fo :meth:`flush`. Default is ``False``.
45 
46     Args:
47         filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`
48             is false this will be used as a prefix.
49         store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this
50             persistence class. Default is ``True``.
51         store_chat_data (:obj:`bool`, optional): Whether user_data should be saved by this
52             persistence class. Default is ``True``.
53         store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this
54             persistence class. Default is ``True`` .
55         single_file (:obj:`bool`, optional): When ``False`` will store 3 sperate files of
56             `filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is
57             ``True``.
58         on_flush (:obj:`bool`, optional): When ``True`` will only save to file when :meth:`flush`
59             is called and keep data in memory until that happens. When ``False`` will store data
60             on any transaction *and* on call fo :meth:`flush`. Default is ``False``.
61     """
62 
63     def __init__(self, filename,
64                  store_user_data=True,
65                  store_chat_data=True,
66                  store_bot_data=True,
67                  single_file=True,
68                  on_flush=False):
69         super(PicklePersistence, self).__init__(store_user_data=store_user_data,
70                                                 store_chat_data=store_chat_data,
71                                                 store_bot_data=store_bot_data)
72         self.filename = filename
73         self.single_file = single_file
74         self.on_flush = on_flush
75         self.user_data = None
76         self.chat_data = None
77         self.bot_data = None
78         self.conversations = None
79 
80     def load_singlefile(self):
81         try:
82             filename = self.filename
83             with open(self.filename, "rb") as f:
84                 all = pickle.load(f)
85                 self.user_data = defaultdict(dict, all['user_data'])
86                 self.chat_data = defaultdict(dict, all['chat_data'])
87                 self.bot_data = all['bot_data']
88                 self.conversations = all['conversations']
89         except IOError:
90             self.conversations = {}
91             self.user_data = defaultdict(dict)
92             self.chat_data = defaultdict(dict)
93             self.bot_data = {}
94         except pickle.UnpicklingError:
95             raise TypeError("File {} does not contain valid pickle data".format(filename))
96         except Exception:
97             raise TypeError("Something went wrong unpickling {}".format(filename))
98 
99     def load_file(self, filename):
100         try:
101             with open(filename, "rb") as f:
102                 return pickle.load(f)
103         except IOError:
104             return None
105         except pickle.UnpicklingError:
106             raise TypeError("File {} does not contain valid pickle data".format(filename))
107         except Exception:
108             raise TypeError("Something went wrong unpickling {}".format(filename))
109 
110     def dump_singlefile(self):
111         with open(self.filename, "wb") as f:
112             all = {'conversations': self.conversations, 'user_data': self.user_data,
113                    'chat_data': self.chat_data, 'bot_data': self.bot_data}
114             pickle.dump(all, f)
115 
116     def dump_file(self, filename, data):
117         with open(filename, "wb") as f:
118             pickle.dump(data, f)
119 
120     def get_user_data(self):
121         """Returns the user_data from the pickle file if it exsists or an empty defaultdict.
122 
123         Returns:
124             :obj:`defaultdict`: The restored user data.
125         """
126         if self.user_data:
127             pass
128         elif not self.single_file:
129             filename = "{}_user_data".format(self.filename)
130             data = self.load_file(filename)
131             if not data:
132                 data = defaultdict(dict)
133             else:
134                 data = defaultdict(dict, data)
135             self.user_data = data
136         else:
137             self.load_singlefile()
138         return deepcopy(self.user_data)
139 
140     def get_chat_data(self):
141         """Returns the chat_data from the pickle file if it exsists or an empty defaultdict.
142 
143         Returns:
144             :obj:`defaultdict`: The restored chat data.
145         """
146         if self.chat_data:
147             pass
148         elif not self.single_file:
149             filename = "{}_chat_data".format(self.filename)
150             data = self.load_file(filename)
151             if not data:
152                 data = defaultdict(dict)
153             else:
154                 data = defaultdict(dict, data)
155             self.chat_data = data
156         else:
157             self.load_singlefile()
158         return deepcopy(self.chat_data)
159 
160     def get_bot_data(self):
161         """Returns the bot_data from the pickle file if it exsists or an empty dict.
162 
163         Returns:
164             :obj:`defaultdict`: The restored bot data.
165         """
166         if self.bot_data:
167             pass
168         elif not self.single_file:
169             filename = "{}_bot_data".format(self.filename)
170             data = self.load_file(filename)
171             if not data:
172                 data = {}
173             self.bot_data = data
174         else:
175             self.load_singlefile()
176         return deepcopy(self.bot_data)
177 
178     def get_conversations(self, name):
179         """Returns the conversations from the pickle file if it exsists or an empty defaultdict.
180 
181         Args:
182             name (:obj:`str`): The handlers name.
183 
184         Returns:
185             :obj:`dict`: The restored conversations for the handler.
186         """
187         if self.conversations:
188             pass
189         elif not self.single_file:
190             filename = "{}_conversations".format(self.filename)
191             data = self.load_file(filename)
192             if not data:
193                 data = {name: {}}
194             self.conversations = data
195         else:
196             self.load_singlefile()
197         return self.conversations.get(name, {}).copy()
198 
199     def update_conversation(self, name, key, new_state):
200         """Will update the conversations for the given handler and depending on :attr:`on_flush`
201         save the pickle file.
202 
203         Args:
204             name (:obj:`str`): The handlers name.
205             key (:obj:`tuple`): The key the state is changed for.
206             new_state (:obj:`tuple` | :obj:`any`): The new state for the given key.
207         """
208         if self.conversations.setdefault(name, {}).get(key) == new_state:
209             return
210         self.conversations[name][key] = new_state
211         if not self.on_flush:
212             if not self.single_file:
213                 filename = "{}_conversations".format(self.filename)
214                 self.dump_file(filename, self.conversations)
215             else:
216                 self.dump_singlefile()
217 
218     def update_user_data(self, user_id, data):
219         """Will update the user_data (if changed) and depending on :attr:`on_flush` save the
220         pickle file.
221 
222         Args:
223             user_id (:obj:`int`): The user the data might have been changed for.
224             data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data` [user_id].
225         """
226         if self.user_data.get(user_id) == data:
227             return
228         self.user_data[user_id] = data
229         if not self.on_flush:
230             if not self.single_file:
231                 filename = "{}_user_data".format(self.filename)
232                 self.dump_file(filename, self.user_data)
233             else:
234                 self.dump_singlefile()
235 
236     def update_chat_data(self, chat_id, data):
237         """Will update the chat_data (if changed) and depending on :attr:`on_flush` save the
238         pickle file.
239 
240         Args:
241             chat_id (:obj:`int`): The chat the data might have been changed for.
242             data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` [chat_id].
243         """
244         if self.chat_data.get(chat_id) == data:
245             return
246         self.chat_data[chat_id] = data
247         if not self.on_flush:
248             if not self.single_file:
249                 filename = "{}_chat_data".format(self.filename)
250                 self.dump_file(filename, self.chat_data)
251             else:
252                 self.dump_singlefile()
253 
254     def update_bot_data(self, data):
255         """Will update the bot_data (if changed) and depending on :attr:`on_flush` save the
256         pickle file.
257 
258         Args:
259             data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`.
260         """
261         if self.bot_data == data:
262             return
263         self.bot_data = data.copy()
264         if not self.on_flush:
265             if not self.single_file:
266                 filename = "{}_bot_data".format(self.filename)
267                 self.dump_file(filename, self.bot_data)
268             else:
269                 self.dump_singlefile()
270 
271     def flush(self):
272         """ Will save all data in memory to pickle file(s).
273         """
274         if self.single_file:
275             if self.user_data or self.chat_data or self.conversations:
276                 self.dump_singlefile()
277         else:
278             if self.user_data:
279                 self.dump_file("{}_user_data".format(self.filename), self.user_data)
280             if self.chat_data:
281                 self.dump_file("{}_chat_data".format(self.filename), self.chat_data)
282             if self.bot_data:
283                 self.dump_file("{}_bot_data".format(self.filename), self.bot_data)
284             if self.conversations:
285                 self.dump_file("{}_conversations".format(self.filename), self.conversations)
286
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/telegram/ext/picklepersistence.py b/telegram/ext/picklepersistence.py
--- a/telegram/ext/picklepersistence.py
+++ b/telegram/ext/picklepersistence.py
@@ -84,7 +84,8 @@
                 all = pickle.load(f)
                 self.user_data = defaultdict(dict, all['user_data'])
                 self.chat_data = defaultdict(dict, all['chat_data'])
-                self.bot_data = all['bot_data']
+                # For backwards compatibility with files not containing bot data
+                self.bot_data = all.get('bot_data', {})
                 self.conversations = all['conversations']
         except IOError:
             self.conversations = {}

{"golden_diff": "diff --git a/telegram/ext/picklepersistence.py b/telegram/ext/picklepersistence.py\n--- a/telegram/ext/picklepersistence.py\n+++ b/telegram/ext/picklepersistence.py\n@@ -84,7 +84,8 @@\n                 all = pickle.load(f)\n                 self.user_data = defaultdict(dict, all['user_data'])\n                 self.chat_data = defaultdict(dict, all['chat_data'])\n-                self.bot_data = all['bot_data']\n+                # For backwards compatibility with files not containing bot data\n+                self.bot_data = all.get('bot_data', {})\n                 self.conversations = all['conversations']\n         except IOError:\n             self.conversations = {}\n", "issue": "[BUG] v12.4 breaks PicklePersistence\n<!--\r\nThanks for reporting issues of python-telegram-bot!\r\n\r\nUse this template to notify us if you found a bug.\r\n\r\nTo make it easier for us to help you please enter detailed information below.\r\n\r\nPlease note, we only support the latest version of python-telegram-bot and\r\nmaster branch. Please make sure to upgrade & recreate the issue on the latest\r\nversion prior to opening an issue.\r\n-->\r\n### Steps to reproduce\r\n1. Have a bot using PicklePersistence with singlefile=True\r\n\r\n2. Upgrade to v12.4\r\n\r\n3. restart bot\r\n\r\n### Expected behaviour\r\npickled file is read correctly\r\n\r\n### Actual behaviour\r\nkey error `bot_data` is thrown\r\n\r\n### Current workaround:\r\nAdd an empty dict `bot_data` to the file manually. Quick and dirty script:\r\n```\r\nimport pickle\r\n\r\nfilename = 'my_pickle_persistence_file'\r\n\r\nwith (open(filename, 'rb')) as file:\r\n    data = pickle.load(file)\r\n\r\ndata['bot_data'] = {}\r\n\r\nwith open(filename, 'wb') as f:\r\n    pickle.dump(data, f)\r\n```\r\n\r\nWill be closed by #1760 \n", "before_files": [{"content": "#!/usr/bin/env python\n#\n# A library that provides a Python interface to the Telegram Bot API\n# Copyright (C) 2015-2020\n# Leandro Toledo de Souza <devs@python-telegram-bot.org>\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU Lesser Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser Public License for more details.\n#\n# You should have received a copy of the GNU Lesser Public License\n# along with this program.  If not, see [http://www.gnu.org/licenses/].\n\"\"\"This module contains the PicklePersistence class.\"\"\"\nimport pickle\nfrom collections import defaultdict\nfrom copy import deepcopy\n\nfrom telegram.ext import BasePersistence\n\n\nclass PicklePersistence(BasePersistence):\n    \"\"\"Using python's builtin pickle for making you bot persistent.\n\n    Attributes:\n        filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`\n            is false this will be used as a prefix.\n        store_user_data (:obj:`bool`): Optional. Whether user_data should be saved by this\n            persistence class.\n        store_chat_data (:obj:`bool`): Optional. Whether user_data should be saved by this\n            persistence class.\n        store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this\n            persistence class.\n        single_file (:obj:`bool`): Optional. When ``False`` will store 3 sperate files of\n            `filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is\n            ``True``.\n        on_flush (:obj:`bool`, optional): When ``True`` will only save to file when :meth:`flush`\n            is called and keep data in memory until that happens. When ``False`` will store data\n            on any transaction *and* on call fo :meth:`flush`. Default is ``False``.\n\n    Args:\n        filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`\n            is false this will be used as a prefix.\n        store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this\n            persistence class. Default is ``True``.\n        store_chat_data (:obj:`bool`, optional): Whether user_data should be saved by this\n            persistence class. Default is ``True``.\n        store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this\n            persistence class. Default is ``True`` .\n        single_file (:obj:`bool`, optional): When ``False`` will store 3 sperate files of\n            `filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is\n            ``True``.\n        on_flush (:obj:`bool`, optional): When ``True`` will only save to file when :meth:`flush`\n            is called and keep data in memory until that happens. When ``False`` will store data\n            on any transaction *and* on call fo :meth:`flush`. Default is ``False``.\n    \"\"\"\n\n    def __init__(self, filename,\n                 store_user_data=True,\n                 store_chat_data=True,\n                 store_bot_data=True,\n                 single_file=True,\n                 on_flush=False):\n        super(PicklePersistence, self).__init__(store_user_data=store_user_data,\n                                                store_chat_data=store_chat_data,\n                                                store_bot_data=store_bot_data)\n        self.filename = filename\n        self.single_file = single_file\n        self.on_flush = on_flush\n        self.user_data = None\n        self.chat_data = None\n        self.bot_data = None\n        self.conversations = None\n\n    def load_singlefile(self):\n        try:\n            filename = self.filename\n            with open(self.filename, \"rb\") as f:\n                all = pickle.load(f)\n                self.user_data = defaultdict(dict, all['user_data'])\n                self.chat_data = defaultdict(dict, all['chat_data'])\n                self.bot_data = all['bot_data']\n                self.conversations = all['conversations']\n        except IOError:\n            self.conversations = {}\n            self.user_data = defaultdict(dict)\n            self.chat_data = defaultdict(dict)\n            self.bot_data = {}\n        except pickle.UnpicklingError:\n            raise TypeError(\"File {} does not contain valid pickle data\".format(filename))\n        except Exception:\n            raise TypeError(\"Something went wrong unpickling {}\".format(filename))\n\n    def load_file(self, filename):\n        try:\n            with open(filename, \"rb\") as f:\n                return pickle.load(f)\n        except IOError:\n            return None\n        except pickle.UnpicklingError:\n            raise TypeError(\"File {} does not contain valid pickle data\".format(filename))\n        except Exception:\n            raise TypeError(\"Something went wrong unpickling {}\".format(filename))\n\n    def dump_singlefile(self):\n        with open(self.filename, \"wb\") as f:\n            all = {'conversations': self.conversations, 'user_data': self.user_data,\n                   'chat_data': self.chat_data, 'bot_data': self.bot_data}\n            pickle.dump(all, f)\n\n    def dump_file(self, filename, data):\n        with open(filename, \"wb\") as f:\n            pickle.dump(data, f)\n\n    def get_user_data(self):\n        \"\"\"Returns the user_data from the pickle file if it exsists or an empty defaultdict.\n\n        Returns:\n            :obj:`defaultdict`: The restored user data.\n        \"\"\"\n        if self.user_data:\n            pass\n        elif not self.single_file:\n            filename = \"{}_user_data\".format(self.filename)\n            data = self.load_file(filename)\n            if not data:\n                data = defaultdict(dict)\n            else:\n                data = defaultdict(dict, data)\n            self.user_data = data\n        else:\n            self.load_singlefile()\n        return deepcopy(self.user_data)\n\n    def get_chat_data(self):\n        \"\"\"Returns the chat_data from the pickle file if it exsists or an empty defaultdict.\n\n        Returns:\n            :obj:`defaultdict`: The restored chat data.\n        \"\"\"\n        if self.chat_data:\n            pass\n        elif not self.single_file:\n            filename = \"{}_chat_data\".format(self.filename)\n            data = self.load_file(filename)\n            if not data:\n                data = defaultdict(dict)\n            else:\n                data = defaultdict(dict, data)\n            self.chat_data = data\n        else:\n            self.load_singlefile()\n        return deepcopy(self.chat_data)\n\n    def get_bot_data(self):\n        \"\"\"Returns the bot_data from the pickle file if it exsists or an empty dict.\n\n        Returns:\n            :obj:`defaultdict`: The restored bot data.\n        \"\"\"\n        if self.bot_data:\n            pass\n        elif not self.single_file:\n            filename = \"{}_bot_data\".format(self.filename)\n            data = self.load_file(filename)\n            if not data:\n                data = {}\n            self.bot_data = data\n        else:\n            self.load_singlefile()\n        return deepcopy(self.bot_data)\n\n    def get_conversations(self, name):\n        \"\"\"Returns the conversations from the pickle file if it exsists or an empty defaultdict.\n\n        Args:\n            name (:obj:`str`): The handlers name.\n\n        Returns:\n            :obj:`dict`: The restored conversations for the handler.\n        \"\"\"\n        if self.conversations:\n            pass\n        elif not self.single_file:\n            filename = \"{}_conversations\".format(self.filename)\n            data = self.load_file(filename)\n            if not data:\n                data = {name: {}}\n            self.conversations = data\n        else:\n            self.load_singlefile()\n        return self.conversations.get(name, {}).copy()\n\n    def update_conversation(self, name, key, new_state):\n        \"\"\"Will update the conversations for the given handler and depending on :attr:`on_flush`\n        save the pickle file.\n\n        Args:\n            name (:obj:`str`): The handlers name.\n            key (:obj:`tuple`): The key the state is changed for.\n            new_state (:obj:`tuple` | :obj:`any`): The new state for the given key.\n        \"\"\"\n        if self.conversations.setdefault(name, {}).get(key) == new_state:\n            return\n        self.conversations[name][key] = new_state\n        if not self.on_flush:\n            if not self.single_file:\n                filename = \"{}_conversations\".format(self.filename)\n                self.dump_file(filename, self.conversations)\n            else:\n                self.dump_singlefile()\n\n    def update_user_data(self, user_id, data):\n        \"\"\"Will update the user_data (if changed) and depending on :attr:`on_flush` save the\n        pickle file.\n\n        Args:\n            user_id (:obj:`int`): The user the data might have been changed for.\n            data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data` [user_id].\n        \"\"\"\n        if self.user_data.get(user_id) == data:\n            return\n        self.user_data[user_id] = data\n        if not self.on_flush:\n            if not self.single_file:\n                filename = \"{}_user_data\".format(self.filename)\n                self.dump_file(filename, self.user_data)\n            else:\n                self.dump_singlefile()\n\n    def update_chat_data(self, chat_id, data):\n        \"\"\"Will update the chat_data (if changed) and depending on :attr:`on_flush` save the\n        pickle file.\n\n        Args:\n            chat_id (:obj:`int`): The chat the data might have been changed for.\n            data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` [chat_id].\n        \"\"\"\n        if self.chat_data.get(chat_id) == data:\n            return\n        self.chat_data[chat_id] = data\n        if not self.on_flush:\n            if not self.single_file:\n                filename = \"{}_chat_data\".format(self.filename)\n                self.dump_file(filename, self.chat_data)\n            else:\n                self.dump_singlefile()\n\n    def update_bot_data(self, data):\n        \"\"\"Will update the bot_data (if changed) and depending on :attr:`on_flush` save the\n        pickle file.\n\n        Args:\n            data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`.\n        \"\"\"\n        if self.bot_data == data:\n            return\n        self.bot_data = data.copy()\n        if not self.on_flush:\n            if not self.single_file:\n                filename = \"{}_bot_data\".format(self.filename)\n                self.dump_file(filename, self.bot_data)\n            else:\n                self.dump_singlefile()\n\n    def flush(self):\n        \"\"\" Will save all data in memory to pickle file(s).\n        \"\"\"\n        if self.single_file:\n            if self.user_data or self.chat_data or self.conversations:\n                self.dump_singlefile()\n        else:\n            if self.user_data:\n                self.dump_file(\"{}_user_data\".format(self.filename), self.user_data)\n            if self.chat_data:\n                self.dump_file(\"{}_chat_data\".format(self.filename), self.chat_data)\n            if self.bot_data:\n                self.dump_file(\"{}_bot_data\".format(self.filename), self.bot_data)\n            if self.conversations:\n                self.dump_file(\"{}_conversations\".format(self.filename), self.conversations)\n", "path": "telegram/ext/picklepersistence.py"}], "after_files": [{"content": "#!/usr/bin/env python\n#\n# A library that provides a Python interface to the Telegram Bot API\n# Copyright (C) 2015-2020\n# Leandro Toledo de Souza <devs@python-telegram-bot.org>\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU Lesser Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser Public License for more details.\n#\n# You should have received a copy of the GNU Lesser Public License\n# along with this program.  If not, see [http://www.gnu.org/licenses/].\n\"\"\"This module contains the PicklePersistence class.\"\"\"\nimport pickle\nfrom collections import defaultdict\nfrom copy import deepcopy\n\nfrom telegram.ext import BasePersistence\n\n\nclass PicklePersistence(BasePersistence):\n    \"\"\"Using python's builtin pickle for making you bot persistent.\n\n    Attributes:\n        filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`\n            is false this will be used as a prefix.\n        store_user_data (:obj:`bool`): Optional. Whether user_data should be saved by this\n            persistence class.\n        store_chat_data (:obj:`bool`): Optional. Whether user_data should be saved by this\n            persistence class.\n        store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this\n            persistence class.\n        single_file (:obj:`bool`): Optional. When ``False`` will store 3 sperate files of\n            `filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is\n            ``True``.\n        on_flush (:obj:`bool`, optional): When ``True`` will only save to file when :meth:`flush`\n            is called and keep data in memory until that happens. When ``False`` will store data\n            on any transaction *and* on call fo :meth:`flush`. Default is ``False``.\n\n    Args:\n        filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file`\n            is false this will be used as a prefix.\n        store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this\n            persistence class. Default is ``True``.\n        store_chat_data (:obj:`bool`, optional): Whether user_data should be saved by this\n            persistence class. Default is ``True``.\n        store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this\n            persistence class. Default is ``True`` .\n        single_file (:obj:`bool`, optional): When ``False`` will store 3 sperate files of\n            `filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is\n            ``True``.\n        on_flush (:obj:`bool`, optional): When ``True`` will only save to file when :meth:`flush`\n            is called and keep data in memory until that happens. When ``False`` will store data\n            on any transaction *and* on call fo :meth:`flush`. Default is ``False``.\n    \"\"\"\n\n    def __init__(self, filename,\n                 store_user_data=True,\n                 store_chat_data=True,\n                 store_bot_data=True,\n                 single_file=True,\n                 on_flush=False):\n        super(PicklePersistence, self).__init__(store_user_data=store_user_data,\n                                                store_chat_data=store_chat_data,\n                                                store_bot_data=store_bot_data)\n        self.filename = filename\n        self.single_file = single_file\n        self.on_flush = on_flush\n        self.user_data = None\n        self.chat_data = None\n        self.bot_data = None\n        self.conversations = None\n\n    def load_singlefile(self):\n        try:\n            filename = self.filename\n            with open(self.filename, \"rb\") as f:\n                all = pickle.load(f)\n                self.user_data = defaultdict(dict, all['user_data'])\n                self.chat_data = defaultdict(dict, all['chat_data'])\n                # For backwards compatibility with files not containing bot data\n                self.bot_data = all.get('bot_data', {})\n                self.conversations = all['conversations']\n        except IOError:\n            self.conversations = {}\n            self.user_data = defaultdict(dict)\n            self.chat_data = defaultdict(dict)\n            self.bot_data = {}\n        except pickle.UnpicklingError:\n            raise TypeError(\"File {} does not contain valid pickle data\".format(filename))\n        except Exception:\n            raise TypeError(\"Something went wrong unpickling {}\".format(filename))\n\n    def load_file(self, filename):\n        try:\n            with open(filename, \"rb\") as f:\n                return pickle.load(f)\n        except IOError:\n            return None\n        except pickle.UnpicklingError:\n            raise TypeError(\"File {} does not contain valid pickle data\".format(filename))\n        except Exception:\n            raise TypeError(\"Something went wrong unpickling {}\".format(filename))\n\n    def dump_singlefile(self):\n        with open(self.filename, \"wb\") as f:\n            all = {'conversations': self.conversations, 'user_data': self.user_data,\n                   'chat_data': self.chat_data, 'bot_data': self.bot_data}\n            pickle.dump(all, f)\n\n    def dump_file(self, filename, data):\n        with open(filename, \"wb\") as f:\n            pickle.dump(data, f)\n\n    def get_user_data(self):\n        \"\"\"Returns the user_data from the pickle file if it exsists or an empty defaultdict.\n\n        Returns:\n            :obj:`defaultdict`: The restored user data.\n        \"\"\"\n        if self.user_data:\n            pass\n        elif not self.single_file:\n            filename = \"{}_user_data\".format(self.filename)\n            data = self.load_file(filename)\n            if not data:\n                data = defaultdict(dict)\n            else:\n                data = defaultdict(dict, data)\n            self.user_data = data\n        else:\n            self.load_singlefile()\n        return deepcopy(self.user_data)\n\n    def get_chat_data(self):\n        \"\"\"Returns the chat_data from the pickle file if it exsists or an empty defaultdict.\n\n        Returns:\n            :obj:`defaultdict`: The restored chat data.\n        \"\"\"\n        if self.chat_data:\n            pass\n        elif not self.single_file:\n            filename = \"{}_chat_data\".format(self.filename)\n            data = self.load_file(filename)\n            if not data:\n                data = defaultdict(dict)\n            else:\n                data = defaultdict(dict, data)\n            self.chat_data = data\n        else:\n            self.load_singlefile()\n        return deepcopy(self.chat_data)\n\n    def get_bot_data(self):\n        \"\"\"Returns the bot_data from the pickle file if it exsists or an empty dict.\n\n        Returns:\n            :obj:`defaultdict`: The restored bot data.\n        \"\"\"\n        if self.bot_data:\n            pass\n        elif not self.single_file:\n            filename = \"{}_bot_data\".format(self.filename)\n            data = self.load_file(filename)\n            if not data:\n                data = {}\n            self.bot_data = data\n        else:\n            self.load_singlefile()\n        return deepcopy(self.bot_data)\n\n    def get_conversations(self, name):\n        \"\"\"Returns the conversations from the pickle file if it exsists or an empty defaultdict.\n\n        Args:\n            name (:obj:`str`): The handlers name.\n\n        Returns:\n            :obj:`dict`: The restored conversations for the handler.\n        \"\"\"\n        if self.conversations:\n            pass\n        elif not self.single_file:\n            filename = \"{}_conversations\".format(self.filename)\n            data = self.load_file(filename)\n            if not data:\n                data = {name: {}}\n            self.conversations = data\n        else:\n            self.load_singlefile()\n        return self.conversations.get(name, {}).copy()\n\n    def update_conversation(self, name, key, new_state):\n        \"\"\"Will update the conversations for the given handler and depending on :attr:`on_flush`\n        save the pickle file.\n\n        Args:\n            name (:obj:`str`): The handlers name.\n            key (:obj:`tuple`): The key the state is changed for.\n            new_state (:obj:`tuple` | :obj:`any`): The new state for the given key.\n        \"\"\"\n        if self.conversations.setdefault(name, {}).get(key) == new_state:\n            return\n        self.conversations[name][key] = new_state\n        if not self.on_flush:\n            if not self.single_file:\n                filename = \"{}_conversations\".format(self.filename)\n                self.dump_file(filename, self.conversations)\n            else:\n                self.dump_singlefile()\n\n    def update_user_data(self, user_id, data):\n        \"\"\"Will update the user_data (if changed) and depending on :attr:`on_flush` save the\n        pickle file.\n\n        Args:\n            user_id (:obj:`int`): The user the data might have been changed for.\n            data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data` [user_id].\n        \"\"\"\n        if self.user_data.get(user_id) == data:\n            return\n        self.user_data[user_id] = data\n        if not self.on_flush:\n            if not self.single_file:\n                filename = \"{}_user_data\".format(self.filename)\n                self.dump_file(filename, self.user_data)\n            else:\n                self.dump_singlefile()\n\n    def update_chat_data(self, chat_id, data):\n        \"\"\"Will update the chat_data (if changed) and depending on :attr:`on_flush` save the\n        pickle file.\n\n        Args:\n            chat_id (:obj:`int`): The chat the data might have been changed for.\n            data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` [chat_id].\n        \"\"\"\n        if self.chat_data.get(chat_id) == data:\n            return\n        self.chat_data[chat_id] = data\n        if not self.on_flush:\n            if not self.single_file:\n                filename = \"{}_chat_data\".format(self.filename)\n                self.dump_file(filename, self.chat_data)\n            else:\n                self.dump_singlefile()\n\n    def update_bot_data(self, data):\n        \"\"\"Will update the bot_data (if changed) and depending on :attr:`on_flush` save the\n        pickle file.\n\n        Args:\n            data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`.\n        \"\"\"\n        if self.bot_data == data:\n            return\n        self.bot_data = data.copy()\n        if not self.on_flush:\n            if not self.single_file:\n                filename = \"{}_bot_data\".format(self.filename)\n                self.dump_file(filename, self.bot_data)\n            else:\n                self.dump_singlefile()\n\n    def flush(self):\n        \"\"\" Will save all data in memory to pickle file(s).\n        \"\"\"\n        if self.single_file:\n            if self.user_data or self.chat_data or self.conversations:\n                self.dump_singlefile()\n        else:\n            if self.user_data:\n                self.dump_file(\"{}_user_data\".format(self.filename), self.user_data)\n            if self.chat_data:\n                self.dump_file(\"{}_chat_data\".format(self.filename), self.chat_data)\n            if self.bot_data:\n                self.dump_file(\"{}_bot_data\".format(self.filename), self.bot_data)\n            if self.conversations:\n                self.dump_file(\"{}_conversations\".format(self.filename), self.conversations)\n", "path": "telegram/ext/picklepersistence.py"}]}