We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Clock terminated with Exception
With the latest Manjaro Testing Update, I received version 3.32 with Python 3.9.1.

All modules still work except the clock module which is terminated. The journal simply says
```Exception in `i3pystatus clock` post_config_hook().```

The config didn't change and works with 3.31:
```
clock {
    format = "{Local}"
    format_time = "{icon} %a, %d.%m.%Y %H:%M"
}
```

Downgrading to 3.31 works. What else information do you need?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `py3status/storage.py`
Content:
```
1 import os
2 import time
3 
4 from pathlib import Path
5 from pickle import dump, load
6 from tempfile import NamedTemporaryFile
7 
8 
9 class Storage:
10 
11     data = {}
12     initialized = False
13 
14     def init(self, py3_wrapper):
15         self.py3_wrapper = py3_wrapper
16         self.config = py3_wrapper.config
17         py3_config = self.config.get("py3_config", {})
18 
19         # check for legacy storage cache
20         legacy_storage_path = self.get_legacy_storage_path()
21 
22         # cutting edge storage cache
23         storage_config = py3_config.get("py3status", {}).get("storage")
24         if storage_config:
25             storage_file = os.path.expandvars(storage_config.expanduser())
26             if "/" in storage_file:
27                 storage_dir = None
28             else:
29                 storage_dir = os.environ.get("XDG_CACHE_HOME")
30         else:
31             storage_dir = os.environ.get("XDG_CACHE_HOME")
32             storage_file = Path("py3status_cache.data")
33 
34         if not storage_dir:
35             storage_dir = Path("~/.cache").expanduser()
36         self.storage_path = storage_dir / storage_file
37 
38         # move legacy storage cache to new desired / default location
39         if legacy_storage_path:
40             self.py3_wrapper.log(
41                 "moving legacy storage_path {} to {}".format(
42                     legacy_storage_path, self.storage_path
43                 )
44             )
45             legacy_storage_path.rename(self.storage_path)
46 
47         try:
48             with self.storage_path.open("rb") as f:
49                 self.data = load(f, encoding="bytes")
50         except OSError:
51             pass
52 
53         self.py3_wrapper.log(f"storage_path: {self.storage_path}")
54         if self.data:
55             self.py3_wrapper.log(f"storage_data: {self.data}")
56         self.initialized = True
57 
58     def get_legacy_storage_path(self):
59         """
60         Detect and return existing legacy storage path.
61         """
62         config_dir = Path(
63             self.py3_wrapper.config.get("i3status_config_path", "/tmp")
64         ).parent
65         storage_path = config_dir / "py3status.data"
66         if storage_path.exists():
67             return storage_path
68         else:
69             return None
70 
71     def save(self):
72         """
73         Save our data to disk. We want to always have a valid file.
74         """
75         with NamedTemporaryFile(dir=self.storage_path.parent, delete=False) as f:
76             # we use protocol=2 for python 2/3 compatibility
77             dump(self.data, f, protocol=2)
78             f.flush()
79             os.fsync(f.fileno())
80             tmppath = Path(f.name)
81         tmppath.rename(self.storage_path)
82 
83     def storage_set(self, module_name, key, value):
84         if key.startswith("_"):
85             raise ValueError('cannot set keys starting with an underscore "_"')
86 
87         if self.data.get(module_name, {}).get(key) == value:
88             return
89 
90         if module_name not in self.data:
91             self.data[module_name] = {}
92         self.data[module_name][key] = value
93         ts = time.time()
94         if "_ctime" not in self.data[module_name]:
95             self.data[module_name]["_ctime"] = ts
96         self.data[module_name]["_mtime"] = ts
97         self.save()
98 
99     def storage_get(self, module_name, key):
100         return self.data.get(module_name, {}).get(key, None)
101 
102     def storage_del(self, module_name, key=None):
103         if module_name in self.data and key in self.data[module_name]:
104             del self.data[module_name][key]
105             self.save()
106 
107     def storage_keys(self, module_name):
108         return list(self.data.get(module_name, {}))
109
```
--- 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/py3status/storage.py b/py3status/storage.py
--- a/py3status/storage.py
+++ b/py3status/storage.py
@@ -22,18 +22,18 @@
         # cutting edge storage cache
         storage_config = py3_config.get("py3status", {}).get("storage")
         if storage_config:
-            storage_file = os.path.expandvars(storage_config.expanduser())
+            storage_file = os.path.expandvars(os.path.expanduser(storage_config))
             if "/" in storage_file:
                 storage_dir = None
             else:
                 storage_dir = os.environ.get("XDG_CACHE_HOME")
         else:
             storage_dir = os.environ.get("XDG_CACHE_HOME")
-            storage_file = Path("py3status_cache.data")
+            storage_file = "py3status_cache.data"
 
         if not storage_dir:
             storage_dir = Path("~/.cache").expanduser()
-        self.storage_path = storage_dir / storage_file
+        self.storage_path = Path(storage_dir, storage_file)
 
         # move legacy storage cache to new desired / default location
         if legacy_storage_path:

{"golden_diff": "diff --git a/py3status/storage.py b/py3status/storage.py\n--- a/py3status/storage.py\n+++ b/py3status/storage.py\n@@ -22,18 +22,18 @@\n         # cutting edge storage cache\n         storage_config = py3_config.get(\"py3status\", {}).get(\"storage\")\n         if storage_config:\n-            storage_file = os.path.expandvars(storage_config.expanduser())\n+            storage_file = os.path.expandvars(os.path.expanduser(storage_config))\n             if \"/\" in storage_file:\n                 storage_dir = None\n             else:\n                 storage_dir = os.environ.get(\"XDG_CACHE_HOME\")\n         else:\n             storage_dir = os.environ.get(\"XDG_CACHE_HOME\")\n-            storage_file = Path(\"py3status_cache.data\")\n+            storage_file = \"py3status_cache.data\"\n \n         if not storage_dir:\n             storage_dir = Path(\"~/.cache\").expanduser()\n-        self.storage_path = storage_dir / storage_file\n+        self.storage_path = Path(storage_dir, storage_file)\n \n         # move legacy storage cache to new desired / default location\n         if legacy_storage_path:\n", "issue": "Clock terminated with Exception\nWith the latest Manjaro Testing Update, I received version 3.32 with Python 3.9.1.\r\n\r\nAll modules still work except the clock module which is terminated. The journal simply says\r\n```Exception in `i3pystatus clock` post_config_hook().```\r\n\r\nThe config didn't change and works with 3.31:\r\n```\r\nclock {\r\n    format = \"{Local}\"\r\n    format_time = \"{icon} %a, %d.%m.%Y %H:%M\"\r\n}\r\n```\r\n\r\nDowngrading to 3.31 works. What else information do you need?\n", "before_files": [{"content": "import os\nimport time\n\nfrom pathlib import Path\nfrom pickle import dump, load\nfrom tempfile import NamedTemporaryFile\n\n\nclass Storage:\n\n    data = {}\n    initialized = False\n\n    def init(self, py3_wrapper):\n        self.py3_wrapper = py3_wrapper\n        self.config = py3_wrapper.config\n        py3_config = self.config.get(\"py3_config\", {})\n\n        # check for legacy storage cache\n        legacy_storage_path = self.get_legacy_storage_path()\n\n        # cutting edge storage cache\n        storage_config = py3_config.get(\"py3status\", {}).get(\"storage\")\n        if storage_config:\n            storage_file = os.path.expandvars(storage_config.expanduser())\n            if \"/\" in storage_file:\n                storage_dir = None\n            else:\n                storage_dir = os.environ.get(\"XDG_CACHE_HOME\")\n        else:\n            storage_dir = os.environ.get(\"XDG_CACHE_HOME\")\n            storage_file = Path(\"py3status_cache.data\")\n\n        if not storage_dir:\n            storage_dir = Path(\"~/.cache\").expanduser()\n        self.storage_path = storage_dir / storage_file\n\n        # move legacy storage cache to new desired / default location\n        if legacy_storage_path:\n            self.py3_wrapper.log(\n                \"moving legacy storage_path {} to {}\".format(\n                    legacy_storage_path, self.storage_path\n                )\n            )\n            legacy_storage_path.rename(self.storage_path)\n\n        try:\n            with self.storage_path.open(\"rb\") as f:\n                self.data = load(f, encoding=\"bytes\")\n        except OSError:\n            pass\n\n        self.py3_wrapper.log(f\"storage_path: {self.storage_path}\")\n        if self.data:\n            self.py3_wrapper.log(f\"storage_data: {self.data}\")\n        self.initialized = True\n\n    def get_legacy_storage_path(self):\n        \"\"\"\n        Detect and return existing legacy storage path.\n        \"\"\"\n        config_dir = Path(\n            self.py3_wrapper.config.get(\"i3status_config_path\", \"/tmp\")\n        ).parent\n        storage_path = config_dir / \"py3status.data\"\n        if storage_path.exists():\n            return storage_path\n        else:\n            return None\n\n    def save(self):\n        \"\"\"\n        Save our data to disk. We want to always have a valid file.\n        \"\"\"\n        with NamedTemporaryFile(dir=self.storage_path.parent, delete=False) as f:\n            # we use protocol=2 for python 2/3 compatibility\n            dump(self.data, f, protocol=2)\n            f.flush()\n            os.fsync(f.fileno())\n            tmppath = Path(f.name)\n        tmppath.rename(self.storage_path)\n\n    def storage_set(self, module_name, key, value):\n        if key.startswith(\"_\"):\n            raise ValueError('cannot set keys starting with an underscore \"_\"')\n\n        if self.data.get(module_name, {}).get(key) == value:\n            return\n\n        if module_name not in self.data:\n            self.data[module_name] = {}\n        self.data[module_name][key] = value\n        ts = time.time()\n        if \"_ctime\" not in self.data[module_name]:\n            self.data[module_name][\"_ctime\"] = ts\n        self.data[module_name][\"_mtime\"] = ts\n        self.save()\n\n    def storage_get(self, module_name, key):\n        return self.data.get(module_name, {}).get(key, None)\n\n    def storage_del(self, module_name, key=None):\n        if module_name in self.data and key in self.data[module_name]:\n            del self.data[module_name][key]\n            self.save()\n\n    def storage_keys(self, module_name):\n        return list(self.data.get(module_name, {}))\n", "path": "py3status/storage.py"}], "after_files": [{"content": "import os\nimport time\n\nfrom pathlib import Path\nfrom pickle import dump, load\nfrom tempfile import NamedTemporaryFile\n\n\nclass Storage:\n\n    data = {}\n    initialized = False\n\n    def init(self, py3_wrapper):\n        self.py3_wrapper = py3_wrapper\n        self.config = py3_wrapper.config\n        py3_config = self.config.get(\"py3_config\", {})\n\n        # check for legacy storage cache\n        legacy_storage_path = self.get_legacy_storage_path()\n\n        # cutting edge storage cache\n        storage_config = py3_config.get(\"py3status\", {}).get(\"storage\")\n        if storage_config:\n            storage_file = os.path.expandvars(os.path.expanduser(storage_config))\n            if \"/\" in storage_file:\n                storage_dir = None\n            else:\n                storage_dir = os.environ.get(\"XDG_CACHE_HOME\")\n        else:\n            storage_dir = os.environ.get(\"XDG_CACHE_HOME\")\n            storage_file = \"py3status_cache.data\"\n\n        if not storage_dir:\n            storage_dir = Path(\"~/.cache\").expanduser()\n        self.storage_path = Path(storage_dir, storage_file)\n\n        # move legacy storage cache to new desired / default location\n        if legacy_storage_path:\n            self.py3_wrapper.log(\n                \"moving legacy storage_path {} to {}\".format(\n                    legacy_storage_path, self.storage_path\n                )\n            )\n            legacy_storage_path.rename(self.storage_path)\n\n        try:\n            with self.storage_path.open(\"rb\") as f:\n                self.data = load(f, encoding=\"bytes\")\n        except OSError:\n            pass\n\n        self.py3_wrapper.log(f\"storage_path: {self.storage_path}\")\n        if self.data:\n            self.py3_wrapper.log(f\"storage_data: {self.data}\")\n        self.initialized = True\n\n    def get_legacy_storage_path(self):\n        \"\"\"\n        Detect and return existing legacy storage path.\n        \"\"\"\n        config_dir = Path(\n            self.py3_wrapper.config.get(\"i3status_config_path\", \"/tmp\")\n        ).parent\n        storage_path = config_dir / \"py3status.data\"\n        if storage_path.exists():\n            return storage_path\n        else:\n            return None\n\n    def save(self):\n        \"\"\"\n        Save our data to disk. We want to always have a valid file.\n        \"\"\"\n        with NamedTemporaryFile(dir=self.storage_path.parent, delete=False) as f:\n            # we use protocol=2 for python 2/3 compatibility\n            dump(self.data, f, protocol=2)\n            f.flush()\n            os.fsync(f.fileno())\n            tmppath = Path(f.name)\n        tmppath.rename(self.storage_path)\n\n    def storage_set(self, module_name, key, value):\n        if key.startswith(\"_\"):\n            raise ValueError('cannot set keys starting with an underscore \"_\"')\n\n        if self.data.get(module_name, {}).get(key) == value:\n            return\n\n        if module_name not in self.data:\n            self.data[module_name] = {}\n        self.data[module_name][key] = value\n        ts = time.time()\n        if \"_ctime\" not in self.data[module_name]:\n            self.data[module_name][\"_ctime\"] = ts\n        self.data[module_name][\"_mtime\"] = ts\n        self.save()\n\n    def storage_get(self, module_name, key):\n        return self.data.get(module_name, {}).get(key, None)\n\n    def storage_del(self, module_name, key=None):\n        if module_name in self.data and key in self.data[module_name]:\n            del self.data[module_name][key]\n            self.save()\n\n    def storage_keys(self, module_name):\n        return list(self.data.get(module_name, {}))\n", "path": "py3status/storage.py"}]}